# Linker Operand soll L-Wert sein/Strukturen



## Googlehupf (18. November 2011)

Hallihallo,

ich bekommen den Fehler: error C2106: '=': Linker Operand muss ein L-Wert sein(Zeile 51)

Ich weiß zwar was dieser Fehler bedeutet:
3=x --> macht keine Sinn, weil x in 3 speichern.. naja ^^ --> Linker Operand muss ein L-Wert sein.
x=3 --> macht sinn, da man x 3 zuweist, also 3 in x speichert.

Aber ich verstehe das bei mir nicht mein linker Operand ist ja eine Struktur und diesen will ich halt ein ausgelesenens Wort zuweisen.

Oder weise ich da überhaupt falsch zu?

Funktion des Programms: Es soll einfach die 1. Zeile auslesen(indem Fall 1 Wort) und dann in "vorname" speichern.

In adressen.txt stehen einfach Adressen z.b:
Franz
Müller
Hofburgstraße 13
Schuhgröße 37
Größe 175

und noch mehr Adressen...

Franz soll in vorname, Müller in Nachname usw. gespeichert werden und wenn die Schuhgröße unter 38 ist, dann soll es die gesamte Adresse auf dem Bildschirm ausgeben.

Das Programm ist noch nicht fertig, da ich den eine Fehler mal beheben will.


Programm:

```
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse adresse;
  int    schuhgroesse;
  float  groesse;
};

typedef struct personendaten_struct personendaten;



int main()
{
  FILE*fileio = NULL;

  char text[MAXSTRING];
  int x=0;
  personendaten theperson;


  fileio=fopen("adressen.txt","r");
  if(fileio == NULL)
  {
    printf("Fehler beim LESEN der Datei adressen.txt");
	exit(-1);
  }

  while(!feof(fileio))
  {
    fgets(text,MAXSTRING,fileio);
	x++;
    
	if(x == 1)
	{
	  theperson.adresse.vorname=text;
	}
  }

  fclose(fileio);

  return(0);
}
```

mfg Googlehupf


----------



## Matthias Reitinger (18. November 2011)

Hallo,

ein Array ist kein L-Wert. Um Arrays zu kopieren, musst du z.B. memcpy verwenden. In diesem Fall ist aber strcpy angebrachter, da du eine Zeichenkette kopieren willst.

Grüße,
Matthias


----------



## Googlehupf (18. November 2011)

Ich danke dir.
Hab das Programm jetzt geschrieben, aber ich bräuchte vielleicht paar Tipps, Hinweise bitte .

Die konkrete Aufgabenstellung ist:
Kurzbeschreibung : Programm zum Arbeiten mit Strukturen.
Schreiben Sie ein Programm  das die 
personendaten (typedef struct ......) von einer Textdatei einliest
und alle Personen und deren Adresse ausgibt die eine Schuhgrösse kleiner 38
haben.

In adressen.txt steht(die 5. Zeile ist die PLZ, die 6. die Schuhgröße und die 7. Zeile die Größe, also die zeilen jeweils bei den Adressen):

```
Lieselotte
Musterschülerin
Buseckerstrasse 44
Heppenheim
4443
38
172

Peter
Jackson
Mall street 10
USA
7860
45
189

Harry
Potter
Hogwarts 45
England
9234
35
178

Tom
Turbo
Turbohofgasse 1
Torbio
0001
22
156
```


So hab ichs versucht(in den comments steht warum das es maybe nicht funktioniert):

```
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse adresse;
  char   schuhgroesse[MAXSTRING];
  char  groesse[MAXSTRING];
};

typedef struct personendaten_struct personendaten;



int main()
{
  FILE*fileio = NULL;

  char text[MAXSTRING];
  int x=0;
  int i=0;
  personendaten theperson;


  fileio=fopen("adressen.txt","r");
  if(fileio == NULL)
  {
    printf("Fehler beim LESEN der Datei adressen.txt");
	exit(-1);
  }

  while(!feof(fileio))
  {
    fgets(text,MAXSTRING,fileio);
	x++;
    
	if(x == 1)
	{
	  strncpy(theperson.adresse.vorname,text,MAXSTRING);
	}

	if(x == 2)
	{
	  strncpy(theperson.adresse.nachname,text,MAXSTRING);
	}

	if(x == 3)
	{
	  strncpy(theperson.adresse.strasse,text,MAXSTRING);
	}

	if(x == 4)
	{
	  strncpy(theperson.adresse.ort,text,MAXSTRING);
	}

	if(x == 5)
	{
	  strncpy(theperson.adresse.PLZ,text,MAXSTRING);

	}

	if(x == 6)
	{
	  strncpy(theperson.schuhgroesse,text,MAXSTRING);
	  i=atoi(text);//wenn dann text="38" ist, dann ist ja i != 38, weils ja ungewandelt wird von string in int oder?
	  if(i < 38)
	  {
	    printf("%s",theperson.adresse.vorname);
		printf("%s",theperson.adresse.nachname);
		printf("%s",theperson.adresse.strasse);
		printf("%s",theperson.adresse.ort);
		printf("%s",theperson.adresse.PLZ);
		printf("%s",theperson.schuhgroesse);
	  }
	}

	if(x == 7)
	{
	  strncpy(theperson.groesse,text,MAXSTRING);
	  x=0;
	}
  }

  fclose(fileio);

  return(0);
}
```

Danke im voraus!


----------



## sheel (18. November 2011)

Hi

also zuerst einmal würde ich Schuhgröße etc. als int speichern.

In der Schliefe, statt eine Zeile einlesen und if 1 bis 7:
Warum nicht pro Schleifendurchgang alle 7 Zeilen einlesen?

