C Frage zum FILE Pointer und fgetc()

Majek

Cadet 4th Year
Registriert
Feb. 2005
Beiträge
88
Hallo, versuche seit ein paar Tage mir C-Grundlagen mit Hilfe eines Buches anzueignen.
Leider verstehe ich aber nicht was genau bei folgendem Code passiert:

int ch;
FILE *zeiger;
while(!feof(zeiger)) {
putchar(ch);
//printf("\n%i\n", *zeiger);
ch=fgetc(zeiger);
}

Ist der Pointer richtig initialisiert wird der gesamte Inhalt der Datei ausgedruckt.
Putchar druckt ja nur ein Zeichen aus, also muss sich der Wert des Pointers ständig
erhöhen, durch die auskommentierte Zeile habe ich das auch überprüft und der Wert
wird tatsächlich immer um ein Byte erhöht. Aber wie geschieht das? Bin verwirrt.:(
 
Hi,

du hast z.B: vergessen die Datei zu öffnen.

FILE *zeiger;

zeiger = fopen( "Datei.bla", "r" );

while( !feof( zeiger ) )
{
putchar( fgetc( zeiger ) );
}
 
Ja, ich weiss sry. Das fehlte jetzt in dem Code-Ausschnitt. Die Datei wird bei mir ja auch fehlerfrei geprintet. Es geht mir darum zu verstehen wie wann und wo der Pointer verändert wird.
 
Nene: der zeiger bleibt wo/wie er ist ( der zeigt immer nur auf die Datei ).
Es wird intern ein ponter verschoben den kannst mittels fseek( ... ) plazieren wo du willst.
Hab vergessen wie sich das teil nennt goolge einfach nach "fseek"

Hier wird das erklärt

ps: das buch ist sehr gut und free.
 
Zuletzt bearbeitet:
Mit fopen() besorgst du dir ja dein FILE Pointer.
FILE ist eine Struktur, welche alle Informationen vorhält, die du brauchst.
D.h. alles um den Strom/Stream, welcher in FILE gespeichert ist, zu kontrollieren + den Buffer.

Der Buffer ist mit einem Pad von X in FILE zu erreichen.

Der Pointer zeigt auf den Buffer, welcher (sagen wir mal bei FF01) irgendwo anfängt.
Unser String ist "Welt".

In fgetc() wird dabei der Pointer verändert.

FF01 ist das erste Zeichen, also 'W'. Nun nutzen wir fgetc() um das nächste Zeichen zu bekommen -> der Pointer wird +1 genommen.
FF02 ist das zweite Zeichen, also 'e'. Usw..

fgetc() springt also im Buffer immer eine "Zelle" weiter.
 
und gibt wenn es schon dabei ist das zeichen( in welcher Form auch immer ) zurück ;)
 
Da verstehst du etwas falsch. Der Zeiger wird nicht erhöht. Der Zeiger zeigt auf eine Struktur. Die Struktur heißt FILE. Wie diese Struktur aufgebaut ist, kannst du dir in der entsprechenden include Datei anschauen. Der genaue Aufbau ist systemabhängig. Was du beim printf ausgibst, ist auch nicht der Zeiger, sondern der Wert eines int, auf den der Zeiger zeigt. Es ist so zu sagen der Inhalt der ersten vier Bytes der FILE Struktur bei einem 32 Bit Compiler. Wie die ersten vier Bytes deiner FILE Struktur aber zu interpretieren sind, findest du in der Include Datei, in der die Struktur FILE definiert ist.

In der Struktur FILE sind Verwaltungsinformationen enthalten, die darüber Buch führen, wo sich der "Leser" gerade befindet (wird durch fgetc aktualisiert).

(Ups, ich muss schneller tippen)
 
r0b0t, nicht ganz richtig.
fgetc gibt zwar 4 bytes zurück, ließt aber nur 1 Byte aus dem Buffer. ;)
Ansonsten würde das System nicht klappen, den nach jeder fgetc() wird der Zeiger um +1 erhöht, so müsste er entweder 3mal garnicht und dann +4 erhöht werden, oder das System dahinter wäre komplexer.

Zumindest in der MinGW implementation sind's 1 Byte Schritte.^^
 
oldsqldma, das kann ich jetzt so nicht stehen lassen. Der erste Absatz meiner Antwort bezog sich auf das printf statement. Und dieses gibt eben nicht "den Zeiger" zeiger, sondern den Wert auf den der Zeiger zeiger zeigt, aus. Das hat jetzt zunächst überhaupt nichts mit fgetc zu tun.

//printf("\n%i\n", *zeiger);

Wenn FILE wie folgt definiert ist, wird dadurch _ptr ausgegeben.

struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;

Vorausgesetzt man weiß was man tut, funktioniert dies mehr oder weniger zufällig, um sich den "file position indicator" anzusehen, da das erste Element der FILE Struktur halt zufällig dieser Positionsindikator ist. Das muss aber nicht auf jedem System so sein. Ich möchte mal bei einem Anfänger stark bezweifeln, das er das genauso vorhatte. Besser wäre schon:

