Struktelement in Funktion ändern

OP #4586469
Lesenswert?
• ▲
▼
Hallo Gemeinde,
Ich habe ein Problem mit meinem Programm. Ich möchte einem Element eines 
Structs innerhalb einer Funktion ein Feld übergeben und dieses ausgeben 
lassen. Eigentlich arbeite ich da schon mit Feldern, weshalb ich den 
Fehler nicht sehe...Kann mir da jemand behilflich sein?
1
struct node {                       // Zur Übung ist bisher nur ein Element
2
  char* vorname;              // drin, weitere sollen aber folgen
3
};
4

5

6
void eingabe_vorname(node *temp) {
7
  char *f1, *f2, c;
8
  int pos = 0;
9

10
  
11
  f1 = new char [100];
12

13
  c = getchar();
14

15
  while (c != '\n') {
16
    f1[pos] = c;
17
    pos++;
18
    c = getchar();
19
  }
20

21
  f1[pos] = '\0';
22
  f2 = new char[pos];
23
  
24
  pos = 0;
25

26
  while (f1[pos] != '\0') {        
27
    f2[pos] = f1[pos];
28
    pos++;
29
  }
30

31
  delete [] f1;
32
  temp->vorname = f2;      // Hier vermute ich den Fehler
33
  pos = 0;
34
  delete [] f2;
35

36
/*  while (*temp->vorname[pos] != '\0') {         // Funktioniert nicht
37
    putchar(*temp->vorname[pos]);
38
    pos++;
39
  }
40
*/
41

42
}
43

44

45
int main () {
46
        int pos = 0;
47
  node *temp;
48
  temp = new node;
49
  printf("Bitte geben Sie hier Ihren Vornamen ein: ");
50
  eingabe_vorname(temp);
51

52
  while (temp->vorname[pos] != '\0') {    // Funktioniert nicht
53
    putchar(temp->vorname[pos]);
54
    pos++;
55
  }
56

57
  delete [] temp;
58

59
  return 0;
60
}
OP #4586488
Lesenswert?
• ▲
▼
Peter II schrieb:
>
1
> temp->vorname = f2;
2
>   pos = 0;
3
>   delete [] f2;
4
> 
5
>
>
>
> du gibst ja gleich den Speicher wieder frei.
>
> Generell solltest du ein paar mehr string funtionen verwenden.

Also gebe ich den Speicher frei, wo meine Elemente drin stehen...Er kann 
also keine Elemente ausgeben, die logischerweise ja nicht da sind, oder 
sehe ich das falsch?

Edit fragt: Warum bekomme ich da eigentlich keinen 
Speicherzugriffsfehler?

Viel wichtiger: Wenn ich dann den Speicher mittels
1
delete [] temp;
wieder freigebe, wird dann auch der Speicher für f2 freigegeben? Und 
wenn nein, wie mache ich das?
Meine ursprüngliche Aufgabe ist ein Feld von (Stru ct-)Zeigern zu 
initialisieren, die dem Nullzeiger zugewiesen sind oder eben auf den 
struct node zeigen.
Ich frage deshalb, weil ich in einer Teilaufgabe den Struct auch wieder 
löschen muss und dem Zeiger die 0 zuweisen muss und da Bedenken zwecks 
dem angeforderten Speicher für f2 habe.
#4586602
Lesenswert?
• ▲
▼
Max F. schrieb:
> Edit fragt: Warum bekomme ich da eigentlich keinen
> Speicherzugriffsfehler?

Solange nichts anderes mit dem Speicher angestellt wird, "funktioniert" 
das...
Nennt sich allerdings Use-After-Free oder Dangling-Pointer und ist eine 
klassische Sicherheitslücke 
https://en.wikipedia.org/wiki/Dangling_pointer
von denen noch ein paar andere im Quelltext schlummern...

> Viel wichtiger: Wenn ich dann den Speicher mittels
>
1
> delete [] temp;
2
>
> wieder freigebe, wird dann auch der Speicher für f2 freigegeben?

Nein.

> Und wenn nein, wie mache ich das?

