Autor |
Beitrag |
Frühlingsrolle
      
Beiträge: 2162
Erhaltene Danke: 399
[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
|
Verfasst: Do 24.08.17 09:20
Ob es Sinn macht, was Wikipedia da von sich gibt, kann ich nicht beurteilen. Ich hab das Beispiel so nicht übernommen, sondern ein eigenes frei heraus getippt.
Th69 meinte, meins sei falsch. Wiki zeigt ein ähnliches Beispiel auf. Was daran nun falsch ist, bleibt offen.
_________________ „Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 10:14
OK, ich dachte, das sei offensichtlich.
Ich kommentiere ihn deshalb mal:
C++-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| char* cNeu = new char[3]; cNeu = "Neu"; printf("%s", cNeu); delete(cNeu); char* cAlt = (char*)malloc(3 * sizeof(char)); cAlt = "Alt"; printf("%s", cAlt); free(cAlt); |
Wahrscheinlich meintest du in Zeile 2 (und [jetzt] 10):
C++-Quelltext 1: 2: 3:
| strncpy(cNeu, "Neu", 3); strncpy(cAlt, "Alt", 3); |
d.h. du schreibst in den mittels new/ malloc allozierten Speicherbereich etwas rein (s. strncpy).
Ergänzung: Bedenke, daß aber hier der String dann nicht null-terminiert ist, d.h. die Ausgaben mittels cout oder printf dann ebenso UB sind!
Für diesen Beitrag haben gedankt: Frühlingsrolle
|
|
Frühlingsrolle
      
Beiträge: 2162
Erhaltene Danke: 399
[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
|
Verfasst: Do 24.08.17 10:43
Ne, offensichtlich nicht. Ich kann auch nur einiges deichseln.
Zitat: | cNeu = "Neu"; // hier weist du dem Zeiger eine neue Adresse zu (auf ein String-Literal), daher ist der vorherige Zeigerwert überschrieben |
Stimmt, so weist man eine Adresse zu. Das war sehr dumm. Da müsste man mit strncpy() arbeiten.
Zitat: | Bedenke, daß aber hier der String dann nicht null-terminiert ist, d.h. die Ausgaben mittels cout oder printf dann ebenso UB sind! |
Gut, merk' ich mir, danke.
PS: Inwiefern unterscheidet sich das dann zu:
C++-Quelltext
_________________ „Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Do 24.08.17 10:59
Frühlingsrolle hat folgendes geschrieben : | Da müsste man mit strncpy() arbeiten. |
Je nach System. Der C11-Standard und Microsoft empfehlen strncpy_s, ältere C-Standards strncpy(), unter bestimmten Systemen mit bestimmten C-Standardbibliotheken bietet sich vielleicht eher strlcpy() an. Und so weiter.
Ja, aber cNeu ist hinterher immer noch NULL. 
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 12:29
C++-Quelltext
Dies gibt einen Compilerfehler (oder zumindestens eine Warnung): Ideone-Code, sofern cNeu weiterhin als char * deklariert ist, denn *cNeu entspricht ja cNeu[0], d.h. nur der Wert der Speicheradresse (also hier ein einzelnes Zeichen ( char)).
----------------
hydemarie hat folgendes geschrieben: | Ja, aber cNeu ist hinterher immer noch NULL. |
Was meinst du damit??? Wie kommst du auf NULL?
Für diesen Beitrag haben gedankt: Frühlingsrolle
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Do 24.08.17 12:42
Gegenfrage: Mit welchem Wert (nicht: Typ) ist cNeu denn initialisiert?
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 12:53
Wir reden (bzw. schreiben) hier doch von:
C++-Quelltext 1:
| char* cNeu = new char[3]; |
also hat cNeu wohl einen anderen Wert als NULL (und sollte new keinen Speicher mehr allozieren können, dann gibt es eine bad_alloc Exception).
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Do 24.08.17 13:04
Th69 hat folgendes geschrieben : | also hat cNeu wohl einen anderen Wert als NULL |
Nämlich?
Was ist denn der Standardwert eines char?
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 13:12
Ich verstehe dich leider immer noch nicht. Bitte poste nochmals den gesamten Code, auf den du dich beziehst.
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Do 24.08.17 13:20
Du behauptest, cNeu habe einen anderen Wert als NULL. Welchen hat er denn deiner Meinung nach? Das war doch eine eigentlich ganz einfach formulierte Frage.
Nachtrag:
C++-Quelltext 1:
| printf("cNeu ist %s\n", cNeu); |
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 13:36
cNeu ist ein Zeiger, d.h. es enthält eine Adresse:
C++-Quelltext
Wenn du
C++-Quelltext 1:
| printf("cNeu ist %s\n", cNeu); |
ausgibst, dann gibt du den Inhalt als nullterminierten String aus, auf den cNeu zeigt (das ist etwas ganz anderes - und NULL wird dann auch nicht ausgegeben).
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Do 24.08.17 13:44
Du hast meine Frage nicht beantwortet.
Der Wert, der an der Adresse, auf die der Zeiger zeigt, steht, ist was , wenn nicht NULL?
Was ist der Standardwert eines nicht initialisierten char*?
Th69 hat folgendes geschrieben : | NULL wird dann auch nicht ausgegeben). |
Das liegt daran, dass NULL nicht ausgegeben werden kann. Auf ideone steht da stattdessen (null) ...
Nachtrag:
Die ursprüngliche Frage war ja:
C++-Quelltext
Ich unterstelle, dass das so gemeint war, dass hinterher in cNeu "Neu" drinsteht. @Frühlingsrolle mag mich diesbezüglich korrigieren. Die Ausgabe von cNeu ist und bleibt hinterher aber "leer".
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 13:53
Das ist UB, denn bei einem nicht-initialisierten Zeiger weiß man ja gar nicht, worauf der Zeiger zeigt (irgendeine beliebige Speicheradresse):
C++-Quelltext 1: 2: 3: 4: 5: 6:
| int main() { char *cNeu; printf("%x\n", cNeu); printf("%s\n", cNeu); } |
(Im Debug-Modus werden diese [lokalen Variablen] zwar von einigen Compilern mit 0 initialisiert, aber spätestens im Release-Modus führst dies zu undefinertem Verhalten).
Nachtrag:
Dein letzter Satz ist jetzt aber erst recht widersprüchlich:
Wenn da "Neu" drinsteht (also wenn man es korrekt z.B. mittels strncpy oder strcpy kopiert), dann wird auch "Neu" ausgegeben!
Warum sollte der vorher zugewiesene Zeiger auf einem mal NULL sein???
Zuletzt bearbeitet von Th69 am Do 24.08.17 13:59, insgesamt 1-mal bearbeitet
Für diesen Beitrag haben gedankt: hydemarie
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Do 24.08.17 13:56
Th69 hat folgendes geschrieben : | Das ist UB, denn bei einem nicht-initialisierten Zeiger weiß man ja gar nicht, worauf der Zeiger zeigt |
Und wenn du ihn ausgibst, ist das Verhalten in jedem mir bekannten Compiler gleich: Da steht dann "nichts" drin.
(N.b.: calloc() ist in vielen Fällen die deutlich bessere Wahl, wenn man sich über die Werte nicht ganz sicher ist.)
|
|
Th69
      

Beiträge: 3930
Erhaltene Danke: 803
Win7
C++, C# (VS 2015/17)
|
Verfasst: Do 24.08.17 14:11
Hier nochmal als Ideone-Code -> Runtime error!
|
|
Frühlingsrolle
      
Beiträge: 2162
Erhaltene Danke: 399
[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
|
Verfasst: Do 24.08.17 16:22
Konzentrieren wir uns dann wieder auf das malloc() im Zusammenhang mit der Sprache C. Für die String und Pointer Verarbeitung in C und C++ würde ich dafür ein neues Topic erstellen und ein "Übungsbeispiel" oder zwei durchgehen. Das kann, wie man sieht, nicht schaden. 
_________________ „Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Für diesen Beitrag haben gedankt: hydemarie
|
|
tomycat 
      
Beiträge: 174
Erhaltene Danke: 1
|
Verfasst: Fr 25.08.17 07:16
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Fr 25.08.17 08:20
Du machst den Speicher frei, sobald du ihn beziehungsweise den Wert nicht mehr brauchst.
Am Ende würde auch gehen, aber dann müsstest du realloc() (Neubelegen noch reservierten Speichers) für jede Zeile nutzen. Vorteil: du müsstest nur noch einmal aufräumen. Ist aber gefährlicher, was mögliche Memleaks, also auch nach dem Programmende noch belegten Speicher, betrifft, zum Beispiel bei Fehlern in der Schleife.
Für diesen Beitrag haben gedankt: tomycat
|
|
tomycat 
      
Beiträge: 174
Erhaltene Danke: 1
|
Verfasst: Fr 25.08.17 15:10
ok,
Zeile 2: Wenn textfile Null, dann bricht die Schleife ab.
Zeile 3: Es wird Untersucht ob ein \n in textfile vorhanden ist, das wird in nextline gespeichert.
Zeile 4: ist nextline wahr, dann kommt es zu einer Subtaktion, ähh das geht ?!? Zeichenlänge wird berechnet
Zeile 5: Dann reserviere ich mir einen Speicherplatz für linelenth und weise Ihn dem temp_str zu, richtig?
Wird die If Abfrage ausgeführt, bei 10 Zeilen, 10 mal ausgeführt. Dann wird doch immer der Speicher wieder freigegeben?
|
|
hydemarie
      
Beiträge: 405
Erhaltene Danke: 50
|
Verfasst: Fr 25.08.17 15:18
Das ist so richtig, ja. 
Für diesen Beitrag haben gedankt: tomycat
|
|