Warum nur ggf. bei jeder 6. Zeile Personen je nach Schuhgröße ausgeben?
Wenn du, wie im oberen Absatz, alles in einem Schleifendurchgang einliest,
hast du das "Problem" nicht.

puts statt printf-%s nehmen. Ist nicht falsch, aber vergleichsweise langsam.

Und doch, atoi("38") ergibt die Zahl 38. Das ist der alleinige Sinn von atoi.

Was ist jetzt eigentlich die Frage gewesen?


----------



## Googlehupf (18. November 2011)

sheel hat gesagt.:


> In der Schliefe, statt eine Zeile einlesen und if 1 bis 7:
> Warum nicht pro Schleifendurchgang alle 7 Zeilen einlesen?


Mh... fgets liest doch nur bis zu einen \n. Befehle die weiter Zählen hätten wir noch nicht gelernt.
Wie könnt das den gehn(ohne einen neuen Befehl ^^)?



> Warum nur ggf. bei jeder 6. Zeile Personen je nach Schuhgröße ausgeben?


Naja, weil ja "text" nach der 7. Zeile wieder anderst ist... und ich die Schuhgröße steht ja in der 6. Zeile.



> Was ist jetzt eigentlich die Frage gewesen?


Eigentlich eh wie man das fehlerhafte Programm besser schreiben könnte.


----------



## deepthroat (18. November 2011)

Hi.

Hinzu kommt, das du überhaupt keine Eingaben auf Erfolg prüfst.  Du mußt doch sicherstellen, dass du einen Datensatz auch komplett eingelesen hast!

Warum liest du denn die Daten nicht gleich in die Struktur ein?

Bsp:

```
while (fgets(p.name, sizeof(p.name), datei) != NULL
     && fgets(p.vorname, sizeof(p.vorname), datei) != NULL
     && fgets(...) // ... usw.
{
}
```
Noch besser wäre es, du würdest dir eine Funktion zum Einlesen in die Struktur schreiben die du dann in der Schleife immer nur aufrufen mußt.

Gruß


----------



## saftmeister (19. November 2011)

Außerdem, warum verwendest du nicht statt fputs/fgets eher die Funktionen fread/fwrite? Damit könntest du die komplette Struktur schreiben und lesen und müsstest nicht an den Struktur-Elementen rum pfriemeln. Du verwendest ja nicht mal Pointer in deinen Strukturen, sollte also ohne Probleme funktionieren.

Beispiel:


```
if(fwrite(&theperson, sizeof(personendaten), 1, fp) != 1)
{
  perror(strerror(errno)); // Für errno brauchst du errno.h und für strerror string.h
}
```


----------



## Matthias Reitinger (19. November 2011)

saftmeister hat gesagt.:


> Außerdem, warum verwendest du nicht statt fputs/fgets eher die Funktionen fread/fwrite? Damit könntest du die komplette Struktur schreiben und lesen und müsstest nicht an den Struktur-Elementen rum pfriemeln. Du verwendest ja nicht mal Pointer in deinen Strukturen, sollte also ohne Probleme funktionieren.


Zumindest bis man den Compiler, dessen Einstellungen oder die Plattform wechselt. Compilern steht es nämlich frei, beliebig Füllbytes zwischen Membern einer Struktur einzufügen. Da kann es schnell zu Inkompatibilitäten kommen. Im allgemeinen ist das Schreiben oder Lesen von Strukturen mit einem Aufruf also nicht zu empfehlen, es sei denn man weiß genau, was man tut (z.B. wenn man die Füllbytes per Compilerdirektive deaktiviert hat).

Abgesehen davon wäre das Format dann nicht mehr menschenlesbar.

Grüße,
Matthias


----------



## saftmeister (19. November 2011)

Gut, was ist mit attribute packed? Dann wäre "nur" das Problem, das die Datentypen alle die gleichen Byte-Größen haben müssen, zu mindest wenn man den Compiler wechselt.


----------



## Matthias Reitinger (19. November 2011)

saftmeister hat gesagt.:


> Gut, was ist mit attribute packed? Dann wäre "nur" das Problem, das die Datentypen alle die gleichen Byte-Größen haben müssen, zu mindest wenn man den Compiler wechselt.


Wie gesagt: wenn man weiß was man tut, dann kann man das schon so machen. Einem Anfänger würde ich aber nicht dazu raten, zumindest nicht ohne diesen Fallstrick zu nennen.

Grüße,
Matthias


----------



## Googlehupf (26. November 2011)

deepthroat hat gesagt.:


> Hi.
> Warum liest du denn die Daten nicht gleich in die Struktur ein?
> 
> Bsp:
> ...



Mh ok danke, aber ich versteh nicht warum eine while() hier?

Und was bedeutet dann "sizeof(p.name), datei) != NULL"?

Gruß 

Googlehupf


----------



## sheel (26. November 2011)

```
fgets(p.name, sizeof(p.name), datei)
```
Liest einen String von datei in p.name rein, maximal aber sizeof(p.name) Byte.
Weil mehr passt ja nicht rein (sizeof ergibt in dem Fall die Byteanzahl).

Das "!=NULL" deswegen, weil fgets im Fehlerfall NULL liefert (Fehler ist zB auch das Dateiende).

Die while liest damit so lange ganze Personen ein, bis es nicht mehr geht bzw. die Datei aus ist.
In der Schleife hast du eine fertige Person, mit der du was machen kannst.
Im nächsten Schleifendurchgang die nächste Perosn usw.


----------



## vfl_freak (26. November 2011)

Moin,



Googlehupf hat gesagt.:


> ich versteh nicht warum eine while() hier?