Erst delete [] temp->vorname, dann delete [] temp oder im Destructor von 
node (Anhand der Mischung ist nicht so ganz eindeutig, ob das jetzt C 
oder C++ werden soll und ob und wenn ja welche Funktionen aus den 
dazugehörigen Libs verwendet werden sollen/dürfen)
OP #4586611
Lesenswert?
• ▲
▼
Arc N. schrieb:
> Max F. schrieb:
>> Edit fragt: Warum bekomme ich da eigentlich keinen
>> Speicherzugriffsfehler?
>
> Solange nichts anderes mit dem Speicher angestellt wird, "funktioniert"
> das...
> Nennt sich allerdings Use-After-Free oder Dangling-Pointer und ist eine
> klassische Sicherheitslücke
> https://en.wikipedia.org/wiki/Dangling_pointer
> von denen noch ein paar andere im Quelltext schlummern...
>
>> Viel wichtiger: Wenn ich dann den Speicher mittels
>>
1
>> delete [] temp;
2
>>
>> wieder freigebe, wird dann auch der Speicher für f2 freigegeben?
>
> Nein.
>
>> Und wenn nein, wie mache ich das?
>
> Erst delete [] temp->vorname, dann delete [] temp oder im Destructor von
> node (Anhand der Mischung ist nicht so ganz eindeutig, ob das jetzt C
> oder C++ werden soll und ob und wenn ja welche Funktionen aus den
> dazugehörigen Libs verwendet werden sollen/dürfen)

Es soll C++ werden ;)
Danke, hab es jetzt auch verstanden! NEW liefert ja nur einen Zeiger und 
wenn ich den Zeiger jetzt temp->vorname zuordne, kann ich auch darüber 
den Speicher freigeben...!  :)
Ich darf lediglich stdio.h benutzen^^
Gast #4586621
Lesenswert?
• ▲
▼
Max F. schrieb:
> Danke, hab es jetzt auch verstanden! NEW liefert ja nur einen Zeiger und
> wenn ich den Zeiger jetzt temp->vorname zuordne, kann ich auch darüber
> den Speicher freigeben...!  :)

Du kannst den Zeiger so oft kopieren wie du willst.

Das Problem bei Zeigern ist, das die Kopien nicht wissen, das der 
original Speicherbereich nicht mehr existiert !!

Ich glaube es gab mal die Idee das es mit einem "Zeiger auf Zeiger" zu 
lösen. In C++ ginge das mit einer Referenz.
Aber wenn diese(r) wieder "aufgelöst" wird, kommt man zum obigen Problem 
wieder zurück.
#4586641
Lesenswert?
• ▲
▼
Hans Ulli K. schrieb:
> Ich glaube es gab mal die Idee das es mit einem "Zeiger auf Zeiger" zu
> lösen.

unique_ptr<>, shared_ptr<>, weak_ptr<> und Konsorten in neueren 
C++-Varianten. In Rust ist es sauberer gelöst, aber auch komplizierter 
(Ownership, Borrowing und Lifetimes)

> In C++ ginge das mit einer Referenz.

Genauso gut...
1
char* str = new char[100];
2
char& str_ref = *str;
3
...
4
delete [] str;
5
...
6
return str_ref;
Gast #4586744
Lesenswert?
• ▲
▼
Max F. schrieb:
> (Anhand der Mischung ist nicht so ganz eindeutig, ob das jetzt C
> oder C++ werden soll und ob und wenn ja welche Funktionen aus den
> dazugehörigen Libs verwendet werden sollen/dürfen)
>
> Es soll C++ werden ;)

Der Code ist allerdings komplett im C-Stil gehalten. Bis auf die 
Verwendung von new und delete statt malloc und free ist das reiner 
C-Code.

> Ich darf lediglich stdio.h benutzen^^

Ist nicht unbedingt sehr sinnvoll in C++.
#4586881
Lesenswert?
• ▲
▼
Arc N. schrieb:
>> In C++ ginge das mit einer Referenz.
>
> Genauso gut...char* str = new char[100];
> char& str_ref = *str;
> ...
> delete [] str;
> ...
> return str_ref;

NEEEIIN! So referenziert man nur das erste char, und nach dem Delete ist 
das Referenzierte char auchnoch freigegeben! Referenzen sind genau wie 
zeiger, abgesehen davon, dass sie sich nur auf ein Element beziehen, und 
man sie nur über Umwege auf 0 Zeigen lassen kann.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren