Seite 1 von 2

mehrdim. char Arrays

Verfasst: Mo Jul 18, 2011 3:36 pm
von Bruno
Hallo!

btw.: Hat die Seite irgendwo ein timeout?

Ich habe heute versucht etwas hochzuladen, aber das ist nicht im Forum angekommen?

Hier meine aktuelle Herausforderung:

Ich möchte Dateinamen aus einer Liste lesen und die Dateien dann anschließend öffen.

Mein Codeschnipsel sieht so aus:

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *substr(char [], int start, int end);

int main(void)
{
  FILE *Datei;
  char Zeile[80];
  char *Dateiname;
  int Anzahl=0;
  int i;
  char Dateien[10][80];

  Datei = fopen("wert.dat", "r+b");

    while (!feof(Datei))
    {
      fgets(Zeile,120,Datei);
      if (strstr(Zeile,"$") != NULL  && strncmp(Zeile,"$",1) == 0 )
      {
        continue;
      }
      if (strstr(Zeile,"Name") != NULL )
      {
/*       printf("%s",Zeile);*/
        Dateiname=strtok(Zeile,"'");
        Dateiname=strtok(NULL,"'");
/*        printf("Dateiname: %s\n",Dateiname);*/
        Anzahl++;
        strcpy(&Dateien[Anzahl][80],Dateiname);
      }
   }
/*
*/
  printf("gelesene Dateinamen: %d\n",Anzahl);  
  for  (i=1;i<=Anzahl;i++)
  {
    printf("%d %s\n",i,Dateien[i][80]);  
/*
    Datei = fopen(Dateien[i][80], "r+b");

    while (!feof(Datei))
    {
      fgets(Zeile,120,Datei);
      printf("%s",Zeile);
    }
*/    
  }
  return 0;
}
Die Datei wert.dat sieht so aus:

Code: Alles auswählen

Name  'abc.txt'
Name  'def.txt'
Name  'ghi.txt'
$Name  'ABC.txt'
NAME  'DEF.txt'
Complilieren tuts auch, aber beim starten gibts einen coredump.
Mein debugger liefert:
Program terminated with signal 11, Segmentation fault.
#0 0x000000379d771340 in strlen () from /lib64/tls/libc.so.6
Also was in der Funktion strlen, macht mich leider nicht wesentlich schlauer.

Ciao

Jürgen

P.S. das mit dem Fortran Tutorial überleg ich mir...

Re: mehrdim. char Arrays

Verfasst: Mo Jul 18, 2011 4:00 pm
von fat-lobyte
1. Du hast keinen Aufruf zu strlen. Könntest du bitte mit dem "-g" Flag kompilieren, das Programm mit GDB starten (gdb ./deinprogramm), das Programm starten ("r" eingeben) und nach dem Segmentation Fault "bt" eingeben, und die Ausgabe posten.
(Beenden mit k, y und q).

2.
Bruno hat geschrieben:

Code: Alles auswählen

Dateiname=strtok(Zeile,"'");
        Dateiname=strtok(NULL,"'");
Was genau hast du dir drunter vorgestellt? Wenn ich jetzt in der Referenz nachkucke, steht dort:
http://www.cplusplus.com/reference/clibrary/cstring/strtok/ hat geschrieben:C string to truncate. The contents of this string are modified and broken into smaller strings (tokens).
Alternativelly, a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
Bist du dir sicher dass der erste Aufruf erfolgreich war? Übrigens stehen da deine auskommentierten printf()'s nicht schlecht, die könnten dir beim debuggen helfen.

Ansonsten wunderts mich beim ersten drüberschauen schon, warum strlen() fehlschlägt wenn du es gar nicht aufrufst, bitte poste den Stack Trace.

Re: mehrdim. char Arrays

Verfasst: Mo Jul 18, 2011 4:33 pm
von Xin
Bruno hat geschrieben:Hallo!

btw.: Hat die Seite irgendwo ein timeout?
Welche Art Timeout meinst Du?
Bruno hat geschrieben:Ich möchte Dateinamen aus einer Liste lesen und die Dateien dann anschließend öffen.
Ich kann das hier nicht testen, aber ich habe mal drübergeguckt und ein paar Kommentare reingesetzt.

Code: Alles auswählen

int main(void)
{
  FILE *Datei;
  char Zeile[80];
  char *Dateiname;
  int Anzahl=0;
  int i;
  char Dateien[10][80];

  Datei = fopen("wert.dat", "r+b");

    while (!feof(Datei))
    {
// Du liest max 120 Zeichen in ein 80 Zeichen Array... sowas könnte schief gehen
// fgets( Zeile, sizeof(Zeile), Datei );
      fgets(Zeile,120,Datei);       
                               
// das entspricht if( Zeile[0] == '$' )
      if (strstr(Zeile,"$") != NULL  && strncmp(Zeile,"$",1) == 0 )   
      {
        continue;
      }
      if (strstr(Zeile,"Name") != NULL )
      {
/*       printf("%s",Zeile);*/
        Dateiname=strtok(Zeile,"'");

// das hier sieht mir kriminell aus? Was, wenn "'" nicht gefunden wurde?
// Wie ist Dateiname an der Stelle? Mach die printf()'s bitte wieder an und poste die Ausgabe.

        Dateiname=strtok(NULL,"'");            
Beispiel für strtok: http://www.proggen.org/doku.php?id=c:lib:string:strtok

PS: fat-lobytes Fazit hatte ich noch gar nicht gesehen. Dann haben aber unabhängig den gleichen Verdacht... ^^
Dann wird's wohl doch was anderes sein ;->

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 7:06 am
von Bruno
Hallo!

Hier der GDB output:

Program received signal SIGSEGV, Segmentation fault.
0x000000379d771340 in strlen () from /lib64/tls/libc.so.6
(gdb) bt
#0 0x000000379d771340 in strlen () from /lib64/tls/libc.so.6
#1 0x000000379d742e79 in vfprintf () from /lib64/tls/libc.so.6
#2 0x000000379d7486c8 in printf () from /lib64/tls/libc.so.6
#3 0x000000000040080e in main () at chararray.c:39
(gdb) k
Kill the program being debugged? (y or n) y
(gdb) q

fat-lobyte hat geschrieben:2.
Bruno hat geschrieben:

Code: Alles auswählen

Dateiname=strtok(Zeile,"'");
Dateiname=strtok(NULL,"'");
Was genau hast du dir drunter vorgestellt?
Damit zerteile ich die Zeile und schneide den part raus, der mich interessiert.
In einem Tutorial im Netz habe ich den Codeschnipsel zu gefunden und wenn ich das zuweise der Dateinamen in das Array auskommentiere, dann bekomme ich genau die mit den ' eingeschlossenen Dateinamen.
fat-lobyte hat geschrieben: Bist du dir sicher dass der erste Aufruf erfolgreich war? Übrigens stehen da deine auskommentierten printf()'s nicht schlecht, die könnten dir beim debuggen helfen.
Habe ich bereits versucht, aber entweder es sieht alles i.O. aus oder ich kriege einen segmentation fault.

Ruft strtok evt. strlen auf?

Zum timeout:
Ich habe bereits mehrfach Postings doppelt schreiben müssen, weil ich zwischendurch unterbrechen mußte und beim absenden mußte ich mich neu anmelden und das posting war weg. Oder ich konnte absenden ohne neu anzumelden und das posting war auchn weg.

Nur, wenn ich innerhalb einer (irgendwie gearteten) Zeitspanne schreibe und absende kann ich posten...
Sieht jedenfalls für mich so aus, daher die Frage nach einem timeout o.ä.

Ciao

Jürgen

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 7:40 am
von cloidnerux

Code: Alles auswählen

printf("%d %s\n",i,Dateien[i][80]); 
Ich glaube da hast du einen massiven Fehler drin.
%s erwartet einen c-string, also einen char-Pointer (char *cstring). Du übergibst aber das letzte Zeichen aus deinem Array, das noch nicht einmal Daten enthalten muss. Und wenn der Computer das jetzt wie einen Pointer verwendet und irgendwo im Ram liest, na dann gute nacht.
Es müsste egt so aussehen:

Code: Alles auswählen

printf("%d %s\mn", i, &Dateien[i]);
Ich habe bereits mehrfach Postings doppelt schreiben müssen, weil ich zwischendurch unterbrechen mußte und beim absenden mußte ich mich neu anmelden und das posting war weg. Oder ich konnte absenden ohne neu anzumelden und das posting war auchn weg.
Klingt danach, das die Session abläuft. Melde dich mal an und setze das Häkchen bei "Dauerhaft angemeldet bleiben", dann sollte es egt klappen.

MfG cloidnerux.

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 8:22 am
von fat-lobyte
cloidnerux hat geschrieben:

Code: Alles auswählen

printf("%d %s\mn", i, &Dateien[i]);
Das eine & ist noch zuviel, das gibt dir erstmal die Adresse der Adresse zu den Zeigern. Wenn du zum Anfang willst, brauchst du einfach nur Dateien.

Und ich glaube die ganzen anderen Dateien[80] sind auch falsch. Das ist ja das 81. Element des i. char-Arrays, und das wird nichtmal gesetzt. Wenn du da rein-strcpy'st, dann schreibt er an die 81. Stelle, dann zwar im Array, aber danach darüber hinaus.

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 9:12 am
von Xin
fat-lobyte hat geschrieben:
cloidnerux hat geschrieben:

Code: Alles auswählen

printf("%d %s\mn", i, &Dateien[i]);
Ich werfe mal

Code: Alles auswählen

printf("%d %s\n", i, Dateien[i]);
in den Ring ;-D

Begründungen sind ja schon geliefert. :-)

@Bruno: Hast Du Dir die beiden folgenden Seiten mal durchgelesen?
http://www.proggen.org/doku.php?id=c:tutorial:cstrings
http://www.proggen.org/doku.php?id=c:tutorial:pointer

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 1:44 pm
von Bruno
Hallo!
Xin hat geschrieben: @Bruno: Hast Du Dir die beiden folgenden Seiten mal durchgelesen?
http://www.proggen.org/doku.php?id=c:tutorial:cstrings
http://www.proggen.org/doku.php?id=c:tutorial:pointer
Ja, habe ich durchgeackert, im Tutorial sind ein paar Rächtschraibfeler und Steckwabenverbuchsler drin... :-) Aber ansonsten gut gemacht! Hut ab!

Klemmer habe ich trotzdem, aber mehr mit was anderem

Ich habe lese aus einer Datei meine Dateinamen ein:

Code: Alles auswählen

  
  char* MainFileName = 0;
  FILE *Datei ;
  char Zeile[120];
  char *inclname;
  char includes[100][80];
  char FileName;
  int inclzahl=1;
  int i;

// [...]

 while (!feof(Datei))
    {
      fgets(Zeile,120,Datei);
//
      if (strstr(Zeile,"$") != NULL  && strncmp(Zeile,"$",1) == 0 )
      {
        continue;
      }
      if (strstr(Zeile,"INCLUDE") != NULL || strstr(Zeile,"include") != NULL || strstr(Zeile,"Include") != NULL )
      {
        inclname=strtok(Zeile,"'");
        inclname=strtok(NULL,"'");
        strcpy(&includes[inclzahl][80],inclname);
        printf("%3d %s\n",inclzahl,inclname);
        inclzahl++;
      }
   }
   fclose(Datei);
und dann parse ich die de Dateien durch:

Code: Alles auswählen

  for  (i=1;i<inclzahl;i++)
  {
    strcpy(&FileName,MainFileName);    
    strcat(&FileName,includes[i]);    

    Datei = fopen(&FileName, "r+b");

    if (!Datei) 
    {
      printf("Die Datei `%s' konnte nicht geöffnet werden\n",includes[i]);
    }
    else
    {
      printf("lese include Nr. %d : %s\n",i,includes[i]);
      while (!feof(Datei))
      {
        fgets(Zeile,120,Datei);
//
        if (strstr(Zeile,"$") != NULL  && strncmp(Zeile,"$",1) == 0 )
        {
          continue;
        }
//
        if (strstr(Zeile,"Keyword") != NULL )
        {
//          [tu was]        }
      }
    }

  }
Was aber rauskommt ist:

1 Datei1.txt
2 Datei2.txt
3 Datei3.txt
Die Datei `AN/AN/' konnte nicht geöffnet werden
lese include Nr. 2 : Datei1.txt
lese include Nr. 3 : Datei2.txt

Wieso läuft die Zuweisung für den ersten Arrayeintrag schief? Da mache ich doch nichts anderes als wie bei den anderen Arrays??

Ciao

Jürgen

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 2:00 pm
von fat-lobyte
Kuck mal genau:

Code: Alles auswählen

strcpy(&includes[inclzahl][80],inclname);
Wieder der gleiche Fehler: du beginnst am ENDE des ersten Puffers zu lesen, der Anfang ist nicht initialisiert und deshalb zufällig (in deinem Fall der String "AN/AN/"). Außerdem schreibst du über die Arraygrenzen hinweg.
Nochmal, einfach:

Code: Alles auswählen

strcpy(includes[inclzahl],inclname);

Re: mehrdim. char Arrays

Verfasst: Di Jul 19, 2011 2:02 pm
von Xin
Bruno hat geschrieben:Hallo!
Xin hat geschrieben: @Bruno: Hast Du Dir die beiden folgenden Seiten mal durchgelesen?
Ja, habe ich durchgeackert, im Tutorial sind ein paar Rächtschraibfeler und Steckwabenverbuchsler drin... :-) Aber ansonsten gut gemacht! Hut ab!
Die Seiten sind noch recht neu, und wenn ich schreibe, lese ich, was ich schreiben wollte, nicht was ich geschrieben habe... dafür muss ich die Texte ein paar Wochen später nochmal lesen.
Bruno hat geschrieben:Ich habe lese aus einer Datei meine Dateinamen ein:
...
Was aber rauskommt ist:

1 Datei1.txt
2 Datei2.txt
3 Datei3.txt
Die Datei `AN/AN/' konnte nicht geöffnet werden
lese include Nr. 2 : Datei1.txt
lese include Nr. 3 : Datei2.txt

Wieso läuft die Zuweisung für den ersten Arrayeintrag schief? Da mache ich doch nichts anderes als wie bei den anderen Arrays??
"Datei1.txt" steht bei Index 2, Index 1 scheint nicht sinnvoll belegt zu sein. An Index2 müsste eigentlich "Datei2.txt" stehen. Ich sehe jetzt auch nicht direkt, wo der Fehler auftritt, aber include[1] hakt.

Ich vermute, dass der Fehler dadurch entsteht, dass Du den Filenamen an "&Filename" kopierst, also an die Adresse eines einzelnen Chars. Dort kopierst Du dann reichlich Daten hinter, was Dir vermutlich den Stack killt und zu willkürlichen Ergebnissen führt.

Filename sollte wenigstens ein großes Array sein und strcpy dann Filename und nicht &Filename erhalten.
Ändere das und dann guck nochmal, was passiert.


Edit: Was fatlobyte beschreibt, verursacht den konkreten Fehler. Trotzdem musst das von mir beschriebene ebenfalls korrigieren.