weil *fgets* die Quelle *zeilenweise* einliest - vgl. hier :
http://pronix.linuxdelta.de/C/standard_C/c_programmierung_19_3.shtml



Googlehupf hat gesagt.:


> Und was bedeutet dann "sizeof(p.name), datei) != NULL"?


so ist das nicht zu lesen, sondern ob das Ergebnis von *fgets* ungleich null ist :

```
fgets( p.name, sizeof(p.name), datei ) != NULL
```
vgl. auch hier den obigen Link!

Gruß
Klaus


----------



## deepthroat (26. November 2011)

Googlehupf hat gesagt.:


> Mh ok danke, aber ich versteh nicht warum eine while() hier?


Weil du alle Datensätze verarbeiten willst.

Vermutlich hast du nicht verstanden, dass das die einzige Schleife ist. Der Schleifenblock würde aber nur ausgeführt werden wenn _alle_ Zeilen die zu einem Datensatz gehören eingelesen sind.

Wie gesagt, eine Funktion dafür wäre deutlich schöner:

```
int readRecord(FILE* f, personendaten* ppd) {
  return (fgets(ppd->name, sizeof(ppd->name), f) != NULL &&
     fgets(ppd->vorname, sizeof(ppd->vorname), f) != NULL &&
     ...;
}

... 

while (readRecord(datei, &p)) {
  ...
}
```
Gruß


----------



## Googlehupf (26. November 2011)

sheel hat gesagt.:


> ```
> fgets(p.name, sizeof(p.name), datei)
> ```
> Liest einen String von datei in p.name rein, maximal aber sizeof(p.name) Byte.
> Weil mehr passt ja nicht rein (sizeof ergibt in dem Fall die Byteanzahl).



Also, fgets ist so definiert: char * fgets ( char * str, int num, FILE * stream )

Da wo int num steht, steht sizeof(.....), aber warum kann man hier nicht die maximale größe des Strings hineinschreiben in unserem Fall?
Also: MAXSTRING ?



> Das "!=NULL" deswegen, weil fgets im Fehlerfall NULL liefert (Fehler ist zB auch das Dateiende).
> 
> Die while liest damit so lange ganze Personen ein, bis es nicht mehr geht bzw. die Datei aus ist.
> In der Schleife hast du eine fertige Person, mit der du was machen kannst.
> Im nächsten Schleifendurchgang die nächste Perosn usw.



Wenn man das !=NULL weglässt, dann müsste man theoretisch eine while(!feof(....)) schreiben oder?


----------



## sheel (26. November 2011)

Zu "fgets ist so definiert...": Ja.
Der Returnwert ist im Fehlerfall NULL, sonst kommt der Parameter str wieder zurück.

Zu MAXSTRING: Könnte man in dem Fall auch.

Zu feof: Ist eine andere Methode, um das Dateiende festzstellen.
Das NULL kommt aber nicht nur beim Dateiende, sondern auch bei anderen Fehlern,
falls welche auftreten.
Auch, wenn du mit feof auf das Dateiende prüfst,
müsstest du fgets noch immer auf Fehler abfragen.

Und wenn dir fgets auch gleich das Dateiende mitsignalisieren kann,
warum dann noch feof dazunehmen?
fgets allein reicht doch auch.

Gruß


----------



## saftmeister (26. November 2011)

Es ist immer besser, die Größe des Ziel-Buffers berechnen zu lassen, anstatt eine Definitions-Konstante zu verwenden. Wer gibt dir die Garantie, das es statt buffer[MAXSIZE] nicht irgendwann buffer[SIZE_MAX] heißt, wobei MAXSIZE dann 20 ist und SIZE_MAX nur 10. Lässt du die Größe des Buffers berechnen, ist es egal, mit welcher Größen-Konstante der Buffer angelegt wird. sizeof wird immer das richtige zurück geben.

Falls du dir wegen Performance Gedanken machst, kann ich dich beruhigen: die meisten Compiler werden das sizeof() weg optimieren und statt dessen dort einen konstanten Wert hin schreiben, wenn der Buffer mit einer konstanten Größe definiert ist.

Zum Thema NULL-Prüfung: Grundsätzlich ist das natürlich schon möglich, feof() auf den File-Pointer anzuwenden und ich würde das tatsächlich auch machen. Allerdings ist es dennoch nicht verkehrt, den Rückgabe-Pointer von fgets() zu prüfen. Lieber einmal mehr als einmal zu wenig geprüft.



sheel hat gesagt.:


> Und wenn dir fgets auch gleich das Dateiende mitsignalisieren kann,
> warum dann noch feof dazunehmen?
> fgets allein reicht doch auch.


 
Es mag genügen, um festzustellen, ob man abrechen sollte. Wenn man aber differenziert Fehler loggen will, genügt es eben nicht ;-)


----------



## deepthroat (26. November 2011)

saftmeister hat gesagt.:


> Falls du dir wegen Performance Gedanken machst, kann ich dich beruhigen: die meisten Compiler werden das sizeof() weg optimieren und statt dessen dort einen konstanten Wert hin schreiben, wenn der Buffer mit einer konstanten Größe definiert ist.


Es funktioniert ausschließlich mit statischen Arrays dessen Größe zur Kompilation feststeht. In C99 gibt es auch Array variabler Größe - dann steht aber die Größe sowieso erst zur Laufzeit fest...


saftmeister hat gesagt.:


> Zum Thema NULL-Prüfung: Grundsätzlich ist das natürlich schon möglich, feof() auf den File-Pointer anzuwenden und ich würde das tatsächlich auch machen.


Was ist mit ferror?


saftmeister hat gesagt.:


