Autor Beitrag
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1984
Erhaltene Danke: 365

[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
BeitragVerfasst: Do 24.08.17 10: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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 11:14 
OK, ich dachte, das sei offensichtlich. ;-)
Ich kommentiere ihn deshalb mal:
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
char* cNeu = new char[3];
cNeu = "Neu"// hier weist du dem Zeiger eine neue Adresse zu (auf ein String-Literal), daher ist der vorherige Zeigerwert überschrieben
printf("%s", cNeu);
delete(cNeu); // und hier hast du zwei Fehler:
              // 1. bei Arrays immer delete [] verwenden
              // 2. Undefined behaviour (UB), da jetzt in cNeu die Adresse des String-Literals steht (und nicht der von new allokierte)
// eventuell noch NULL setzen

char* cAlt = (char*)malloc(3 * sizeof(char));
cAlt = "Alt"// selbiges wie oben
printf("%s", cAlt);
free(cAlt); // also auch hier UB

Wahrscheinlich meintest du in Zeile 2 (und [jetzt] 10):
ausblenden C++-Quelltext
1:
2:
3:
strncpy(cNeu, "Neu"3);
// bzw.
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1984
Erhaltene Danke: 365

[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
BeitragVerfasst: Do 24.08.17 11: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:
ausblenden C++-Quelltext
1:
*cNeu = "Neu"// findet hier eine Stringzuweisung statt?					

_________________
„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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Do 24.08.17 11:59 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
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. :wink:

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden C++-Quelltext
1:
*cNeu = "Neu"// findet hier eine Stringzuweisung statt?					


Ja, aber cNeu ist hinterher immer noch NULL. 8)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 13:29 
ausblenden C++-Quelltext
1:
*cNeu = "Neu";					

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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Do 24.08.17 13:42 
Gegenfrage: Mit welchem Wert (nicht: Typ) ist cNeu denn initialisiert?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 13:53 
Wir reden (bzw. schreiben) hier doch von:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Do 24.08.17 14:04 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
also hat cNeu wohl einen anderen Wert als NULL


Nämlich?

Was ist denn der Standardwert eines char?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 14:12 
Ich verstehe dich leider immer noch nicht. Bitte poste nochmals den gesamten Code, auf den du dich beziehst.
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Do 24.08.17 14: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:

ausblenden C++-Quelltext
1:
printf("cNeu ist %s\n", cNeu);					
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 14:36 
cNeu ist ein Zeiger, d.h. es enthält eine Adresse:
ausblenden C++-Quelltext
1:
printf("%x", cNeu);					

Wenn du
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Do 24.08.17 14: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*? :)

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
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:

ausblenden C++-Quelltext
1:
*cNeu = "Neu"// findet hier eine Stringzuweisung statt?					


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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 14:53 
Das ist UB, denn bei einem nicht-initialisierten Zeiger weiß man ja gar nicht, worauf der Zeiger zeigt (irgendeine beliebige Speicheradresse):
ausblenden 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 14:59, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: hydemarie
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Do 24.08.17 14:56 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3706
Erhaltene Danke: 753

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Do 24.08.17 15:11 
Hier nochmal als Ideone-Code -> Runtime error!
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1984
Erhaltene Danke: 365

[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
BeitragVerfasst: Do 24.08.17 17: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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 171
Erhaltene Danke: 1



BeitragVerfasst: Fr 25.08.17 08:16 
user profile iconhydemarie hat folgendes geschrieben Zum zitierten Posting springen:
Du brauchst malloc/calloc beziehungsweise realloc zum Beispiel für C und damit auch die Interaktion mit C.

Konkreter Anwendungsfall: du möchtest eine Textdatei zeilenweise in eine Variable speichern. Da C keine std::strings und keine Vektoren kennt, bräuchtest du dafür zum Beispiel einen char**-Pointer. Die einzelnen Strings brauchen aber jedes Mal eine andere Anzahl an Byte, sie sind ja selten identisch.

ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
/* Annahme: char* textfile enthält Textdatei */
while (textfile) {
    char* next_line = strchr(textfile, '\n');
    int linelength = next_line ? (next_line - textfile) : strlen(textfile); /* berechne Zeilenlänge */
    char* temp_str = (char *)malloc(linelength + 1); /* alloziere genau so viel Speicher (plus Nullterminator)! */

    if (temp_str) {
        memcpy(temp_str, textfile, linelength);
        temp_str[linelength] = '\0';
        /* temp_str = aktuelle Zeile */
        /* mach irgendwas damit */
        free(temp_str);
    }

    textfile = next_line ? (next_line + 1) : NULL;
}


Absturz (Beispiel): Räume einen Speicherbereich frei, der dir nicht gehört.

ausblenden C++-Quelltext
1:
2:
int quux = 42;
free(quux); /* peng */


ok, wenn ich es richtig verstanden habe, lese ich eine Text Datei zeilenweise aus und jedesmal beantrage ich einen Speicherbereich. Erst am Ende mache ich den Speicher wieder frei?
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Fr 25.08.17 09: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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 171
Erhaltene Danke: 1



BeitragVerfasst: Fr 25.08.17 16: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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 48



BeitragVerfasst: Fr 25.08.17 16:18 
Das ist so richtig, ja. :)

Für diesen Beitrag haben gedankt: tomycat