• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

C In-Place String Replace mit Memmove -> Speicherfehler

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
Ich hab gerade ein kleines C Problem, ich arbeite gerade an einer In Place String Replace Funktion, die funktioniert auch soweit ganz gut wie gedacht, aber ich bekomme immer einen Memory corruption Fehler bei der 2ten Variante mit Memmove beim Freeing des Elements.

Die Frage ist, wie muß der Code beschaffen sein damit das Element mit free(elm) aufgelöst werden kann ohne Speicherfehler zu verursachen?
Bei Bedarf stelle ich den gesamten Source Code zu Verfügung, ist analog zu diesem Posting/Thema. Ich würde das gerne in Place machen so das die Daten die an die Replace Funktion übergeben werden auch direkt umgearbeitet werden.

Der aufrufende Code sieht so aus:
[src=c]// Find the common blocks with equal counts across files
// Fills the sampleStore
buildSampleList(filesToAnalyze);

// Modify the dnaFiles data to figure out how many left samples there are
// in those files and count them together with the other sequences to get the file sanmples

// Clean the sample file data from found tags
for (i = 0; i < dnaFiles.fileCount; i++) {
for (j = 0; j < sampleStore.count; j++) {
printf("%s\n", sampleStore.samples[j].sequence);
replace(dnaFiles.files.data, sampleStore.samples[j].sequence, "_");
printf("%s\n", dnaFiles.files.data);
break;
}
break;
}[/src]

Folgender Code funktioniert auch soweit, also das gesuchte mit einem "_" zu überschreiben...
[src=c]char* replace(char* data, char* searchString, char replacement) {
unsigned int position, current, offset = 0;
unsigned int dataLength = strlen(data);
unsigned int sizeSearchString = strlen(searchString);

while (position != -1) {
position = indexOf(data, searchString, 0);
if (position != -1) {
current = 0;
while (current < sizeSearchString) {
data[position + current] = replacement;
current++;
}
}
}

return data;
}[/src]

Folgender Code funktioniert zwar auch, hier wird Memmove genutzt um den Inhalt des Strings zu verschieben, ich kann den Inhalt ausgeben, aber ich bekomme immer den folgenden Speicherfehler beeim freeing.
Ich hab auch schon versucht den Inhalt mit Realloc zu schrumpfen, bekomme aber immer einen "invalid next size"-Error obwohl chars + strlen(data) genutzt wurde :unknown:
[src=c]char* replace(char* data, char* searchString, char* replacement) {
unsigned int position, current, offset = 0;
unsigned int dataLength = strlen(data);
unsigned int sizeReplacement = strlen(replacement);
unsigned int sizeSearchString = strlen(searchString);
while (position != -1) {
position = indexOf(data, searchString, 0);
if (position != -1) {
current = 0;

while (current < sizeReplacement) {
data[position + current] = replacement[current];
current++;
}

offset = position + sizeReplacement;
dataLength -= (sizeSearchString - sizeReplacement);
memmove(data + offset, data + offset + sizeSearchString, sizeof (char)*(dataLength));
}
}
printf("%d length\n", dataLength);

return data;
}[/src]

Die Cleaning Ausgabe (dnaFiles[x].data ist eines der Objekte die memmoved sind):
[src=c]Cleaning ressources...
Freeing alphabet...
Freeing block128...
Freeing dnaFiles data...
*** Error in `./dnalyzer': double free or corruption (!prev): 0x00000000008c20b0 ***[/src]
 
Zuletzt bearbeitet:

drouwocu

Neu angemeldet

Registriert
27 Juli 2015
Beiträge
6
@theSplit:
Meiner Meinung nach stimmt in "memmove" das "dataLength" nicht, da muss mindestens noch der "offset"+"sizeSearchString" abgezogen werden und deswegen würde ich "dataLength" nicht dafür verwenden. Aber so richtig hab ich noch nicht verstanden was du machen willst.
[src=c]unsigned int cpyLen = dataLength – (offset + sizeSearchString);
memmove(data + offset, data + offset + sizeSearchString, cpyLen);[/src]
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #4
Folgend eine Variante die auf dem obigen Code aufbaut aber leicht modifiziert ist.

Was mich daran wundert, vorher hatte ich immer einen Error bekommen wenn ich die gleiche Variable/Char Array überschreiben wollte. Ich wollte quasi den Originalstring kürzen so fern angebracht, deßhalb das verschieben der Inhalte mit Memmove.
Oder das Problem war das der Code vorher auf ein Memory allocated Element in einem Struct zugegriffen hat?

Aber jetzt funktioniert es erstmal, bin schon glücklich drüber :)

Freeing des Strings string geht auch! :T

@drouwocu
Gute Frage, der Code hatte vorher schon ein brauchbares Ergebnis zwischendurch produziert - aber ich hatte wegen des Freeing Errors wirklich herumprobiert wie es richtig ist.
Der Memmove sollte die Textinformationen nach der ersetzen Position hinter dem ersetzten Zeichen zurückziehen um Texte zu überschreiben. Also bei "TestString Test" = "Test_ Test" wenn wir "String" ersetzen mit "_" - also nachrücken und überschreiben.


[src=c]#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Toolset
char* replace(char* data, char* searchString, char* replacement);
int indexOf(char* data, char* searchString, unsigned int searchPosition);
int countOccurence(char* data, char* searchString);

// Main

int main(void) {
char* string = "Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring.\0";

printf("Gerade:\n%s\n", string);
string = replace(string, "kein", "ein");
string = replace(string, "Test", "Sample");
string = replace(string, "Dies", "Das");

printf("\nDanach:\n%s\n", string);
free(string);

return 0;
}

// Replace

char* replace(char* data, char* searchString, char* replacement) {
int current = 0, position = 0, previousPosition = 0, writingPos = 0, readingPos = 0;

unsigned int replacementLength = strlen(replacement);
unsigned int searchStringLength = strlen(searchString);
char* newData = (char*) calloc(strlen(data) + (countOccurence(data, searchString) * replacementLength), sizeof (char));

while (position != -1) {
position = indexOf(data, searchString, previousPosition);
if (position != -1) {

if (previousPosition == 0) {
strncat(newData, data, position);
strcat(newData, replacement);
previousPosition = position + searchStringLength;
} else {
readingPos = previousPosition;
writingPos = strlen(newData);
current = position - previousPosition;
while (current > 0) {
newData[writingPos] = data[readingPos];
current--;
writingPos++;
readingPos++;
}

strcat(newData, replacement);
previousPosition = position + searchStringLength;
}
} else {
writingPos += replacementLength;
readingPos += searchStringLength;

while (readingPos < strlen(data)) {
newData[writingPos + current] = data[readingPos];
current++;
readingPos++;
}
}
}
return newData;
}

// Index of

int indexOf(char* data, char* searchString, unsigned int searchPosition) {
unsigned int searchDataLength = strlen(data);
unsigned int searchStringLength = strlen(searchString);
int currentPosition = 0;
unsigned int searchDataIndex = 0;
for (currentPosition = searchPosition; currentPosition < searchDataLength; currentPosition++) {
if (data[currentPosition] != searchString[searchDataIndex]) {
currentPosition -= searchDataIndex;
searchDataIndex = 0;
} else {
searchDataIndex++;

if (searchDataIndex == searchStringLength) {
return (currentPosition + 1 - searchStringLength);
}
}
}

return -1;
}

int countOccurence(char* data, char* searchString) {
unsigned int countOccurence = 0, searchStringLength = strlen(searchString);
int currentPosition = 0;

while (true) {
currentPosition = indexOf(data, searchString, currentPosition);
if (currentPosition != -1) {
countOccurence++;
currentPosition += searchStringLength;
} else {
return countOccurence;
}
}

return -1;
}

[/src]
 
Zuletzt bearbeitet:

exomo

NGBler

Registriert
1 Aug. 2015
Beiträge
129
Ich habe deinen Code mal ein bisschen unter die Lupe genommen und auf etwa die Hälfte verkürzt bei gleicher funktionalität (zuindest wenn ich alles richtig verstanden habe).
Die Methode indexOf ist völlig überflüssig, weil das genau das ist was man normalerweise mit strstr() macht. Die ganzen index ind Positionen merker habe ich durch wenige pointer ersetzt.
[src=c]#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Toolset
char* replace(char* data, char* searchString, char* replacement);
int countOccurence(char* data, char* searchString);

// Main

int main(void) {
char *string = "Dies ist keinkein einfacher Teststring. Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring."; // strings are implicitly terminated, no need to add \0

printf("Gerade:\n%s\n", string);
string = replace(string, "kein", "ein");
string = replace(string, "Test", "Sample");
string = replace(string, "Dies", "Das");

printf("\nDanach:\n%s\n", string);
free(string);

return 0;
}

// Replace

char* replace(char* data, char* searchString, char* replacement) {
char *position, *previousPosition;

unsigned int replacementLength = strlen(replacement);
unsigned int searchStringLength = strlen(searchString);
char* newData = (char*) calloc(strlen(data) + (countOccurence(data, searchString) * (replacementLength-searchStringLength)) + 1, sizeof (char));

previousPosition = data;
position = strstr(data, searchString);
while (position != 0) {
// copy everything from previous position to occurrence of search string
strncat(newData, previousPosition, (position-previousPosition));

// copy the replacement text
strcat(newData, replacement);

previousPosition = position + searchStringLength;
position = strstr(previousPosition, searchString);
}

// copy the remaining parts of the original string
strcat(newData, previousPosition);

return newData;
}

int countOccurence(char* data, char* searchString) {
unsigned int countOccurence = 0, searchStringLength = strlen(searchString);
char *currentPosition;

currentPosition = strstr(data, searchString);
while (currentPosition != 0) {
++countOccurence;
currentPosition = strstr(currentPosition + searchStringLength, searchString);
}
return countOccurence;
}
[/src]

Was ich nicht behoben habe ist dein riesen Memory Leak. Jedes replace() legt neuen Speicher an, aber nur einer (der letzte) wird wieder freigegeben.

EDIT:
Da es ja ursprünglich um ein in-place replace ging habe ich m(d)einen Code nochmal etwas angepasst:
Replace (in-place). Jetzt auch mit const-correctness und ohne Memory Leaks.
[src=c]#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Toolset
char *inplaceReplace(char* data, const char* searchString, const char* replacement);
int countOccurence(const char* data, const char* searchString);

// Main
int main(void) {
char string[] = "Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring."; // strings are implicitly terminated, no need to add \0

char *newString = (char*) malloc((strlen(string)+1)*sizeof(char));
strcpy(newString, string);

printf("Gerade:\n%s\n", newString);
newString = inplaceReplace(newString, "kein", "ein");
newString = inplaceReplace(newString, "Test", "Sample");
newString = inplaceReplace(newString, "Dies", "Das");

printf("\nDanach:\n%s\n", newString);
free(newString);

return 0;
}

// Inplace replace
char *inplaceReplace(char* data, const char* searchString, const char* replacement) {
char *position;

unsigned int replacementLength = strlen(replacement);
unsigned int searchStringLength = strlen(searchString);
unsigned int newSize = strlen(data) + (countOccurence(data, searchString) * (replacementLength-searchStringLength)) + 1;

if(newSize > strlen(data) + 1)
{
data = (char*) realloc(data, newSize);
}

position = strstr(data, searchString);
while (position != 0)
{
if(replacementLength != searchStringLength)
{
memmove(position + replacementLength, position + searchStringLength, strlen(data) - ((position + searchStringLength) - data) + 1);
}

// copy the replacement text
memcpy(position, replacement, replacementLength);
position = strstr(position + replacementLength, searchString);
}

return data;
}

int countOccurence(const char* data, const char* searchString) {
unsigned int countOccurence = 0, searchStringLength = strlen(searchString);
char *currentPosition;

currentPosition = strstr(data, searchString);
while (currentPosition != 0) {
++countOccurence;
currentPosition = strstr(currentPosition + searchStringLength, searchString);
}
return countOccurence;
}[/src]Wahrscheinlich kann man noch das eine oder andere optimieren, aber bei mir funktioniert es so erstmal. realloc wird nur aufgerufen wenn der neue String länger ist, wenn der Speicher verkleinert werden soll müsste man das am Ende der Funktion machen.
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #6
@exomo:

Erstmal herzlich Willkommen und vielen Dank für den Input :)

Der erste Replace arbeitet ja mit Zeiger-Arithmetik, damit habe ich mich noch nicht intensiver beschäftigt.
Auch wenn mir nicht gleich ersichtlich ist warum zum Beispiel in Zeile 38:
strncat(newData, previousPosition, (position - previousPosition));

Hier also position - previousPosition funktioniert.
Wenn ich richtig sehe liefern die Zeiger ja beides Speicheradressen. Durch strstr wird der Datenzeiger dann auf die nächste Position, mit
position = strstr(previousPosition, searchString);
innerhalb der Daten verschoben an dem das gesuchte zu finden ist? (Und ist damit automatisch als Speicheradresse höher als die vorherige Position?)

Ich bin ein wenig verwirrt, Aufklärung wäre schön :)

Wenn man das ganze als dezimal ausgibt macht es Sinn, aber so richtig nachvollziehen kann ich es noch nicht wie die Zeiger Berechnung dabei funktioniert.

Deine zweite Version mit dem in-place Replace habe ich nur leicht modifiziert, er mochte das const Keyword im countOccurence nicht. Der Realloc ist dafür drin und es wird auch kein Speicher geleaked.
[src=c]#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Toolset
char *inplaceReplace(char* data, const char* searchString, const char* replacement);
int countOccurence(char* data, const char* searchString);

// Main

int main(void) {
char string[] = "Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring. Dies ist kein einfacher Teststring."; // strings are implicitly terminated, no need to add \0

char *newString = (char*) malloc((strlen(string) + 1) * sizeof (char));
strcpy(newString, string);

printf("Gerade:\n%s\n", newString);
newString = inplaceReplace(newString, "kein", "ein");
newString = inplaceReplace(newString, "Test", "Sample");
newString = inplaceReplace(newString, "Dies", "Das");

printf("\nDanach:\n%s\n", newString);
free(newString);

return 0;
}

// Inplace replace

char *inplaceReplace(char* data, const char* searchString, const char* replacement) {
char *position;

unsigned int replacementLength = strlen(replacement);
unsigned int searchStringLength = strlen(searchString);
unsigned int newSize = strlen(data) + (countOccurence(data, searchString) * (replacementLength - searchStringLength)) + 1;

if (newSize > strlen(data) + 1) {
data = (char*) realloc(data, newSize);
}

position = strstr(data, searchString);
while (position != 0) {
if (replacementLength != searchStringLength) {
memmove(position + replacementLength, position + searchStringLength, strlen(data) - ((position + searchStringLength) - data) + 1);
}

// copy the replacement text
memcpy(position, replacement, replacementLength);
position = strstr(position + replacementLength, searchString);
}

data = (char*) realloc(data, (strlen(data) + 1) * sizeof (char));
return data;
}

int countOccurence(char* data, const char* searchString) {
unsigned int countOccurence = 0, searchStringLength = strlen(searchString);
char *currentPosition;

currentPosition = strstr(data, searchString);
while (currentPosition != 0) {
++countOccurence;
currentPosition = strstr(currentPosition + searchStringLength, searchString);
}
return countOccurence;
}

[/src]
 
Zuletzt bearbeitet:

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Was hier passiert wird klarer, wenn man sich genau anschaut, wie das im Speicher aussieht. Stell dir vor, du hast den String "ELECTRIC-LARRY" und möchtest den Bindestrich "-" mit einem Stern "*" replacen.

Wenn unser Suchstring in den Speicher geladen wurde, dann sieht das dort in etwa so aus:



In der ersten Spalte siehst du die Speicheradresse am Beginn der jeweiligen Zeile in Hexadezimal. Unser String "ELECTRIC-LARRY" beginnt an der Speicheradresse 0x3A (= 58) und endet bei 0x47 (= 71).

Stell dir vor, wir haben jetzt zwei Pointer, den einen, char *pAnfang setzen wir auf den Anfang des Strings, den anderen , char *pEnde, auf das Ende des Strings.

pAnfang würde also auf die Speicheradresse 58, wo das 'E' steht, zeigen. pEnde zeigt auf Adresse 71, also auf das 'Y'. "Zeigen" bedeutet im Grunde ja nur, dass der Wert der Variable 58 bzw. 71 ist. Möchtest du die Länge des Strings wissen, könntest du die beiden Pointer subtrahieren und eins hinzufügen. Eins kommt dazu, weil pEnde ja auf den letzten Buchstaben und nicht auf die Speicherstelle danach zeigt.

Was passiert hier also, wenn wir davon ausgehen, dass data = "ELECTRIC-LARRY" und searchString = "-" ist und mit einem "*" ersetzt werden soll?

[src=c]
char* newData = (char*) calloc(...);
//newdata lassen wir ganz am Anfang
//unseres Speicherblocks aus der Grafik oben sein,
//der pointer zeigt also auf Adresse 0. Dorthin wird
//der neue String geschrieben

previousPosition = data;
//pointer previousPosition zeigt auf Adresse 58,
//wo das erste 'E' steht
position = strstr(data, searchString);
//position zeigt auf 66 wo der Bindestrich '-' ist.

strncat(newData, previousPosition, (position-previousPosition) );
//Wir kopieren 66 - 58 (= 8) Zeichen von der Speicheradresse 58
//an die Stelle 0 im Speicher
[/src]

Im Speicher würde das dann etwa so aussehen:



[src=c]

strcat(newData, replacement);
//Jetzt hängen wir an das Ende des Strings, der
//bei Adresse 0 beginnt, den Replacement-Text an.
//Die Funktion erkennt das Ende des Strings am NULL-Byte (0x00)
//auf der Adresse 8.

previousPosition = position + searchStringLength;
//Für den nächsten Durchlauf der Schleife zeigt der Pointer
//previousPosition auf 61 + 1 = 62 wo das 'L' steht.

position = strstr(previousPosition, searchString);
//position würde auf die Nächste Adresse, wo ein '-' zu
//finden ist, zeigen. Da es keinen zweiten Bindestrich
//gibt, returnt sie aber NULL und die Schleife wird beendet.

// copy the remaining parts of the original string
strcat(newData, previousPosition);
//Nachdem die Schleife beendet wurde, wird noch der Rest
//des Strings an das Ende des neuen Strings angehängt.
//Also an die Adresse 9 werden alle Zeichen beginnend von
//Adresse 0x43 (=67) bis zum Null-Byte auf Adresse 0x48 (=72).

[/src]

Im Speicher hätten wir dann dieses Bild:



<3
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #8
Wow, da hat sich aber jemand wirklich Mühe gemacht das aufzudröseln. Danke Electric Larry für die ausführliche Erklärung. :)
Ist auch super verständlich.

Aber nur um das nochmal festzuhalten "strstr" liefert uns eine Adresse auf das erste Aufkommen des gesuchten innerhalb des zu durchsuchenden Strings und keinen integer Wert des Indexes...

Wenn wir jetzt den Wert von strstr als String ausgeben, erhalten wir die Elemente des char-Arrays von Adresse bis zum Nullterminierten Ende?
Mich hat die Ausgabe von
[src=c]position = strstr(data, searchString);
printf("%s\n", position);[/src]
nämlich irritiert, weil hier der String ja von dem ersten auftauchen bis zum Ende angezeigt wird...

Aber die Vermutung das prinf in diesem Fall von Startadresse bis zum null terminierten Ende ausgibt ist, vermute ich, korrekt?

Und Frage zwei:

Wie kann ich dann auf einen Buchstaben zurückgreifen wenn ich die Adresse habe an der sich der char im Speicher befindet?
[src=c]data[position];[/src]
würde in diesem Fall ja so nicht mehr funktionieren.

Edit:
Die zweite Frage hat sich gerade geklärt:
[src=c]printf("%c", position[0]);[/src]
 
Zuletzt bearbeitet:

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Aber nur um das nochmal festzuhalten "strstr" liefert uns eine Adresse auf das erste Aufkommen des gesuchten innerhalb des zu durchsuchenden Strings und keinen integer Wert des Indexes...

Genau. Um den Index innerhalb des Strings zu erhalten, könntest du die Startadresse von der gefundenen Adresse subtrahieren.

Wie kann ich dann auf einen Buchstaben zurückgreifen wenn ich die Adresse habe an der sich der char im Speicher befindet?

Um einen Pointer aufzulösen und an den Wert zu gelangen, kannst du *pAnfang verwenden, musst das dann aber meistens selbst casten. Also würde, wenn du einen Pointer auf einen Integer hast, pInteger die Adresse im Speicher wo die Zahl liegt, sein, der Wert hinter dem Pointer wäre mit *pInteger zu erreichen.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #10
@electric.larry:

Also das mit der Pointer-Arithmethik habe ich jetzt schon begriffen, ist auch nach deiner guten Anleitung nicht mehr sonderlich schwer :T

Zum Thema auf den aktuellen Wert zurückzugreifen auf den ein Pointer zeigt, sehr easy :)
Was ich allerdings auch wieder daran tricky finde, wenn man den Pointer navigiert und dann freeen will, bekommt man einen Fehler, der Pointer muss daher wieder auf Position 0 zurück.
Ist schon wieder so eine Sache die nicht ersichtlich ist :)

[src=c]int main(void) {
int *integer;
integer = (int*) malloc(sizeof (int)* 2);
integer[0] = 14;
integer[1] = 12;

//integer++;

printf("%d\n", *integer);
//integer--; // oder...
//integer = 0; // Variante 2
free(integer);
return 0;
}[/src]

Aber ich versuchs mir einzubläumen. :)
 

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Dangling Pointers sind in größeren Anwendungen auch richtig schei*e zu debuggen. Hab mir angewohnt nach der Freigabe des Speichers die Pointer immer auf NULL zu setzen und beim Verwenden dann auch zuerst auf NULL zu prüfen.

Als damals so Sprachen wie C# salonfähig wurden, hab ich immer über automatische Speicherverwaltung und fehlende Pointers geschimpft, gibt man ja irgendwie die Kontrolle über den Speicher aus der Hand. Heute, wo jedes Projekt das auf meinem Schreibtisch landet schon gestern fertig sein muss, bin ich froh, dass es .NET, Unity und wie sie alle heißen, gibt und ich mich um solche Dinge nicht mehr kümmern muss.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #12
Glaube ich dir zu 100%.

Ich hab heute versucht mit einem XML to json Konverter anzufangen, aber das ist doch noch ne Ecke komplizierter als gedacht - die Zeiger Arithmetik kann man dafür gut gebrauchen. Sieht wirklich handy aus als im Vergleich mit integern zu arbeiten, so fern man das gut subtrahieren kann.

Was ich damit sagen wollte, der Thread hilft schon eine Menge weiter, sind schon wieder ein paar Löcher gestopft. Durch das Buch hier von Jürgen Wolf habe ich zwar die Grundlagen gelernt, aber nicht wie es im Detail wirklich funktioniert und manche Sachen sind kaum bis gar nicht zur Anwendung gekommen.

Ich könnte mit dem XML to json Konverter gleich noch einen Thread aufmachen, gibt es schon wieder Probleme und Fragen dazu. Und ich bin mir momentan gar nicht sicher ob die Denkweise die ich gerade an den Tag lege die Richtige ist, wenn ich sehe wie lange ich an Speichermanagement hänge und versuche zu debuggen bei wenig Fortschritt. Da wäre C++ schon eher was aber das ist auch wieder was ganz anderes.... ich werd mich am WE mal hinsetzen das zu programmieren was ich mir gedacht habe, und dann einfach den Code hier posten. Vielleicht ist der gar nicht so schlecht für den Anfang. :)
 

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Gibt es einen bestimmten Grund, dass du sowas nicht in einer higher-leveligen Sprache alla C#, JS oder Python machst? Oder möchtest einfach C(++) lernen?
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #14
Ich geb zu, es ist etwas Quälerei - aber für mich steht das Lernen der Sprache im Vordergrund.

Zu C++ wollte ich dann zu anderen Zeiten umsteigen. C Sharp ungern weil ich mal gehört habe das die Sprache nicht portabel ist weil auf .net basierend - also doch eher C++.
 

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Das Interessante am Arbeiten mit C/C++ oder vielleicht sogar Asm ist aus meiner Sicht, dass man ein wirklich gutes Verständnis dafür bekommt, was "unter der Haube" passiert. Auch wenn man z. B. Visual C++ rein auf API Ebene Programmiert, bekommt man ein gutes Bild davon, was da eigentlich passiert, wenn auf meinem Screen ein Fensterlein mit ein paar Buttons aufgeht.

Dass .net Anwendungen nicht auf Linux oder Mac rennen, stimmt so nicht ganz. Einerseits gibt es Mono, mit dem man zumindest einfache Anwendungen, die nicht speziell auf ein Betriebssystem zugeschnitten sind, auch unter anderen Betriebssystemen laufen lassen kann. Auf der anderen Seite hat Microsoft die .NET Core Runtime unter Open Source Lizenz gestellt womit die Reise von .NET auf jeden Fall in Richtung Crossplattform-Kompatibilität geht.

Ich war lange Jahre Verfechter von Lowlevel-Sprachen und profitier bis heute beim Lernen neuer Techniken davon, dass ich mich zum Beispiel mit Assembler beschäftigt hab. Inzwischen hab ich das Handwerk an sich aber schon recht gut verinnerlicht, dass der interessante Teil der Arbeit nur noch selten die Programmierung an sich, sondern viel mehr das Ding, das am Ende dabei herauskommt, ist.
Wenn wir für irgendein Projekt ein selbstgeschnitztes Tool brauchen, dann schau ich meist zuerst welche Sprache oder welches Framework mir die meiste Arbeit dabei abnimmt und verwende dann das, anstelle einer "Lieblingsprogrammiersprache".

Crossplattform Anwendungen schreib ich momentan am ehesten in Python mit QT Lib. Da bekommt man ohne viel Aufwand eine kleine, kompakte Anwendung ohne großartige Abhängigkeiten, die meine Kollegen auf Windows genau so wie die auf Linux benutzen können.
Bei Zeiten werd ich mir auch Mono wieder einmal genauer ansehen. Wenn hier wirklich auch ohne große Änderungen crossplattform-kompatibilität gewährleistet ist, würd ich wieder auf .net umschwenken; C-Syntax ist mir persönlich einfach lieber, als Basic oder Python Texte.

Sobald wieder einmal etwas Zeit ist, möcht ich mir jedenfalls Microsofts kostenlose Visual Studio Community Edition ansehen. Auf der MS Website wird die ganz interessant angepriesen:

Visual Studio Community
A free, fully-featured, and extensible IDE for creating modern applications for Windows, Android, and iOS, as well as Web applications and cloud services.

Wirklich empfehlenswert ist auch Microsofts Code Editor. für Windoze, Mac und Linux. Ich hab hier zwar meistens Notepad++ unter Wine laufen, aber Code ist zumindest meine zweite Wahl :)
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #16
Ich muss doch nochmal eine Frage einwerfen, die ist bestimmt wieder sau einfach - aber ich komme nicht darauf...

Wie kann ich in so einem Struct das zum Beispiel wie folgt aussieht, den Stirng "name" dynamisch (realloc, calloc, malloc) gestalten?
[src=c]typedef struct tag {
unsigned int dataLength;
keyValue* data;
char* name;
node* parentNode;
};[/src]

Ich will eigentlich vermeiden den Char mit einer fixen Breite von X Zeichen anzulegen, sondern wollte diese dynamisch hinzufügen.
Wenn ich bei obigen Beispiel ein Realloc verwende, bekomme ich ein "invalid old size" Error - also nicht initialisiert. Ich will aber dem Pointer Speicher zuweisen damit ich mit strcpy einen String als namen für einen Tag festlegen kann....

Ich hab heute vormittag/mittag schon versucht das irgendwie hinzubiegen, aber ich bekomm es nicht hin das ich die Länge eines Stirngs dynamisch allokiert und an den Pointer übergeben wird....

Bei einem Int Pointer kann ich doch auch Elemente hinzufügen oder entfernen mit realloc und Zuweisung über einen Index, ist der Datentyp char da anders?
 

exomo

NGBler

Registriert
1 Aug. 2015
Beiträge
129
Der char Pointer verhält sich ganz genauso wie ein int Pointer. Ob der Pointer in einer Struktur ist oder nicht spielt auch keine Rolle. Wichtig ist nur dass das array zuerst mit einem malloc allokiert wurde, bevor du realloc aufrufen kannst. Wenn das Array statisch initialisiert ist oder der Pointer noch gar nicht initialisiert ist funkioniert das nicht.

Als Tipp für die "Man muss den Pointer zusücksetzen" Problematik:
Behalte den Pointer den malloc usw. zurückgibt immer unverändert. Für Stringoperationen verwendest du einen zweiten Pointer. So hast du den richtigen zum freigeben immer noch verfügbar. Beim Arbeiten mit dynamischem Speicher ist es auch extrem wichtig, dass du dir darüber im Klaren bist wer den Speicher anfordert und wer ihn wann wieder freigibt.

Und genau solche Aufgaben sind der Grund warum ich niemandem empfehlen würde das mit C zu machen. Früher oder später macht man einen Fehler bei der Speicherverwaltung und wenn man Pech hat merkt man es nicht mal gleich sondern wundert sich irgendwann warum das Programm völlig unerklärlich abstürzt. Trotzdem ist C super um das Verständnis dafür zu bekommen wie das System arbeitet. Ich bin großer Fan von C++: Kann alles was C auch kann, hat aber einen deutlich höheren Programmierkomfort. Z.B. gibt es eine string Klasse. Manuelle Speicherverwaltung ist nur noch sehr selten notwendig. Wie electric.larry sagt kommt es immer auf den Fall an welche Sprache bzw. Bibliotheken dafür gerade am besten geeignet sind. Der einzige Fall für den bei mir die Wahl auf C fällt ist für Mikrokontroller, für die es keine anderen Compiler gibt :D
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #18
Der char Pointer verhält sich ganz genauso wie ein int Pointer. Ob der Pointer in einer Struktur ist oder nicht spielt auch keine Rolle. Wichtig ist nur dass das array zuerst mit einem malloc allokiert wurde, bevor du realloc aufrufen kannst. Wenn das Array statisch initialisiert ist oder der Pointer noch gar nicht initialisiert ist funkioniert das nicht.

Da liegt schon das Verständnisproblem das ich habe. Folgender Code, nochmal zusammen, da übersichtlicher und besser nachzuvollziehen:

[src=c]
typedef struct keyValue {
char* key;
char* value;
};

typedef struct tag {
unsigned int dataLength;
keyValue* data;
char* name; // Um "char* name" geht es...
node* parentNode;
};

typedef struct tags {
unsigned int tagCount;
tag* tags;
};
[/src]

und das funtkioniert nicht für mich:
currentTag ist ein char Array
[src=c]
// Speicher für den Tag in der Tag Liste anlegen
tagList.tags = (tag*) malloc(sizeof (tag)); // Speicher erstmal allkokieren, kommt Zeilen vorher
// ein paar Zeilen weiter im Code beim hinzufügen eines neue Tags in die Tag Liste:
tagList.tags = (tag*) realloc(tagList.tags, sizeof (tag) * (tagList.tagCount + 1));

//tagList.tags[tagList.tagCount].name = NULL; // Auskommentiert weil illegale zuweisung
// Speicher für Tag vorbereiten
tagList.tags[tagList.tagCount].name = (char*) malloc(sizeof (char)*(strlen(currentTag)+1)); // <--- schlägt Fehl mit "invalid old size"
strcpy(tagList.tags[tagList.tagCount].name, currentTag);
[/src]


Und genau das dieses Speicher allokieren, mit malloc, nicht funktioniert kann ich nicht nachvollziehen, hier muß doch irgend ein Fehler vorliegen?
Entweder in der Deklaration oder ich habe einen Denkfehler...

Wenn ich richtig recherchiert habe sagt der Fehler "invalid old size" das "Housekeeping" Daten in dem Pointer stehen? Etwas kryptisch.
 
Zuletzt bearbeitet:

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Was @exomo sagt. Hier wär noch ein Beispiel, wie du malloc und realloc verwenden kannst.

[src=c]
#include<stdio.h>
#include<string.h>
#include <stdlib.h>

typedef struct Tag
{
unsigned int dataLength;
char* name;

} tag;


int main()
{
struct Tag myTag;

//initialize with a short string
char* strShort = {"Larry"};
//save length of the short string
myTag.dataLength = strlen(strShort);
//get enough space in memory for our string
myTag.name = (char*)malloc(myTag.dataLength);
//copy the string to the struct
strcpy(myTag.name, strShort);

printf("name: %s\ndatalength: %i\n", myTag.name, myTag.dataLength);

//reinitialize with a longer string
char* strLong = {"Electric.Larry"};
//save length of the longer string
myTag.dataLength = strlen(strLong);
//resize the space in memory where our myTag.name pointer points to
myTag.name = (char*)realloc(myTag.name, myTag.dataLength);
//copy the longer string to our struct
strcpy(myTag.name, strLong);

printf("name: %s\ndatalength: %i\n", myTag.name, myTag.dataLength);

//clean up your mess
free (myTag.name);
myTag.name = NULL;
myTag.dataLength = 0;

return EXIT_SUCCESS;
}
[/src]
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #20
@electric.larry:
Kannst du bitte mal über meinen Code schauen und mir sagen wo ich den Denkfehler habe das ich einen Error bei der Ausführung bekomme?

Ich gehe eigentlich genau so vor wie in deinem Beispiel, außer das es etwas mehr verschachtelt ist... :unknown:
 
Oben