> Allerdings ist es dennoch nicht verkehrt, den Rückgabe-Pointer von fgets() zu prüfen. Lieber einmal mehr als einmal zu wenig geprüft.


Das kann dann aber ganz schnell falsch werden. Wenn fgets != NULL liefert, könnte ein feof danach schon "true" werden. Es ist also in der Regel Unfug doppelt zu prüfen.


saftmeister hat gesagt.:


> Es mag genügen, um festzustellen, ob man abrechen sollte. Wenn man aber differenziert Fehler loggen will, genügt es eben nicht ;-)


Dann kann man allerdings auch noch nach der Schleife prüfen.

Gruß


----------



## saftmeister (26. November 2011)

deepthroat hat gesagt.:


> Es funktioniert ausschließlich mit statischen Arrays dessen Größe zur Kompilation feststeht. In C99 gibt es auch Array variabler Größe - dann steht aber die Größe sowieso erst zur Laufzeit fest...



Deswegen schrieb ich auch die meisten Compiler. Ich kann ja nicht für alle das gleiche annehmen. Und C99 hatte ich auch im Hinterkopf, denn dort funktioniert sizeof() tatsächlich auch zur Laufzeit wenn ich mich richtig erinnere - obgleich ich das nicht verwende, denn schließlich muss mir zur Laufzeit die Puffergröße durch eine Variable bekannt sein.



deepthroat hat gesagt.:


> Was ist mit ferror?



Kannte ich bis dato nicht, danke für den Hinweis. Bislang verwende ich immer errno und strerror().



deepthroat hat gesagt.:


> Das kann dann aber ganz schnell falsch werden. Wenn fgets != NULL liefert, könnte ein feof danach schon "true" werden. Es ist also in der Regel Unfug doppelt zu prüfen.



So hab ich das noch nicht betrachtet. Guter Hinweis. Häufig fällt einem sowas erst auf, wenn man damit mal konfrontiert wurde.


----------



## Googlehupf (3. Dezember 2011)

Ich hab jetzt das ganze in ein Unterpgrogramm gepackt.

Aber nun tritt der Fehler beim "Starten ohne Debuggen" auf: The variable 'person' is being used without being initialized.

Also das "personendaten person" im main.

Könnt ihr mir bitte sagen was es da haben könnte?

Danke!

Gruß Googlehupf


```
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse adresse;
  char  schuhgroesse[MAXSTRING];
  char  groesse[MAXSTRING];
};

typedef struct personendaten_struct personendaten;

void search_print_Person(FILE* text, personendaten p);

void search_print_Person(FILE* text, personendaten p)
{
  int x=0;
  int i=0;
  char temp='x';

  while((fgets(p.adresse.vorname, sizeof(p.adresse.vorname), text) != NULL) && (fgets(p.adresse.nachname, sizeof(p.adresse.nachname), text) != NULL) && 
	  (fgets(p.adresse.strasse, sizeof(p.adresse.strasse), text) != NULL) && (fgets(p.adresse.ort, sizeof(p.adresse.ort), text) != NULL) && 
	  (fgets(p.adresse.PLZ, sizeof(p.adresse.PLZ), text) != NULL) && (fgets(p.schuhgroesse, sizeof(p.schuhgroesse), text) != NULL) && 
	  (fgets(p.groesse, sizeof(p.groesse), text) != NULL))
  {
    fscanf(text,"%c",&temp);
    i=atoi(p.schuhgroesse);

	if(i < 38)
	{
	  printf("%s",p.adresse.vorname);
	  printf("%s",p.adresse.nachname);
	  printf("%s",p.adresse.strasse);
	  printf("%s",p.adresse.ort);
	  printf("%s",p.adresse.PLZ);
	  printf("Schuhgroesse:%s",p.schuhgroesse);
	  printf("Groesse:%s",p.groesse);
	  printf("\n");
	}
  }
}

int main()
{
  FILE*text = NULL;

  personendaten person;

  text=fopen("adressen.txt","r");
  if(text == NULL)
  {
    printf("Fehler beim LESEN der text adressen.txt");
	exit(-1);
  }

  search_print_Person(text,person);
  fclose(text);

  retur
```


----------



## sheel (3. Dezember 2011)

Das ist nur eine Compilerwarnung, oder?
Oder wirklich ein Fehler?

Zu welcher Zeile wird das gezeigt?

Das tritt auf, weil du nichts in person gespeichert hast
und trotzdem schon an die Funktion übergibst.

Warum übergibst du das überhaupt,
wenn dich der Wert in der Funktion sowieso nicht interessiert?


----------



## Googlehupf (3. Dezember 2011)

Jup, das ist eine Compilerwarnung. Also wenn ich mit Einzelschritt F11(Visual C++ 2008) durchgehe dann kommt ein Fenster wo das steht mit "The variable 'person'..." in der Zeile 69. 

Entweder ich schreibe direkt im Unterprogramm "personendaten p;", oder ich mache es mit Pointern das müsste auch gehn oder, also z.B personendaten* person?


----------



## sheel (3. Dezember 2011)

Googlehupf hat gesagt.:


> Entweder ich schreibe direkt im Unterprogramm "personendaten p;"


Genau.

Da du ja keinen Wert vom main in die Funktion übertragen willst,
macht übergeben überhaupt keinen Sinn.
Egal ob mit Pointer oder ohne.


----------



## Googlehupf (9. Dezember 2011)

Wäre es eventuell nicht besser das man die Strukturen im Hauptprogramm ausgibt.

Unser Professor sagt immer das wir möglichst immer im Hauptprogramm ausgeben sollen, dass nur im Unterprogramm die Funktionen stehen.

Dadurch das in der Textdatei mehr wie eine Adresse mit Schuhgröße kleiner 38 vorkommen, kann kann ich das schonmal mit "return"(struktur ins hauptprogramm übergeben) vergessen, da man ja nur eine Zahl bzw. eine Adresse übergeben kann...

1. Möglichkeit: Ginge das, wenn ich eine Adresse mit einer Schuhgröße kleiner 38 finde, dass ich dann danach gleich die Struktur mit einem return-Befehls ins Hauptprogramm übergebe, aber wie komme ich dann ins Unterprogramm wieder zurück?

Hat jemand vielleicht ein paar Tipps oder so?


Anderes Problem:
Ich habe das ganze nun versucht mit Pointer zu schreiben, aber wenn ich "Starten ohne Debugging klicke" STRG+F5, dann kommt das "schwarze Fenster(wo ausgegeben wird)" und danach ein Weiteres Windows-Fenster worin steht: 

"name des programms".exe funktioniert nicht mehr.
Das Programm wird aufgrund eines Problems nicht richtig ausgeführt. Das Programm wird geschlossen und Sie werden benachrichtigt, wenn eine Lösung verfügbar ist.

Hier das Bsp:

```
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse *adresse;
  char  schuhgroesse[MAXSTRING];
  char  groesse[MAXSTRING];
};

typedef struct personendaten_struct personendaten;

void search_print_Person(FILE* text);

void search_print_Person(FILE* text)
{
  int x=0;
  int i=0;
  char temp='x';
  personendaten *p=NULL;

  while(!feof(text))
  {	
	fgets(p->adresse->vorname, sizeof(p->adresse->vorname), text);
	fgets(p->adresse->nachname, sizeof(p->adresse->nachname), text);
	fgets(p->adresse->strasse, sizeof(p->adresse->strasse), text);
	fgets(p->adresse->ort, sizeof(p->adresse->ort), text);
	fgets(p->adresse->PLZ, sizeof(p->adresse->PLZ), text);
	fgets(p->schuhgroesse, sizeof(p->schuhgroesse), text);
	fgets(p->groesse, sizeof(p->groesse), text);
  
    fscanf(text,"%c",&temp);
    i=atoi(p->schuhgroesse);

	if(i < 38)
	{
	  printf("%s",p->adresse->vorname);
	  printf("%s",p->adresse->nachname);
	  printf("%s",p->adresse->strasse);
	  printf("%s",p->adresse->ort);
	  printf("%s",p->adresse->PLZ);
	  printf("Schuhgroesse:%s",p->schuhgroesse);
	  printf("Groesse:%s",p->groesse);
	  printf("\n");
	}
  }
}

int main()
{
  FILE*text = NULL;

  text=fopen("adressen.txt","r");
  if(text == NULL)
  {
    printf("Fehler beim LESEN der text adressen.txt");
	exit(-1);
  }

  search_print_Person(text);
  fclose(text);

  return(0);
}
```


----------



## sheel (9. Dezember 2011)

Erstes Problem: Du kommst gar nicht mehr ins Unterprogramm zurück.
Entweder du teilst es in zwei Up.s auf, oder machst einen Parameter, dem du 1 oder 2 übergibst, welche Hälfte ausgeführt werden soll (innen dann mit if), oder...

Der Grund, dass man Eingaben/Ausgaben etc. möglichst zentral halten soll (und nicht über alle Klassen verstreuen soll): Wenn man dasProgramm von der Konsole zu einer grafsichen GUI umscheribt (oder umgekehrt, oder...),
ist es einfach weniger Aufwand, wenn die Eingaben/Ausgaben nicht verstreut sind.

Gruß


----------



## Googlehupf (11. Dezember 2011)

Danke, aber wo ist der Fehler mit den Pointern, oben habe ich das Programm gepostet und das Problem auch dazu geschrieben.

Kann bitte jemand wer drüber schaun ?


----------



## sheel (11. Dezember 2011)

Schau mal mit dem Debugger, in welcher Zeile das passiert.


----------



## Googlehupf (11. Dezember 2011)

Zeile 37, also beim 1. fgets.


----------



## Muepe32 (11. Dezember 2011)

Das Problem ist hier:

```
personendaten* p = NULL;
```

Dieses p verwendest du nacher, es zeigt aber auf den Nullzeiger.


----------



## Googlehupf (11. Dezember 2011)

Ok, danke, aber wenn ich es weglasse dann kommt diese Meldung: The variable 'p' is being used without being initialized.


----------



## Muepe32 (11. Dezember 2011)

Ja, du musst p mit gültigem Speicher initialisieren. Ich sehe aber gerade nicht, warum p ein Zeiger sein muss, du kannst ja auch einfach ein Objekt von personendaten sein lassen.


----------



## Googlehupf (11. Dezember 2011)

Naja p muss ja ein Zeiger sein, da ich später mit ihm auf die Struktur zeige und reinlese mit fgets oder?


----------



## Muepe32 (11. Dezember 2011)

Wo willst du als Zeiger auf die Struktur zugreifen? In deinem geposteten Code sieht man davon nichts.


----------



## Googlehupf (11. Dezember 2011)

Hier der code nochmal:

```
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse *adresse;
  char  schuhgroesse[MAXSTRING];
  char  groesse[MAXSTRING];
};

typedef struct personendaten_struct personendaten;

void search_print_Person(FILE* text);

void search_print_Person(FILE* text)
{
  int x=0;
  int i=0;
  char temp='x';
  personendaten *p;

  while(!feof(text))
  {	
	fgets(p->adresse->vorname, sizeof(p->adresse->vorname), text); // hier zeige ich auf die struktu?
	fgets(p->adresse->nachname, sizeof(p->adresse->nachname), text);
	fgets(p->adresse->strasse, sizeof(p->adresse->strasse), text);
	fgets(p->adresse->ort, sizeof(p->adresse->ort), text);
	fgets(p->adresse->PLZ, sizeof(p->adresse->PLZ), text);
	fgets(p->schuhgroesse, sizeof(p->schuhgroesse), text);
	fgets(p->groesse, sizeof(p->groesse), text);
  
    fscanf(text,"%c",&temp);
    i=atoi(p->schuhgroesse);

	if(i < 38)
	{
	  printf("%s",p->adresse->vorname);
	  printf("%s",p->adresse->nachname);
	  printf("%s",p->adresse->strasse);
	  printf("%s",p->adresse->ort);
	  printf("%s",p->adresse->PLZ);
	  printf("Schuhgroesse:%s",p->schuhgroesse);
	  printf("Groesse:%s",p->groesse);
	  printf("\n");
	}
  }
}

int main()
{
  FILE*text = NULL;

  text=fopen("adressen.txt","r");
  if(text == NULL)
  {
    printf("Fehler beim LESEN der text adressen.txt");
	exit(-1);
  }

  search_print_Person(text);
  fclose(text);

  return(0);
}
```


----------



## Muepe32 (11. Dezember 2011)

Der Code ist mir durchaus bekannt, jetzt musst du mir sagen wo es zwingend nötig ist, dass es sich bei p um einen Zeiger handelt auf ein personendaten-Objekt und nicht um ein personendaten-Objekt selber.


----------



## Googlehupf (11. Dezember 2011)

p->adresse Zeile 37

p zeigt auf adresse?^^

Wenn ich den * weglasse, dann muss ich statt -> einen . machen. Ich will aber -> machen.


----------



## saftmeister (11. Dezember 2011)

p ist ein Zeiger. Der zeigt erst mal irgendwo hin im Speicher. Bei dir ist er noch nicht mal initialisiert und es wurde auch kein Speicher alloziert. Das heißt der Zeiger ist eigentlich erstmal ungültig, an den Speicher etwas hin zu schreiben, wo der Zeiger hinzeigt, ist gefährlich.

Du müsstest erstmal Speicher vom OS anfordern, in die Anfangsdresse des Speichers dem Zeiger übergeben. Da du eine Struktur ablegen willst, ist es sinnvoll, soviel Speicher anzufordern, wie die Struktur benötigt. Das macht man so:


```
// Expliziter Pointer-Cast weil malloc() einen void* zurück gibt
personendaten p = (personendaten*)malloc( sizeof( personendaten ) );
```

Damit hast du Speicher alloziert, den du nach der Benutzung wieder ans OS zurückgeben musst:


```
free( p );
```

Sonst hast du ein Speicherleck (Memory-Leak) programmiert.

Einfach einen Zeiger zu deklarieren und dann wild Daten reinschreiben bringt dein Programm oder sogar andere Prozesse zum Abstürzen.

Die Frage ist aber: Warum willst du dort unbedingt mit einem Zeiger arbeiten?


----------



## Googlehupf (11. Dezember 2011)

```
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse *adresse;
  char  schuhgroesse[MAXSTRING];
  char  groesse[MAXSTRING];
};

typedef struct personendaten_struct personendaten;

void search_print_Person(FILE* text);

void search_print_Person(FILE* text)
{
  int x=0;
  int i=0;
  char temp='x';
  personendaten *p;

  personendaten p = (personendaten*)malloc( sizeof( personendaten ) );

  while(!feof(text))
  {	
	fgets(p->adresse->vorname, sizeof(p->adresse->vorname), text);
	fgets(p->adresse->nachname, sizeof(p->adresse->nachname), text);
	fgets(p->adresse->strasse, sizeof(p->adresse->strasse), text);
	fgets(p->adresse->ort, sizeof(p->adresse->ort), text);
	fgets(p->adresse->PLZ, sizeof(p->adresse->PLZ), text);
	fgets(p->schuhgroesse, sizeof(p->schuhgroesse), text);
	fgets(p->groesse, sizeof(p->groesse), text);
  
    fscanf(text,"%c",&temp);
    i=atoi(p->schuhgroesse);

	if(i < 38)
	{
	  printf("%s",p->adresse->vorname);
	  printf("%s",p->adresse->nachname);
	  printf("%s",p->adresse->strasse);
	  printf("%s",p->adresse->ort);
	  printf("%s",p->adresse->PLZ);
	  printf("Schuhgroesse:%s",p->schuhgroesse);
	  printf("Groesse:%s",p->groesse);
	  printf("\n");
	}
  }

  free( p );
}

int main()
{
  FILE*text = NULL;

  text=fopen("adressen.txt","r");
  if(text == NULL)
  {
    printf("Fehler beim LESEN der text adressen.txt");
	exit(-1);
  }

  search_print_Person(text);
  fclose(text);

  return(0);
}
```

Muss ich das so machen, weil  in der  Fehlerliste steht dann das sich p(zeile 35) von *p(zeiler 33 )unterscheidet.

Zu deiner Frage: Einfach so als Übung.


----------



## Googlehupf (11. Dezember 2011)

Ich hab aber noch ein anderes Problem... nun habe ich es ohne pointer wieder gemacht, weil für mich leicht ist.

Mit header-file und so:

h-file:

