Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
11.07.2007, 12:36
LeJean



Hi,

so weit ist ja das zeilenweise Lesen einer Datei in C kein Problem:
(der untenstehende Code mag - was Rückgabewert etc. angeht - nicht ganz sinnvoll sein, aber darum soll es auch nicht gehen)

Quellcode:int readfile(char *fname)
{
  FILE* f;
  char line[256];

  f = fopen(fname, "r");
  while(fgets(line, 256, f))
  {
    // do sth
  }
  fclose(f);
  return 1;
}
So weit, so gut. Ich kann meine Zeilen lesen und verarbeiten.
Jetzt stellt sich mir folgendes Problem:
Unter Windows terminiert die Schleife genau so wie sie soll: Sind keine Zeilen in der File mehr vorhanden, dann ist die While-Schleife beendet, die Datei wird geschlossen und ich bekomme meinen Rückgabewert.
Unter Linux jedoch terminiert die Schleife nicht. Wenn versucht wird nach der letzten Zeile noch eine Zeile zu lesen (was ja die kopfgesteuerte Schleife macht), wird die Ausführung gekillt.
Ich hab keine Ahnung auf was ich noch prüfen soll, damit unter Linux diese Schleife terminiert. Der Debugger meldet an der Stelle (wenn die Schleife nach lesen der letzten Zeile ein letztes mal aufgerufen wird und abbrechen sollte): __uflow() mit einer Speicheradresse.

Jemand ne Ahnung wie ich das umgehen kann? Wenn ich zeichenweise statt zeilenweise lese, kann ich auf EOF prüfen.. geht das zeilenweise in irgendeiner Form auch? Oder kann ich prüfen ob die Datei an der derzeitigen Stelle noch folgende Zeilen hat? (Egtl dachte ich dass man das genau wie oben genannt prüfen kann...)

Bin für jede Hilfe dankbar!

MfG, Jean

--

zum Seitenanfang zum Seitenende Profil || Suche
001
11.07.2007, 12:46
feigling



Äh, ich mache es immer so

Quellcode:while(!feof(input))
{
    fgets(buffer, sizeof(buffer), input);

    if(*buffer == '\0')
        continue;

    if((ptr = strrchr(buffer, '\n')))
        *ptr = '\0';
}
Dann ließt er auch nur zeilenweise, maximal halt sizeof(buffer) chars.

--

zum Seitenanfang zum Seitenende Profil || Suche
002
11.07.2007, 12:51
LeJean



Uhm, da ist mir wohl die feof-Funktion entfallen... ich wusste doch dass das irgendwie geht :)

Quellcode:int readfile(char *fname)
{
  FILE* f;
  char line[256];

  f = fopen(fname, "r");
  while(!feof(f))
  {
    fgets(line, 256, f);
    // do sth
  }
  fclose(f);
  return 1;
}
demnach dürfte das in dieser Form (hoffentlich) funktionieren. Ich probier's gleich mal aus.. Danke!

Editiert:
Nein. Jetzt krieg ich o.g. Fehler (__uflow() 0x...) wieder in der Zeile, in welcher fgets(line, 256, f); steht. D.h. auch wenn ich in einer Zeile danach die von dir vorgeschlagene Prüfung auf '\0' einbauen würde, dann käme mein liebes Programm gar nicht so weit.

--


Dieser Beitrag wurde am 11.07.2007 um 12:59 von LeJean bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
003
11.07.2007, 13:10
Mazze



EOF wird nur gesetzt, wenn du schon am Ende bist, also wenn schon versucht wurde zu lesen und es nicht klappt, da du am Ende bist.

Du kannst den Rückgabewert von fgets prüfen.

Mazze

--

BattleTech-MOD:
http://bthl.unitedgaming.net/

zum Seitenanfang zum Seitenende Profil || Suche
004
11.07.2007, 13:17
LeJean



Naja, Auszug der Referenz zu fgets:

Zitat:
ReturnCode == NULL when an error occours. The EOF is considered to be an ERROR!
d.h. mit while(fgets(line, 256, f)) {...} prüfe ich doch den Rückgabewert. Auch bei expliziter Prüfung mit while(fgets(line, 256, f) != NULL) {...} krieg ich selbigen Fehler. Ausserdem Outputs auf der Konsole, die zu div. von mir genutzten Variablennamen sagen "No symbol "line" in current context".

Ich arbeite übrigens mit Eclipse.. jetzt hoffe ich mal ganz schwer dass ich nicht nen total blöden Fehler gemacht hab und nen falschen Compiler drin hab :X

Editiert: in Eclipse selber find ich keine Möglichkeit das umzustellen, ich schätze der nutzt für C ganz normal den gcc. Ich kann nur die Java-Compiler einstellen, aber die haben ja mit C herzlich wenig zu tun.

Editiert #2:
Quellcode:Building target: Labor2
Invoking: GCC C Linker
gcc  -o"Labor2"  ./fileops.o ./main.o ./nodeops.o ./treeops.o  
Finished building target: Labor2

Build complete for project Labor2
... ja, er nimmt den gcc.

Jean

--


Dieser Beitrag wurde am 11.07.2007 um 13:28 von LeJean bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
005
11.07.2007, 13:28
Mazze



Das sieht hier aber anders aus:
http://linux.die.net/man/3/fgets
http://bama.ua.edu/cgi-bin/man-cgi?fgets+3C

--

BattleTech-MOD:
http://bthl.unitedgaming.net/


Dieser Beitrag wurde am 11.07.2007 um 13:29 von Mazze bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
006
11.07.2007, 13:42
LeJean



Ja, du hast zweifelsohne Recht, dass das an und für sich so funktionieren sollte.


Aber der Fehler tritt definitiv in der fgets()-Funktion auf.
Editiert: Dass im Pfad /java vorkommt hängt nur damit zusammen, dass ich mit Eclipse sonst nur Java schreibe, und Eclipse halt alle Daten im Workspace ablegt...

Mein Code sieht im Moment so aus:
Quellcode:while(fgets(line, 256, f) != NULL)
{
  // code
}
Im inneren Code-Teil wird übrigens auch nicht an dem char* line herumgebogen, der bleibt die ganze Zeit bestehen wie er ist. Ich check's grad einfach nicht.

MfG, Jean

--


Dieser Beitrag wurde am 11.07.2007 um 13:43 von LeJean bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
007
11.07.2007, 14:10
default



ich würd ja sagen leg mal die datei die du einlesen willst vor, ich denke es wird dir mehr helfen das alles mit fscanf zu machen statt zeilenweise und dann 'wie auch immer' zu parsen, aber hier ist mal mein beitrag

Quellcode:#include <stdio.h>
#include <string.h>
#include <errno.h>

int readfile(char *fname)
{
    FILE* f;
    char line[256];

    if ((f = fopen(fname, "r")) == NULL)
    {
        printf("could not open file %s (%s)\n", fname, strerror(errno));
        return -1;
    }

    while ( !feof(f) )
    {
        line[0] = '\0';
        if ( fgets(line, 256, f) == NULL )
        {
//            printf("fgets failed (%s)\n", strerror(errno));
            break;
        }

        char *term;
        if ( (term = strstr(line,"\r")) != NULL )
            *term = '\0';

        if ( (term = strstr(line,"\n")) != NULL )
            *term = '\0';

        // ' do it '
        printf("read '%s'\n",line);
        
        
    }
    fclose(f);
    return 1;
}

int main()
{
    return readfile("/etc/motd");
}

--

Du musst Deine Bandbreite verbreitern, damit du breiter wirst von der Bandbreite her und ein breiteres Publikum ansprechen kannst.


Dieser Beitrag wurde am 11.07.2007 um 14:11 von default bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
008
11.07.2007, 14:35
oxff



Ist für kleine Files eh performanter:
Quellcode:int readLines(const char * file)
{
  FILE * handle = fopen(file, "rt");
  char * buffer, * linestart, * lineend;
  long size;

  if(!handle)
    return 0;

  fseek(handle, 0, SEEK_END);
  size = ftell(handle);
  fseek(handle, 0, SEEK_SET);

  buffer = (char *) malloc(size + 1);
  buffer[size] = 0;

  if(fread(buffer, 1, size, handle) < size)
  {
    free(buffer);
    fclose(handle);
    return 0;
  }

  fclose(handle);

  linestart = buffer;
  lineend = strchr(buffer, '\n');

  while(lineend)
  {
    * lineend = 0;

    processLine(linestart);
    linestart = lineend + 1;
    lineend = strchr(linestart, '\n');
  }

  if(* linestart)
    processLine(linestart);

  free(buffer);
  return 1;
}

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik


Dieser Beitrag wurde am 11.07.2007 um 14:39 von oxff bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
009
11.07.2007, 14:39
feigling



Quellcode:if(fread(buffer, 1, size, handle) < size)
  {
    free(buffer);
    return 0;
  }

  fclose(handle);
Da sollte noch nen fclose(handle); in die Klammer und malloc castet man nicht =)

--

zum Seitenanfang zum Seitenende Profil || Suche
010
11.07.2007, 14:40
oxff



Ja, ich hab da nicht ordentlich aufgeräumt (editiert) und man muss das casten.

edit: `kleine' Files heisst hier übrigens Größenordnung < 1 MB.

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik


Dieser Beitrag wurde am 11.07.2007 um 14:40 von oxff bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
011
11.07.2007, 14:41
default



in c nicht

--

Du musst Deine Bandbreite verbreitern, damit du breiter wirst von der Bandbreite her und ein breiteres Publikum ansprechen kannst.

zum Seitenanfang zum Seitenende Profil || Suche
012
11.07.2007, 17:41
Kriz



Siehe auch http://c-faq.com/malloc/mallocnocast.html

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)

zum Seitenanfang zum Seitenende Profil || Suche
013
11.07.2007, 19:08
LeJean



Okay..
zunächst: meine ganze Funktion, die die Probleme macht, sieht wie folgt aus:
Quellcode:NODE* read_tree(char* name)
{
  char p[64] = DATA_PATH;
  char line[256], *lpos;
  NODE *nodes, *curn;
  FILE* f;
  int cnt = 0, icnt = 0;
  
  nodes = (NODE*)calloc(sizeof(NODE), sizeof(NODE));
  strcat(p, name);
  strcat(p, ".cfg");
  
  printf("%s\n", p);
  f = fopen(p, "r");
  if(f != 0)
  {
    while(fgets(line, 256, f) != NULL)
    {
      if(line[0] == 'i')
      {
        if(icnt++ == 0)
          sscanf(line + 1*sizeof(char), "%d", &_n);
        else
          sscanf(line + 1*sizeof(char), "%d", &_k);
      }
      
      if(line[0] == '?')
      {
        icnt = 0;
        
        cnt++;
        printf("Found node. Reading... ");
        nodes = (NODE*)realloc(nodes, cnt * sizeof(NODE));
        curn = nodes + (cnt - 1) * sizeof(NODE);
        
        lpos = line;        
        while(lpos[0] != '\n' && icnt < 5)
        {
          lpos = strchr(lpos, ';') + 1*sizeof(char);
          
          switch(icnt)
          {
            case 0:   sscanf(lpos, "%d", &curn->id);
                      //printf("  read id: %d\n", curn->id);
                      break;
            case 1:   sscanf(lpos, "%d", &curn->is_leaf);
                      //printf("  read leaf: %d\n", curn->is_leaf);
                      break;
            case 2:   sscanf(lpos, "%d", &curn->tmp_sid);
                      //printf("  read sid: %d\n", curn->tmp_sid);
                      break;
            case 3:   sscanf(lpos, "%d", &curn->tmp_cid);
                      //printf("  read cid: %d\n", curn->tmp_cid);
                      break;
            case 4:   strcpy(curn->file, lpos);
                      curn->file[strlen(curn->file) - 1] = '\0';
                      //printf("  read file: %s\n", curn->file);
                      break;
            default:  break;
          }
          
          icnt++;
        }
        printf("done: %d(id) %d(leaf) %d(sid) %d(cid) %s(file)\n", curn->id, curn->is_leaf, curn->tmp_sid, curn->tmp_cid, curn->file);
      }
    }
    fclose(f);
    printf("done all nodes.\n");
    link_nodes(nodes, cnt);
    
    return nodes;
  }
  else
  {
    printf("File not found.\n");
    return NULL;
  }
}
Das Teil dient dazu, aus einer Config-File die Struktur eines zuvor angelegten und abgespeicherten B-Baumes zu lesen, um den Baum erneut aufbauen zu können.
Die File dazu hat folgendes Schema:
Quellcode:=BTREE
i4
i2
=CFG: ?;id;is_leaf;sibling;child;filename
==
?;-1;0;-1;65000;
?;65000;1;-1;-1;firsttree_1
Ach ja.. und mein struct für die Nodes, die gelesen werden...
Quellcode:typedef struct node
{
  int id, is_leaf, tmp_sid, tmp_cid;
  struct node *sibling, *child;
  char file[64];
} NODE;
Die Sache bei besagter Funktion ist: Ich bekomme für alle Nodes aus der File den richtigen Output und kann mir auch einzeln all deren Attribute ausgeben lassen, die stimmen wohl. Allerdings kommt es nie zu dem Aufruf von link_nodes(...), weil eben die Schleife vorher das Programm zum Abbruch zwingt. Demnach wird auch die File nicht richtig geschlossen etc., aber das ist ja auch klar wenn die Schleife abkackt.

So viel erstmal dazu. Alternative Ansätze zum Durchlaufen der Schleife und Parsen der Zeileninhalte sind ja schön und gut, und lassen sich natürlich auch umsetzen, aber an und für sich hat meine Methode da immer funktioniert und wird doch auch überall so vorgeschlagen.

Danke,
MfG, Jean

Editiert:
Quellcode:int main(int argc, char *argv[])
{
    FILE* f = fopen("./Debug/rf", "r");
    char line[10];
    
    if(f == 0)
      return 0;
    while(fgets(line, 10, f))
    {
        printf("line: %s", line);
    }
    printf("EOF\n");    
    
    return 1;
}
mit folgender File als Input:
Quellcode:eins
zwei
drei
vier
liefert wie erwartet das richtige Ergebnis im Output:
Quellcode:line: eins
line: zwei
line: drei
line: vier
EOF
also muss mein Problem nicht zwangsläufig an der Schleife liegen, wenngleich auch der Debugger den Fehler an der Stelle meldet. Ich werd mich mal wieder auf die Suche begeben.

--


Dieser Beitrag wurde am 11.07.2007 um 20:45 von LeJean bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
014
11.07.2007, 21:10
LeJean



alles klar, dank default hat sich das soeben gelöst.
Mein Fehler lag in der Pointerzuweisung für den Speicherbereich vom aktuell zu verarbeitenden Knoten:
Quellcode:curn = nodes + (cnt - 1) * sizeof(NODE); wurde geändert in:
Quellcode:curn = &nodes[cnt - 1]; vielen Dank nochmal!
MfG, Jean

--

zum Seitenanfang zum Seitenende Profil || Suche