//printf("\n%i\n", zeiger->_ptr);

Aber der direkte Zugriff auf interne Datenstrukturen ist schlechter Programmierstil und behindert Wartung und Portierungen auf andere Systeme. Das sollte man als Anfänger vermeiden. Ich gebe aber zu, zum Lernen und Verstehen kann das Anschauen von internen Strukturen sehr nützlich sein.

Zu fgetc: Wieviele Bytes fgetc liest oder zurückgibt habe ich gar nicht erwähnt.

In Majeks Programm war auch noch die Reihenfolge falsch. Zeichen ch wurde erst ausgegeben und dann eingelesen. Ich hoffe Majek ist jetzt nicht völlig verwirrt.
 
Zuletzt bearbeitet:
Nunja, ich dachte die 4 Bytes bezogen sich auf die Auslese von fgetc, so ließt sich das nämlich. ;)
Ich h ab es so interpretiert: "Die Ausgabe von printf ist der 4 Byte Wert des Zeigers".
Das ist nämlich falsch, den den Wert des Zeigers bekommst du durch fgetc() (auch wenn hier unnötig, ein %c, (*file_ptr)++ würde auch genügen).

Hier nochmal der verwirrende Orginal Satz von dir: "Was du beim printf ausgibst, ist auch nicht der Zeiger, sondern der Wert eines int, auf den der Zeiger zeigt."
Besser würde es wohl heißen. "Was du mit printf ausgibst ist nicht der Zeiger, sondern ein Integer, welchen fgetc - Welches einen char Wert aus der FILE Struktur ließt und den Zeiger erhöht - wiedergibt."

War wohl eine Fehlinterpretation von mir.
 
Besser würde es wohl heißen. "Was du mit printf ausgibst ist nicht der Zeiger, sondern ein Integer, welchen fgetc - Welches einen char Wert aus der FILE Struktur ließt und den Zeiger erhöht - wiedergibt."

Also Dein Satz verwirrt mich mehr als meiner ;)
 
Also schon mal vielen Dank für die Antworten. Ich arbeite das Buch "C:Programmieren von Anfang an" durch, und da wird das Programm einfach gezeigt und nicht genau erklärt was bei der While-Schleife passiert. Und vor der schleife fehlt eine Zeile, hab das irgendwie sehr umständlich rüberkopiert...

zeiger=fopen(eingabe, "r");
ch=fgetc(zeiger);
while(!feof(zeiger)) {
putchar(ch);
printf("\n%i\n", zeiger);
ch=fgetc(zeiger);


Genau habe ich es noch nicht verstanden, werde mir aber den Link durchlesen. Zumindest habe ich bemerkt, dass wenn ich ", zeiger);" und nicht ", *zeiger);" ausführe, der Wert des Pointers tatsächlich immer gleich bleibt. Ich habe bis jetzt halt versucht alles genaustens zu verstehen und da war halt eine kleine Lücke. Mit der Zeit werde ich wohl auch dahinter kommen. Danke. :)
 
Hallo, habe heute schon wieder eine Frage und wollte nicht direkt ein neues Thema eröffnen.
Es ist wie folgt:
Ich möchte ein Array vom Typ "struct irgendetwas" initialisieren und dann einen Pointer haben welcher auf das Array zeigt, dann aber durch [] auf eine einzelne Struktur zugreifen kann, das ganze soll dann noch an Funktionen übergeben werden. Konkret poste ich auch mal meinen Code, ist im Grunde eine Aufgabe aus dem oben genannten Buch welche ich etwas ausbauen möchte.

#include <stdio.h>
#include <string.h>
#define TITEL_LAENGE 80
#define DATENBANK_LAENGE 2

struct buch {
int Inv_Nr;
char Titel[TITEL_LAENGE];
float Preis;
float MwSt;
int Anzahl;​
};
typedef struct buch BUCH;

void Eingabe_MwSt(BUCH *);
void Eingabe_Gesamt(BUCH *);
float Verk_Preis(BUCH *);

BUCH Datenbank[DATENBANK_LAENGE];

int main(int argc, char *argv[]) {
float Ges_Preis=0;
Eingabe_MwSt(&Datenbank[0]);
Eingabe_Gesamt(&Datenbank[0]);
int i;
printf("\n-----------------------\nDarstellung der Eintraege:\n");

for(i=0; i<DATENBANK_LAENGE; i++) {
printf("%3.i. MwSt: %.2f, Titel:\"%s\"\n\t-kostet %.2f Euro\n\t-es sind %i Exemplare vorhanden\n\n"
,i+1, Datenbank.MwSt, Datenbank.Titel, Verk_Preis(&Datenbank), Datenbank.Anzahl);
Ges_Preis+=(Verk_Preis(&Datenbank))*(Datenbank).Anzahl;
}
printf("Insgesamt hat das Lager einen Wert von: %.2f Euro.", Ges_Preis);
return 0;

}


