Forum: PC-Programmierung Listeneintrag beschreiben in C


von lueis (Gast)


Lesenswert?

Guten Tag,

Ich habe eine Struktur:
1
typedef struct function{
2
  int inter;
3
  char *functionName;
4
  };
5
6
struct function *firstFct; //=NULL führt zu Fehlermeldung "_firstFct bereits in .obj definiert" wieso?

und dazu eine füllfunktion:
1
void addFunction(char *functionName) {
2
3
   struct function *zeiger;
4
5
   if(firstFct == NULL) {
6
      if((firstFct = malloc(sizeof(struct function))) == NULL) {
7
         fprintf(stderr, "Kein Speicherplatz vorhanden "
8
                         "fuer anfang\n");
9
         return;
10
      }
11
12
13
      firstFct->inter=3; //ich brauch kein int, aber das funktioniert noch
14
      strcpy(firstFct->functionName,functionName); //char * strcpy ( char * destination, const char * source ); 
15
      firstFct->next=NULL;
16
   }
17
18
19
   else {
20
 //Neues Element
21
   }
22
}
ich rufe sie auf mit
char string[39];
addFunction(string)
In der zeile:  strcpy(firstFct->functionName,functionName); springt das 
Programm aber zur Laufzeit raus. woran kann das liegen?
ist es überhaupt möglich, pointer in einem struct zu nutzen?(malloc weiß 
dann ja gar nicht, wie groß die struct ist.) oder muss hier bereits die 
länge vordefiniert sein?

Schönen Gruß
lueis

von Uhu U. (uhu)


Lesenswert?

lueis schrieb:
> strcpy(firstFct->functionName,functionName); //char * strcpy ( char *
> destination, const char * source );
1
 strcpy(firstFct->functionName,functionName); //char * strcpy ( char * destination, const char * source );

firstFct->functionName ist nicht initialisiert und zeigt auf keinen 
gültigen Speicher.

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

lueis schrieb:
> In der zeile:  strcpy(firstFct->functionName,functionName); springt das
> Programm aber zur Laufzeit raus. woran kann das liegen?

Daran, daß du keinen Speicher für die Daten bereitstellst.
firstFct->functionName ist ein Zeiger, der nicht initialisiert ist. Er 
zeigt also irgendwo in den Wald. Und mit strcpy kopierst du deinen Text 
nun an dieses Irgendwo.

> ist es überhaupt möglich, pointer in einem struct zu nutzen?

Ja.

> (malloc weiß dann ja gar nicht, wie groß die struct ist.)

Doch, klar weiß es das. Es reserviert eben den Platz für den Pointer. 
Worauf der später mal zeigen soll, weiß aber malloc nicht. Es wird also 
für deine Daten kein Speicher reserviert.

von Roki (Gast)


Lesenswert?

Bevor der Shitstorm los geht schreib ich etwas konstruktives.

Der Quelltext sollte zum einen so nicht kompiliert werden können, da 
"firstFct" nicht in der Funktion "addFunction" definiert ist.

Zum anderen allozierst du Speicher in dem du
1
firstFct = malloc(sizeof(struct function))
aufrufst. Also zum Verständnis du hast dir mal eine Pointer Variable
1
struct function *firstFct;
angelegt und weist ihr eine gewisse Menge an Speicher zu.

Das heißt du reservierst dir Speicher für den Inhalt deiner Struktur. 
Und da sind einmal ein Integer und ein Pointer auf ein Char drin.
Macht 4 Byte für den Integer und 8 Byte für die Adresse des Chars (es 
ist ja ein Pointer). Jetzt kannst du aber noch lang nicht in den Pointer 
des Chars einfach deine Funktionsnamen reinschreiben. Zuvor musst du, 
wie bereits für deine "firstFct", Speicher allozieren auf den dein Char 
Pointer verweist und in den Speicher kannst du rein schreiben.

also alloziere dir Speicher für deinen Char Pointer und schreib dann 
deine Namen rein.

Und nicht vergessen zum Schluss alles "von innen nach außen" frei zu 
geben. Also erst den Char Pointer, dann den Struktur Pointer.

von DirkB (Gast)


Lesenswert?

Hast du das
1
struct function *firstFct;
in einer .h oder in einer .c stehen?

von PittyJ (Gast)


Lesenswert?

>> in einer .h oder in einer .c stehen?

Da rätselt man wieder, weil es nur Code-Schnipsel, aber nichts richtig 
gibt.
Nach der Fehlermeldung würde ich mal .h tippen.

von lueis (Gast)


Lesenswert?

in einer .h datei. ist

ist das nicht egal, weil header als include in c einfach reinkopiert 
werden?

Ich möchte eine globale liste aus functions machen. Dabei ist firstFct 
immer der Beginn. ich habe das Element
1
 function *next;
 oben vergessen.

Roki schrieb:
> Der Quelltext sollte zum einen so nicht kompiliert werden können, da
> "firstFct" nicht in der Funktion "addFunction" definiert ist.

firstFct ist global, deswegen kann auch der int-Wert beschrieben werden
Soll ich also
1
 firstFct->functionName = malloc(sizeof(*functionName/*string aufgelöst?*/)))
Ich würde gerne die Größe

Wieso führt
1
 struct function *firstFct = NULL //führt zu Fehlermeldung "_firstFct bereits in .obj definiert" wieso?
 zu dieser Fehlermeldung?


Danke für die Lösungsansätze. Ich kann grade nicht, aber ich versuche 
später, ob ich damit weiterkomme!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

lueis schrieb:
> ist das nicht egal, weil header als include in c einfach reinkopiert
> werden?

Eben deswegen ist es nicht egal, weil header in jedes sie einbindende 
C-File einfach reinkopiert werden.

In einer Headerdatei definierte Objekte werden somit bei jedem 
Übersetzungsvorgang erneut angelegt - und sind somit als mehrfache Kopie 
vorhanden.

von Karl H. (kbuchegg)


Lesenswert?

Der andere Punkt

>
>
1
>  firstFct->functionName = malloc(sizeof(*functionName/*string aufgelöst? */))) 
2
>

Im Prinzip: ja.
Aber nicht mit sizeof.

Der String, den du hier bekommst
1
void addFunction(char *functionName) {
2
...

hat eine Länge. Und diese Länge kann man mit strlen() feststellen.
Aber Achtung!
strlen liefert dir die tatsächliche Länge des STrings.
die strlen("Test") wäre 4. Du brauchst aber eine Speicherfläche von 5 
Bytes Größe, da ja für das obligatorische abschliessende \0 Zeichen im 
String auch ein Byte reserviert werden muss.
1
...
2
   firstFct->functionName = malloc( strlen( functionName ) + 1 );
3
   strcpy( firstFct->functionName, functionName );
4
...


Hmm. Solltest du über die Phase des "Wie funktioniert 
String-Verarbeitung in C nicht schon längst hinaus sein, wenn du dich an 
dynamischen Datenstrukturen wie Listen etc. versuchst?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

PS:

Das hier
>
1
>   ....
2
>   if(firstFct == NULL) {
3
>     if((firstFct = malloc(sizeof(struct function))) == NULL) {
4
>   ....
5
>

willst du eigentlich gar nicht so machen.
Denn wenn du mal genauer überlegst, dann musst du ja auf jeden Fall 
einen Neuen Knoten für deine Liste anlegen. Unabhängig davon, ob das 
jetzt der erste Knoten der Liste ist oder ob es bereits eine Liste gibt, 
an die angehängt wird. Ein neuer Knoten muss auf jeden Fall erzeugt 
werden. Das einzige, was unterschiedlich ist, ist wo dieser neue Knoten 
eingehängt wird. In dem einen Fall kommt ein Verweis auf diesen neuen 
Knoten in firstFct rein, im anderen Fall muss zuerst das Ende der 
vorhandenen Liste aufgesucht werden und der neue Knoten wird in die 
Liste eingehängt, in dem ein entsprechender Verweis in das next Feld des 
letzten Listen-Knotens eingetragen wird.

Das sind aber 2 Paar verschiedene Schuhe. Und genau so wird man die auch 
sinnvollerweise behandeln: in 2 Schritten
1
void addFunction(char *functionName)
2
{
3
  struct function *newNode;
4
  struct function *loop;
5
6
   //
7
   // neuen Knoten erzeugen
8
   //
9
   newNode = malloc( sizeof( struct function ) );
10
   if( newNode == NULL ) {
11
     fprintf(stderr, "addFunction: Kein Speicherplatz vorhanden fuer neuen Knoten\n");
12
     return;
13
   }
14
15
   newNode->functionName = malloc( strlen( functionName ) + 1 );
16
   if( newNode->functionName == NULL ) {
17
     fprintf(stderr, "addFunction: Kein Speicherplatz vorhanden fuer Funktionsname\n");
18
     free( newNode );
19
     return;
20
   }
21
   strcpy( newNode->functionName, functionName );
22
   newNode->inter = 3;
23
   newNode->next = NULL;
24
25
  //
26
  // jetzt den neuen Knoten in die Liste einhängen
27
  //
28
  if( firstFct == NULL )           // leere Liste?
29
    firstFct = newNode;
30
31
  else {
32
    loop = firstFct;               // nicht leer, suche das letzte Element
33
    while( loop->next != NULL )
34
      loop = loop->next;
35
    loop->next = newNode;
36
  }
37
}

: Bearbeitet durch User
von lueis (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> lueis schrieb:
>> ist das nicht egal, weil header als include in c einfach reinkopiert
>> werden?
>
> Eben deswegen ist es nicht egal, weil header in jedes sie einbindende
> C-File einfach reinkopiert werden.
>
> In einer Headerdatei definierte Objekte werden somit bei jedem
> Übersetzungsvorgang erneut angelegt - und sind somit als mehrfache Kopie
> vorhanden.


Das wird mit präprozessoren in der h. dateiabgehandelt
1
#ifndef FRONT_H_DEF
2
...
3
struct{}
4
struct function *firstFct = NULL
5
...
6
  #define FRONT_H_DEF
7
...
8
#endif  // FRONT_H_DEF
So wie ich das verstanden habe,  führt das bei mehrmaligem includen 
dazu, dass nur einmal eingebunden wird

Danke, ich habe jetzt auch erst die struktur gebaut und dann angehängt

Karl Heinz Buchegger schrieb:
> Hmm. Solltest du über die Phase des "Wie funktioniert
> String-Verarbeitung in C nicht schon längst hinaus sein, wenn du dich an
> dynamischen Datenstrukturen wie Listen etc. versuchst?

Ich habe lange nciht mehr C programmiert und leider viel mit höheren 
Sprachen gemacht. Da kommt man leicht aus dem logischen Denken raus ;)

von dadada (Gast)


Lesenswert?

lueis schrieb:
> So wie ich das verstanden habe,  führt das bei mehrmaligem includen
> dazu, dass nur einmal eingebunden wird

Mehrmaliges includen in dieselbe Datei wird verhindert. Das hilft aber 
nicht bei dem angesprochenen Problem.

von DirkB (Gast)


Lesenswert?

Jede .c Datei ist eine eigene Übersetzungseinheit. Der Compiler kennt 
daher keine anderen Dateien ausser den Includes.

Darum steht also in jeder .c die deine .h einbindet eine 
Variablendefinition.
Diese Variable steht dann auch in in der enstsprechenden .obj

Jetzt kommt der Linker und findet in verschiedenen .obj Variablen mit 
dem selben Namen. Er kann jetzt annehmen dass es wirklich dieselbe 
Variable ist.
Dann darf eine Zuweisung aber nur einmal erfolgen.

Darum gehört Code der Speicher belegt nicht in eine .h

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.