```
#ifndef _struct4_h_
#define _struct4_h_ 1

#define MAXSTRING 100

struct adresse
{
  char  vorname[MAXSTRING];
  char  nachname[MAXSTRING];
  char  strasse [MAXSTRING];
  char  ort[MAXSTRING];
  char  PLZ[MAXSTRING];
};

struct personendaten_struct
{
  struct adresse adresse;
  char  schuhgroesse[MAXSTRING];
  char  groesse[MAXSTRING];
};

typedef struct personendaten_struct personendaten;

void search_print_Person(FILE* text);//Fehler	3	error C2143: Syntaxfehler: Es fehlt '{' vor '*' / Fehler	2	error C2143: Syntaxfehler: Es fehlt ')' vor '*' / Fehler	4	error C2059: Syntaxfehler: ')'



#endif
```

1. c-file:


```
#include "strukturen_a4.h"
#include <stdio.h>


void search_print_Person(FILE* text)
{
  int x=0;
  int i=0;
  char temp='x';
  personendaten p;

  while(!feof(text))
  {	
	fgets(p.adresse.vorname, sizeof(p.adresse.vorname), text);
	fgets(p.adresse.nachname, sizeof(p.adresse.nachname), text);
	fgets(p.adresse.strasse, sizeof(p.adresse.strasse), text);
	fgets(p.adresse.ort, sizeof(p.adresse.ort), text);
	fgets(p.adresse.PLZ, sizeof(p.adresse.PLZ), text);
	fgets(p.schuhgroesse, sizeof(p.schuhgroesse), text);
	fgets(p.groesse, sizeof(p.groesse), text);
  
    fscanf(text,"%c",&temp);
    i=atoi(p.schuhgroesse);

	if(i < 38)
	{
	  printf("%s",p.adresse.vorname);
	  printf("%s",p.adresse.nachname);
	  printf("%s",p.adresse.strasse);
	  printf("%s",p.adresse.ort);
	  printf("%s",p.adresse.PLZ);
	  printf("Schuhgroesse:%s",p.schuhgroesse);
	  printf("Groesse:%s",p.groesse);
	  printf("\n");
	}
  }
}
```

2. C-file

```
#include "strukturen_a4.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>



int main()
{
  FILE*text = NULL;

  text=fopen("adressen.txt","r");
  if(text == NULL)
  {
    printf("Fehler beim LESEN der text adressen.txt");
	exit(-1);
  }

  search_print_Person(text);

  fclose(text);

  return(0);
}
```

Den Fehler hab ich kommentiert im Header-File. Ich hab lange gesucht, aber nichts gefunden was es da haben könnte.


----------



## Muepe32 (11. Dezember 2011)

Das ist durchaus so, du hast jetzt nämlich beide Varianten gemischt. Du hast mit malloc Speicher zum draufzeigen alloziert und, p dann aber jetzt nicht mehr als Zeiger verwendet. Für eines von beidem solltest du dich entscheiden. Entweder Zeiger mit malloc oder ohne Zeiger ohne Allokation.

/Edit:
Zum Doppelpost:
FILE wird nicht erkannt, wenn du den Header vor stdio einbindest.


----------



## Googlehupf (11. Dezember 2011)

Ok, danke jetzt hab ich den header nach stdio geschrieben aber es kommen diese Fehler:
Fehler	2	fatal error LNK1120: 1 nicht aufgelöste externe Verweise.
Fehler	1	error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_main" in Funktion "___tmainCRTStartup".	MSVCRTD.lib

Zeile steht nicht dabei wo passiert.


----------



## Muepe32 (11. Dezember 2011)

Du hast keine Main-Funktion, bzw die Datei mit der main-Funktion wird nicht mit kompiliert.


----------



## Googlehupf (11. Dezember 2011)

EDIT: Ok, ich hab vergessen die .c-files und .h-files ins Projekt "hinzuzufügen" unter Projekt-Explorer etc.

Auf jedenfall funktionierts danke^^!


----------



## saftmeister (11. Dezember 2011)

Du solltest das Header-File stdio.h auch in das Header-File für deine Strukturen-Definition includieren.

Also noch mal als Erklärung die Sache mit den Pointern:

Wenn du eine definierte Struktur personendaten hast, kannst du ein Objekt auf zweierlei Arten dafür erstellen.

Variante 1 - Objekt-Variable auf den Stack


```
personendaten p;
```

Damit sorgst du dafür, das bereits beim Starten deines Programms Speicher für das Objekt auf dem Stack reserviert wird. Du musst dich nicht darum kümmern, dass der Speicher dafür wieder aufgeräumt wird. Sobald der Scope (der Bereich in dem die Objekt-Variable definiert wurde) verlassen wird, ist die Variable nicht mehr gültig. Beim Verlassen des Programms wird der Speicher dafür implizit freigegeben.

Diese Variante ist für Anfänger die einfachere, da man sich eben nicht um die Speicherverwaltung kümmern muss. Es wird aber eines Tages ein Anwendungsfall kommen, wo du mit dieser Variante alleine nicht mehr weiter kommst. Beispiel: Du musst eine Objekt-Variable erstellen, die größer als der Stack ist, der normalerweise für deinen Compiler und dein Betriebssystem definiert ist.

Zugriff auf Elemente der Struktur:


```
// Da es sich nicht um einen Zeiger handelt, darfst du auch nicht den Referenz-Operator verwenden:

strncpy(p.name, "Hans", sizeof(p.name)-1); // Sicherheitshalber mal die Länge beschränken
```

Variante 2 - Objekt-Variable auf den Heap


```
personendaten *p;
```

Hier wird lediglich ein Zeiger erstellen. Dieser Zeiger zeigt auf irgendeine Stelle im Speicher. Besser wäre es hier schon mal, den Zeiger mit NULL zu initialisieren, da der Zeiger einen undefinierten Zustand hat.