void Eingabe_MwSt(BUCH *buch_ptr) {
int i;
float MwSt_f;
printf("\nBitten Mehrwertsteuer eingeben:\n");
scanf("%f", &MwSt_f);
for(i=0; i<DATENBANK_LAENGE; i++) {
(*buch_ptr).MwSt=MwSt_f;
buch_ptr++;
fflush(stdin);
}​
};


void Eingabe_Gesamt(BUCH *buecherei_struct) {
int i;
char Titel_f[TITEL_LAENGE];
float Preis_f;
int Anzahl_f;
for(i=0; i<DATENBANK_LAENGE; i++) {
/*Inventar-Nummer*/
(*buecherei_struct).Inv_Nr=i+1;
/*Titel*/
printf("\nBitte den %i.Titel eingeben\n", i+1);
gets(Titel_f);
strcpy((*buecherei_struct).Titel,Titel_f);
/*Preis*/
printf("Was soll das Buch \"%s\"ohne MwSt. kosten?\n", Titel_f);
scanf("%f", &Preis_f);
(*buecherei_struct).Preis=Preis_f;
/*Anzahl*/
printf("Wie oft gibt es das Buch \"%s\"?\n", Titel_f);
scanf("%i", &Anzahl_f);
(*buecherei_struct).Anzahl=Anzahl_f;
/*Pointer aufs nächste "Buch"*/
buecherei_struct++;
fflush(stdin);
}​
};


float Verk_Preis(BUCH *buch){
float vpreis;
vpreis=(((*buch).Preis/100.)*(*buch).MwSt)+(*buch).Preis;
return vpreis;​
};



Ich hoffe es ist verständlich was ich erreichen möchte, sry der Code ist durch das Kopieren etwas unleserlich. Habe es jetzt so gelöst dass ich einfach das erste Element des Arrays übergebe und den Pointer dann mit ++ erhöhe, aber so richtig ist es das ja nicht was ich machen wollte...:)

EDIT: Ach ja und das ganze läuft, hier die ein- und ausgabe in der cmd:
cmdausgabe.jpg
 
Zuletzt bearbeitet:
aber so richtig ist es das ja nicht was ich machen wollte
Doch doch, das ist schon richtig. In C sind Arrays und Pointer nur zwei unterschiedliche Sichtweisen auf die gleiche Sache. Du hättest auch schreiben können:
Code:
int main(int argc, char *argv[]) {

    float Ges_Preis=0;
    Eingabe_MwSt(Datenbank);   // geht auch so
    Eingabe_Gesamt(&Datenbank[0]);
oder an anderer Stelle:
Code:
    printf("\nBitte Mehrwertsteuer eingeben:\n");
    scanf("%f", &MwSt_f);
    for(i=0; i<DATENBANK_LAENGE; i++) {
      buch_ptr[i].MwSt=MwSt_f;  // ein pointer kann auch als array benutzt werden.
      fflush(stdin);
    }

Aber wahrscheinlich wolltest du, um die Benutzung des Arrays deutlicher zu machen, eine Definition wie folgt:
Code:
void Eingabe_MwSt(BUCH buch_ptr[]) {// hier ist ein array als Parameter definiert

    int i;
    float MwSt_f;
    printf("\nBitten Mehrwertsteuer eingeben:\n");
    scanf("%f", &MwSt_f);
    for(i=0; i<DATENBANK_LAENGE; i++) {
      buch_ptr[i].MwSt=MwSt_f;
 //   fflush(stdin);  Das ist hier überflüssig
    }

};
Der Aufruf erfolgt dann mittels:
Code:
    Eingabe_MwSt(Datenbank);
oder auch mal anders herum
Code:
void Eingabe_MwSt(BUCH buch_ptr[]) { // hier ist ein array als Parameter definiert
    int i;
    float MwSt_f;
    printf("\nBitten Mehrwertsteuer eingeben:\n");
    scanf("%f", &MwSt_f);
    for(i=0; i<DATENBANK_LAENGE; i++) {
      (*buch_ptr).MwSt=MwSt_f;  // hier kann das array auch als pointer benutzt werden
      buch_ptr++;
    }

};
 
Also ob ich als Parameter einen Pointer auf ein Array oder ein Array direkt übergebe ist das gleiche?
Ach und ohne fflush wird meine Eingabe einfach "übersprungen"...:(
 
Zuletzt bearbeitet:
Ob du einen Pointer auf das erste Element eines Arrays oder das Array (den Arraynamen allein) angibst, ist das Gleiche.
Code:
  char str[9] = "Ein Test";
  char *cptr1;
  char *cptr2;

  cptr1 = str;     // Die Verwendung des Arraynamens ohne die Indexklammern[]
                   // ergibt einen Pointer auf das erste Element des Arrays;
  cptr2 = &str[0]; // so geht es auch

  printf("%s\n",str);
  printf("%s\n",&str[0]);
  printf("%s\n",cptr1);
  printf("%s\n",cptr2);

  float MwSt_f;    // bei mir geht's ohne flush
  printf("\nBitte Mehrwertsteuer eingeben:\n");
  scanf("%f", &MwSt_f);
  printf("%f\n",MwSt_f);
 
Zurück
Oben