WinFuture-Forum.de: C: malloc() und free() - WinFuture-Forum.de

Zum Inhalt wechseln

Nachrichten zum Thema: Entwicklung
Seite 1 von 1

C: malloc() und free() Speicherzugriffsfehler


#1 Mitglied ist offline   Fabi 

  • Gruppe: aktive Mitglieder
  • Beiträge: 1.958
  • Beigetreten: 30. August 04
  • Reputation: 1
  • Geschlecht:Männlich

geschrieben 25. September 2010 - 09:06

Hi,

ich dachte eigentlich das prinzip von malloc() und free() verstanden zu haben, leider erhalte ich hier trotzdem einen Speicherzugriffsfehler.
Ich habe hier ein kleines Programm, das in einem Rutsch sehr viele Dateien umbenennen soll.

Hier mal der Code-Ausschnitt dazu der meiner Meinung nach Probleme macht:
while((ptr_mydir=readdir(mydir)) != NULL)
{
			//Ausgabe der Dateien
			
			if(strcmp((*ptr_mydir).d_name,".") != 0)
			{
				if(strcmp((*ptr_mydir).d_name,"..") != 0)
				{
										i_Files += 1;
					/*Allokation des Speichers für den alten Dateipfad*/
					ptr_dirNameOld =   malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof((*ptr_mydir).d_name));
					ptr_cpyOld = malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof((*ptr_mydir).d_name));
					strcpy(ptr_dirNameOld,FilePath);
					strcat(ptr_dirNameOld,DELIMETER);
					strcat(ptr_dirNameOld,(*ptr_mydir).d_name);
					
					/*Sicherung des Dateinamens machen*/
					strcpy(ptr_cpyOld,ptr_dirNameOld);

					/*Auslesen der Dateiendung*/
					posPoint = strtok(ptr_dirNameOld,".");
					posPoint = strtok(NULL,".");/*Nächsten Token (Dateiendung) auslesen*/
				

					/*Allokation des Speichers für den neuen Dateinamen*/
					ptr_dirNameNew = malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof(NewFileName)+sizeof(c_Files + 1)+sizeof(".")+sizeof(posPoint));
					strcpy(ptr_dirNameNew,FilePath);
					strcat(ptr_dirNameNew,DELIMETER);
					strcat(ptr_dirNameNew,NewFileName);
					
					


					

					

					free(ptr_dirNameOld);
					free(ptr_cpyOld);
					free(ptr_dirNameNew);
									
				}
}


Ich habe das ganze mal auf eine "lesbare" Länge gekürzt, aber das Problem bleibt ja erhalten.
Ich habe das so verstanden, das wenn ich mit malloc() Speicher reserviere und ihn dann wieder freigebe es eigentlich keine Probleme geben dürfte, oder ist hier die while-Schleife das Problem?
Oder steh ich grad nur auf dem Schlauch?
Sobald die erste Datei umbenannt ist, kommt der Speicherzugriffsfehler, dass heisst nach dem ersten mal free().

Ausgabe:

Zitat

fabi@schnecki-workstation ~/Programmierung/C_C++/Renamer $ ./renamer /home/fabi/Programmierung/C_C++/Renamer/Bilder/ test
Dateipfad: /home/fabi/Programmierung/C_C++/Renamer/Bilder/

Verzeichnis wurde erfolgreich geoffnet: /home/fabi/Programmierung/C_C++/Renamer/Bilder/

Anzahl Dateien : 1669
Dateiname (alt): /home/fabi/Programmierung/C_C++/Renamer/Bilder/bild1.jpg
Dateiname (neu): /home/fabi/Programmierung/C_C++/Renamer/Bilder/test1.jpg
Speicherzugriffsfehler


Vielen Dank für eure Hilfe.

lg,
Fabi
0

Anzeige



#2 Mitglied ist offline   Mr. Floppy 

  • Gruppe: VIP Mitglieder
  • Beiträge: 4.115
  • Beigetreten: 01. Juli 08
  • Reputation: 271
  • Geschlecht:Männlich

geschrieben 25. September 2010 - 11:21