Möchtest du einen Zeiger tatsächlich als Datenspeicher verwenden, musst du dafür Speicher anfordern. Es gibt Funktionen, die das von sich aus erledigen (z.B. strdup()). was du auf jeden Fall dann machen musst, ist den Speicher wieder freigeben, sobald er nicht mehr benötigt wird. Wie das geht, habe ich weiter oben schon gezeigt.

Zugriff auf die Elemente der Struktur über den Zeiger:


```
// Da es sich um einen Zeiger handelt, musst du auch den Referenz-Operator verwenden:

strncpy(p->name, "Hans", sizeof(p.name)-1); // Sicherheitshalber mal die Länge beschränken
```


Fazit:

Das sind absolute C-Grundlagen, du solltest den Unterschied erkennen und verstehen. Mein Gefühl sagt mir, das du Zeiger noch nicht verstanden hast.


----------



## Googlehupf (16. Dezember 2011)

Danke!

Aber eins is mir noch nicht klar...:
*
Saftmeister schrieb:*


> ```
> // Expliziter Pointer-Cast weil malloc() einen void* zurück gibt
> personendaten p = (personendaten*)malloc( sizeof( personendaten ) )
> ```



Was macht jetzt das (personendaten*) vor malloc genau? Warum?

Hier ein kurzer Programm-Ausschnitt:

```
complex* c_read_file(char filename[], int* len)
{
  FILE *inFile=NULL;
  complex *arrayValues=NULL;
  complex *actVal = NULL;
  int n=0;
  
  inFile=fopen(filename,"r");
  if (inFile != NULL) 
  {
    arrayValues=(double *)malloc(sizeof(complex)* *len);//* 
    if (arrayValues != NULL)
    {
      actVal=arrayValues;
      for(n=0; n<*len; n++)
      {
				fscanf(inFile,"%lf,%lf",&actVal->real,&actVal->imag);
				actVal++;
      }
      fclose(inFile);
    }
    else
    {
      printf("Memory allocation failure for Data of File %s !\n",filename);
    }
  }
  else
  {
    printf("File %s could not be opened!\n",filename);
  }
	return(arrayValues);
}
```

*hier dieser double-cast beim malloc - Warum? Und sizeof(complex) ermittelt halt die Bytes... in dem Fall steht in der Sturktur complex double real und double imag --> also 16 Bytes? Dadurch das arrayValues ein Pointer auf complex ist der Stern *? ja und len ist die Länge(also die Zeilen-Anzahl) des text-files. Es steht in jeder Zeile eine double-Zahl.

Gruß


----------



## sheel (16. Dezember 2011)

malloc bekommt, wie du ja weißt, nur die Byteanzahl, die es besorgen soll.
Wenn das 16 ist, können das zB. 16 chars (je 1 Byte), oder 2 doubles (je 8 Byte) sein.
Und weil malloc nicht weiß, welche Variablenart das wird (und sich dafür auch überhaupt nicht interessiert), liefert es nur die Adresse. Kein char* oder double*, sondern einheitlich
(void*: Adresse von unbestimmter Variablenart).

Wenn man dieses void* dann einem double* oÄ. zuweist, kann (nur kann) das
je nach Compiler eine Warnung bringen. Das Programm funktioniert trotzdem,
aber die Warnung ist lästig. Deswegen der Cast, um die zu verhindern.


----------



## Googlehupf (16. Dezember 2011)

Danke dir.


```
arrayValues=(double *)malloc(sizeof(complex)* *len);
```

EDIT:
Das ist verwirrend... der Stern ist erst nach der ) und beim len ist der stern eh normal vorm len.
Was macht der Stern den nach ')'?


----------



## sheel (16. Dezember 2011)

Stimmt.
Je nach Compiler können es auch mal mehr als 16 Byte sein,
aber das hat auf den Code keine Auswirkungen.
Kein Grund zum Sorgenmachen,

edit: Der erste Stern ist das math. Multiplizieren,
der zweite wegen dem Pointer, um nicht die Adresse, sondern den Wert selbst zu bekommen.


----------



## saftmeister (16. Dezember 2011)

Expliziter Cast bedeutet, das wir dem Compiler mitteilen, das wir ihn zwingen, dort einen bestimmten Typen zu verwenden.

Ein Void-Pointer ist für den Compiler etwas anderes als ein Pointer auf eine Struktur. Da du als L-Wert einen Pointer auf eine Struktur hast, als R-Wert von malloc() aber ein Void-Pointer zurück kommt, zwingen wir (casten) zum Datentypen Pointer auf Struktur.

Prinzipiell ist es bei einem Void-Pointer egal, ob man ihn explizit castet oder nicht. Der Compiler wird sich darum kümmern, dass dies implizit (also ohne Zwang durch den Programmierer) geschieht. Es ist aber sauberer, und wenn man nach ISO-89 compiliert (wenn ich mich richtig erinnere) wird der Code dadurch auch besser zu verstehen, denn:

In ISO-89 (man vergebe mir bitte, wenn ich das falsch in Erinnerung habe) müssen die Variablen vor dem eigentlichen Programm-Code definiert werden. Das sieht das bspw. so aus, wie du es in deinem letzten Post gemacht hast. Erst kommen die Variablen, dann der logische Code. Wenn man eine Latte von Variablen definiert hat, und anschließend ein paar Zeilen Code kommen, und später erst die Speicher-Allokation, dann muss man immer im Sourcecode nach oben zur Variablen-Definition scrollen, um zu prüfen, auf welchen Typ denn nun der Pointer eigentlich zeigt.

Solltest du keinen expliziten Cast durchführen, bekommst du bim Compilen eine Warnung.

Hier habe ich noch mal eine Seite raus gesucht, in der die Einzelheiten erklärt werden: http://www.willemer.de/informatik/cpp/pointer.htm


----------

