Forum: PC-Programmierung Struktelement in Funktion ändern


von Max F. (mexxe)


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
}

: Bearbeitet durch User
von Hans Ulli K. (Gast)


Lesenswert?

Max F. schrieb:
>
1
> void eingabe_vorname(node *temp) {
2
>   char *f1, *f2, c;
3
>   int pos = 0;
4
> ...
5
>   delete [] f1;
6
>   temp->vorname = f2;
7
>   pos = 0;
8
>   delete [] f2;
9
> ...
10
>

Fällt dir was auf ??

von Peter II (Gast)


Lesenswert?

1
temp->vorname = f2;
2
  pos = 0;
3
  delete [] f2;


du gibst ja gleich den Speicher wieder frei.

Generell solltest du ein paar mehr string funtionen verwenden.

von Max F. (mexxe)


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.

: Bearbeitet durch User
von Arc N. (arc)


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)

von Max F. (mexxe)


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^^

von Hans Ulli K. (Gast)


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.

von Arc N. (arc)


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;

von Rolf Magnus (Gast)


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++.

von Daniel A. (daniel-a)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.