Mein C ist zwar schon etwas eingerostet, aber mir sticht der fehlende Zeigertyp vor malloc ins Auge.
Zeiger = (Zeigertyp) malloc (#Bytes);

Es kann auch nicht schaden, die Größe des Zeigers danach auf Null zu überprüfen. Wenn's irgendwie geht, sollte man auch strncpy statt strcpy benutzen. Bei strcat und allen anderen Stringoperationen ist man auch immer gut beraten, an das abschließende, platzverbrauchende \0 zu denken. Dazu ist bei Dir wahrscheinlich der Delimiter gedacht.
0

#3 Mitglied ist offline   Fabi 

  • Gruppe: aktive Mitglieder
  • Beiträge: 1.958
  • Beigetreten: 30. August 04
  • Reputation: 1
  • Geschlecht:Männlich

geschrieben 25. September 2010 - 22:27

@Mr. Floppy: Vielen Dank für deine Hilfe!
Das mit dem cast werde ich sofort ausprobieren wenn icg wieder daheim bin.
Wenn ich das free() am Ende der Prozedur weglasse kann ich ca. 216 Dareien umbenennen, dann erhalte ich einen Speicherzugriffsfehler.
Das liegt aber vermutlich daran, dass keine (virtueller) Speicher mehr reserviert. werden kann.

/0 sollte uch unbedingt noch ab die Strings anhängen, der Delimeter ist das Trennzeichen für Pfad und Datei (*nix = / und Win = \).

Lg,
Fabi
0

#4 Mitglied ist offline   Fabi 

  • Gruppe: aktive Mitglieder
  • Beiträge: 1.958
  • Beigetreten: 30. August 04
  • Reputation: 1
  • Geschlecht:Männlich

geschrieben 27. September 2010 - 18:29

Also trotz des cast kommt immernoch die selbe Meldung.
Kann es evtl. daran liegen, dass ich die Variablen ptr_dirNameOld und ptr_cpyOld aus den selben Variablen aufbaue?

Denn der Fehler kommt erst nach dem
 free(ptr_dirNameOld)

danach gebe ich ja den Speicher von ptr_cpyOld frei.

lg,
Fabi
0

#5 Mitglied ist offline   Mr. Floppy 

  • Gruppe: VIP Mitglieder
  • Beiträge: 4.115
  • Beigetreten: 01. Juli 08
  • Reputation: 271
  • Geschlecht:Männlich

geschrieben 27. September 2010 - 18:50

Ich tippe auf folgende Zeile:
strcpy(ptr_cpyOld,ptr_dirNameOld);

Das gemeine an strcpy ist, daß es bis zum ersten \0 kopiert. Wenn ptr_dirNameOld also nicht terminiert ist, steht in ptr_cpyOld mehr drin als man eigentlich haben will. Je nachdem wie die Daten im Speicher liegen, kommt der Fehler dann erst beim free. Guck Dir mal die Größen vor und nach dem Kopieren an und ob das alles paßt. Du kannst ja auch erst mal mit festen, ausreichenden Werten (1024?) für die Strings arbeiten. Wenn das klappt, stimmt was bei der Längenberechnung noch nicht.
0

#6 Mitglied ist offline   Fabi 

  • Gruppe: aktive Mitglieder
  • Beiträge: 1.958
  • Beigetreten: 30. August 04
  • Reputation: 1
  • Geschlecht:Männlich

geschrieben 27. September 2010 - 19:20

@Mr.Floppy: Ich habe hier jetzt ein echt komisches Verhalten.
Ich hab das strcpy auf dein durch strncpy ersetzt.
strncpy(ptr_dirNameOld,FilePath,(int) strlen(FilePath));
strncpy(ptr_dirNameNew,FilePath,(int)strlen(FilePath));
strncpy(ptr_cpyOld,ptr_dirNameOld,(int) strlen(ptr_dirNameOld));


Jetzt funktioniert auch das free() :(.
Aber meine Dateinamen die auslese sehen irgendwie komisch aus.

Beispiel:
ZITAT

fabi@schnecki-workstation ~/Programmierung/C_C++/Renamer $ ./renamer Bilder rename_test_
Dateipfad: Bilder

Verzeichnis wurde erfolgreich geoffnet: Bilder

Anzahl Dateien : 13
Laenge (alt): 21
Laenge (neu): 21
Dateiname (alt): Bilder/MyPicsNew2.jpg
Dateiname (neu): Bilder/rename_test_1.jpg
Laenge (alt): 24
Laenge (neu): 24
Dateiname (alt): Bilder/rename_test_2.jpg
Dateiname (neu): Bilder/rename_test_2.jpg
Laenge (alt): 24
Laenge (neu): 24
Dateiname (alt): Bilder/rename_test_6.jpg
Dateiname (neu): Bilder/rename_test_3.jpg
Laenge (alt): 24
Laenge (neu): 24
Dateiname (alt): Bilder/rename_test_4.jpg
Dateiname (neu): Bilder/rename_test_4.jpg
Laenge (alt): 24
Laenge (neu): 24
Dateiname (alt): Bilder/rename_test_1.jpg
Dateiname (neu): Bilder/rename_test_5.jpg
Laenge (alt): 24
Laenge (neu): 24
Dateiname (alt): Bilder/rename_test_9.jpg
Dateiname (neu): Bilder/rename_test_6.jpg
Laenge (alt): 25
Laenge (neu): 25
Dateiname (alt): Bilder/rename_test_12.jpg
Dateiname (neu): Bilder/rename_test_7.jpg
Laenge (alt): 21
Laenge (neu): 25
Dateiname (alt): Bilder/MyPicsNew1.jpg.jpg
Dateiname (neu): Bilder/rename_test_8.jpg
Datei: Bilder/MyPicsNew1.jpg.jpg
konnte nicht umbenannt werden.
Laenge (alt): 17
Laenge (neu): 25
Dateiname (alt): Bilder/.directory.jpg.jpg
Dateiname (neu): Bilder/rename_test_9.directory
Datei: Bilder/.directory.jpg.jpg
konnte nicht umbenannt werden.
Laenge (alt): 21
Laenge (neu): 25
Dateiname (alt): Bilder/MyPicsNew9.jpg.jpg
Dateiname (neu): Bilder/rename_test_10.jpg
Datei: Bilder/MyPicsNew9.jpg.jpg
konnte nicht umbenannt werden.
Laenge (alt): 24
Laenge (neu): 25
Dateiname (alt): Bilder/rename_test_7.jpgg
Dateiname (neu): Bilder/rename_test_11.jpg
Datei: Bilder/rename_test_7.jpgg
konnte nicht umbenannt werden.
Laenge (alt): 22
Laenge (neu): 25
Dateiname (alt): Bilder/NeuerName_1.jpgpgg
Dateiname (neu): Bilder/rename_test_12.jpg
Datei: Bilder/NeuerName_1.jpgpgg
konnte nicht umbenannt werden.
Laenge (alt): 24
Laenge (neu): 25
Dateiname (alt): Bilder/rename_test_3.jpgg
Dateiname (neu): Bilder/rename_test_13.jpg
Datei: Bilder/rename_test_3.jpgg
konnte nicht umbenannt werden.


Ab einem bestimmten Zeitpunkt wird mein Eingangsdateinamen falsch aufgebaut.
Auf jeden fall war der Tipp mit strncpy schonmal Gold wert :), danke dafür.

Was mir noch aufgefallen ist, wenn ich einen int in eine string mit sprintf kopiere und den Speicher für den String zuvor auch mit malloc allokiert habe, erhalte ich auch einen error.
Obwohl ich an den String "\0" angehängt habe.

lg,
Fabi
0

#7 Mitglied ist offline   Mr. Floppy 

  • Gruppe: VIP Mitglieder
  • Beiträge: 4.115
  • Beigetreten: 01. Juli 08
  • Reputation: 271
  • Geschlecht:Männlich

geschrieben 27. September 2010 - 20:25

Zitat

Ab einem bestimmten Zeitpunkt wird mein Eingangsdateinamen falsch aufgebaut.
Guck Dir den Code nochmal genau an. Die Längen stimmen nicht:
Laenge (alt): 25
Laenge (neu): 25
Dateiname (alt): Bilder/rename_test_12.jpg
Dateiname (neu): Bilder/rename_test_7.jpg

Hier ist neu um eine Stelle kürzer als angezeigt wird. Außerdem scheint der alte String immer so groß wie der neue zu sein. Das würde auch die überflüssigen Zeichen erklären. Das sind die Reste vom alten String, die noch im Speicher sind.

Zitat

Obwohl ich an den String "\0" angehängt habe.
sprintf hängt selbst noch ein \0 dran!
0

#8 Mitglied ist offline   Fabi 

  • Gruppe: aktive Mitglieder
  • Beiträge: 1.958
  • Beigetreten: 30. August 04
  • Reputation: 1
  • Geschlecht:Männlich

geschrieben 27. September 2010 - 20:49

@Mr.Floppy:
Die Länge von neu und alt bezieht sich auf ptr_dirNameOld und ptr_cpyOld (auf die Kopie von ptr_dirNameOld). Die Darstellung ist etwas doof, aber für mich zum Debuggen und Fehlersuchen ganz wichtig.

Die Dateilänge von ptr_dirNameOld und ptr_cpyOld variert tortzdem ab und zu.
Hier mal der Code:
ptr_dirNameOld = (char*) malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof((*ptr_mydir).d_name)+sizeof("\0"));
				ptr_cpyOld	 = (char*) malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof((*ptr_mydir).d_name)+sizeof("\0"));
				strncpy(ptr_dirNameOld,FilePath,(int) strlen(FilePath));
				strcat(ptr_dirNameOld,DELIMETER);
				strcat(ptr_dirNameOld,(*ptr_mydir).d_name);
				strcat(ptr_dirNameOld,"\0");
					
			/*Sicherung des Dateinamens machen*/
				strncpy(ptr_cpyOld,ptr_dirNameOld,(int)strlen(ptr_dirNameOld));
				fprintf(stdout,"Dateilaenge ptr_dirNameOld: %d\n",(int)strlen(ptr_dirNameOld));
				fprintf(stdout,"Dateilaenge ptr_cpyOld: %d\n",(int)strlen(ptr_cpyOld));

Komischerweise ist die Länge der beiden unterschiedlich, ich frag mich echt woran das liegt.
Zumal ich sie ja genau gleich initialisiere und dann kopiere.

lg,
Fabi
0

#9 Mitglied ist offline   Cataclysm 

  • Gruppe: Mitglieder
  • Beiträge: 4
  • Beigetreten: 06. November 08
  • Reputation: 0

geschrieben 27. September 2010 - 21:22

Beitrag anzeigenZitat (Fabi: 27.09.2010, 20:49)

ptr_dirNameOld = (char*) malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof((
*ptr_mydir).d_name)+sizeof("\0"));
ptr_cpyOld = (char*) malloc(sizeof(FilePath)+sizeof(DELIMETER)+sizeof((
*ptr_mydir).d_name)+sizeof("\0"));

Mal eine dumme Frage.... FilePath ist deklariert als char[] oder als char * ? sizeof(char *) ist nämlich die Länge eines Zeigers...

Edit:

Beitrag anzeigenZitat (Fabi: 27.09.2010, 20:49)

strcat(ptr_dirNameOld,"\0");

Dieser Befehl macht genau gar nichts :( strcat() kopiert einen String bis zum Ende (== erstes Vorkommen von 0x00 im String), also wird gar nichts kopiert.

Dieser Beitrag wurde von Cataclysm bearbeitet: 27. September 2010 - 21:33

0

#10 Mitglied ist offline   Fabi 

  • Gruppe: aktive Mitglieder
  • Beiträge: 1.958
  • Beigetreten: 30. August 04
  • Reputation: 1
  • Geschlecht:Männlich

geschrieben 29. September 2010 - 15:52

Zitat

FilePath ist deklariert als char[]

Jap, FilePath ist ein char[] mit fester Länge.
Dann wird es wohl daran liegen, oder?
Wie kann ich das dann machen? FilePath wird der Funktion übergeben bzw. ist ein Parameter für das mein Programm (steht in argv[1]).

Wahrscheinlich habe ich auch deshalb Probleme bei langen Dateipfaden....

Zitat

Dieser Befehl macht genau gar nichts ;D strcat() kopiert einen String bis zum Ende (== erstes Vorkommen von 0x00 im String), also wird gar nichts kopiert.

Klingt logisch :smokin: !
Danke dafür.

lg,
Fabi
0

#11 Mitglied ist offline   Cataclysm 

  • Gruppe: Mitglieder
  • Beiträge: 4
  • Beigetreten: 06. November 08
  • Reputation: 0

geschrieben 30. September 2010 - 11:05

Du kannst sizeof() auf char[] benutzen, wo der Compiler klar weiß wie groß das Array ist. Wenn es aber ein char* ist benutz einfach strlen().

Meine Vermutung z.Zt. ist daß die Strings kürzer ge'malloc()ed werden als sie müssten und du dadurch wild im Stack rumschreibst. Passt zumindest zum Symptom.

Die strcat()-Komplexe würde ich auch der Übersicht halber durch sprintf() ersetzen.
0

Thema verteilen:


Seite 1 von 1

1 Besucher lesen dieses Thema
Mitglieder: 0, Gäste: 1, unsichtbare Mitglieder: 0