Dateiinhalt als char



  • hi,
    ich habe bisher ein funktionierendes Programm,

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void main (void)
    {
    char *txt;
    int leng;
    txt="Der lange Text...";
    leng=strlen(txt);
    printf("\n%s\t\t\t%d\n","Anzahl der Zeichen im Text:",leng);
    ...
    }
    

    das ich so ändern möchte, dass der Text aus einer txt-Datei einlesen wird (statt hier im Code). Wie mache ich das, dass ich so wenig wie möglich an meinem ursprünglichen Code verändern muss.
    Also ich möchte möglichst den Teil behalten:

    char *txt;
    int leng;
    txt=
    

    Danke für die Aufmerksamkeit



  • okay dein programm ist nicht korrekt.

    char* text;
    
    text = "blah. .."; /* hier sollte nen fehler auftauchen */
    

    du hast nicht genug speicher reserviert um deinen text in der variable text zu speichern. mach es entweder so:

    char* text = "blah ...";
    

    oder du nimmst dynamische speicherverwaltung:

    char* text;
    if( ( text = malloc( 100 ) ) != NULL ) {
       strcpy( text, "blah..." );
    }
    

    zu deinem vorhaben: wie willst du die datei auslesen, bzw. wie wird die datei bekannt gemacht? willst du über ne file-umlenkung (z.b. unter unix/linux verwendet) die datei auslesen, oder wird der dateiname als parameter an das programm (an main) mit übergeben oder willst du die datei im quelltext als stream haben?



  • hando schrieb:

    okay dein programm ist nicht korrekt.

    char* text;
    
    text = "blah. .."; /* hier sollte nen fehler auftauchen */
    

    du hast nicht genug speicher reserviert um deinen text in der variable text zu speichern.

    Quark!



  • hando schrieb:

    zu deinem vorhaben: wie willst du die datei auslesen, bzw. wie wird die datei bekannt gemacht? willst du über ne file-umlenkung (z.b. unter unix/linux verwendet) die datei auslesen, oder wird der dateiname als parameter an das programm (an main) mit übergeben oder willst du die datei im quelltext als stream haben?

    hi,
    ich möchte die Datei als stream haben.
    ich stelle sie mir so vor:

    FILE *datei;  
    datei = fopen("text.txt", "r");  
    int i=0;  
    char *b;  
    while (!feof(datei)){  
          b[i]=fgetc(datei); 
    	  i++; 
    }  
    b[i]='\0'; 
    
    char *text = b
    ...
    

    was aber nicht funktioniert...



  • clanicat schrieb:

    hando schrieb:

    zu deinem vorhaben: wie willst du die datei auslesen, bzw. wie wird die datei bekannt gemacht? willst du über ne file-umlenkung (z.b. unter unix/linux verwendet) die datei auslesen, oder wird der dateiname als parameter an das programm (an main) mit übergeben oder willst du die datei im quelltext als stream haben?

    hi,
    ich möchte die Datei als stream haben.
    ich stelle sie mir so vor:

    FILE *datei;  
    datei = fopen("text.txt", "r");  
    int i=0;  
    char *b;  
    while (!feof(datei)){  
          b[i]=fgetc(datei); 
    	  i++; 
    }  
    b[i]='\0'; 
    
    char *text = b
    ...
    

    was aber nicht funktioniert...

    Hi!
    Es funktioniert, mit folgenden Ansätzen: char b[anzahl_zeichen_in_datei+1];,
    oder: char* b = malloc ( ...

    Gruß,
    B.B.



  • hiermit kannst du zum beispiel eine datei (zeichenweise) auslesen und wird in dem fall zeichenweise ausgegeben:

    int c, i = 0;
    char inhalt[100];
    FILE* datei = fopen( "test.txt", "r" );
    
    if( datei != NULL ) {
       while( ( c = fgetc( datei ) ) != EOF ) {
          inhalt[i] = c;
          i++;
       }
    }
    
    else
       /* Fehler beim Oeffnen der Datei */
    

    das sollte dir eigetnlich weiterhelfen. habs allerdings nicht getestet 🙂

    beachte: wenn mehr eingelesen wird als speicher für variable inhalt (hier 100) reserviert wurde, gibts nen overflow.



  • Hi,
    Danke für eure Hilfe.

    aber das Problem ist gerade, dass
    1. das Programm dazu dienen soll, die Zeichen zu zählen,
    2. die Datei soll beliebig groß sein (als Beispiel ein Roman)

    Der Code in meinem Anfangsbeitrag funktioniert,

    txt="Der lange Text...";
    

    auch wenn dieser txt ein paar Tausend Zeichen enthält.



  • Die Anzahl der Zeichen lässt sich per Dateiinformationen ermitteln, z.B. fstat und co..
    Ermitteln lässt sich sich auch ohne Dateiinfos mit fseek/ftell oder zeichenweises Einlesen und zählen der Zeichen.
    Brauchst du den Text komplett im Arbeitsspeicher, kommst du ab einer bestimmten Anzahl Bytes nicht um malloc drum herum:
    char* b = malloc ( anzahl_der_zeichen + 1);
    Es funktioniert auch ohne sich im Voraus um die Anzahl der Zeichen in der Datei zu kümmern, indem das Array mit realloc dynamisch erweitert wird.



  • Oder halt ueber verkettete Liste, die dann in einen String geschrieben wird - etwa so (ins Grobe geschmiert):

    struct SingleChar
    {
         char                cData;
         struct SingleChar  *pNext;
    }
    
    struct SingleChar *ReadList (FILE  *pFile)
    {
            struct SingleChar *pCurrent = NULL,
                              *pReturn  = NULL,
                              *pTemp;
            char               cTemp;
    
            while (!feof(pFile))
            {
                    pTemp = malloc (sizeof (SingleChar));
                    pTemp->cData = fgetc(pFile);
                    pTemp->pNext = NULL;
    
                    if (pReturn == NULL)
                            pReturn = pTemp;
                    else
                            pCurrent->pNext = pTemp;
    
                    pCurrent = pTemp;
            }
    
            return pReturn;
    }
    
    void FillData (char              *szText,
                   struct SingleChar *pIn)
    {
            szText [0] = pIn->cData;
    
            if (pIn->pNext != NULL)
                    FillData (&szText [1], pIn->pNext);
            else
                    szText [1] = '/0';
    }
    
    int GetCount (struct SingleChar *pIn,
                  int                iValue)
    {
            if (pIn == NULL)
                    return iValue;
            else
                    return (GetCount->pNext, iValue + 1);
    }
    
    char *BuildStr (struct SingleChar *pIn)
    {
            char    *szReturn;
    
            szReturn = calloc (GetCount (pIn, 0) + 1, sizeof (char);
    
            FillData (szReturn, pIn);
    
            return szReturn;
    }
    
    int main ()
    {
            FILE               *pFile     = NULL;
            struct SingleChar  *pCharList = NULL;
            char               *szOut     = NULL;
    
            pFile = fopen("text.txt", "r");
    
            if (pFile != NULL)
                  pCharList = ReadList (pFile);
    
            if (pCharList != NULL)
                    szOut = BuildStr (pCharList);
    
            if (szOut != NULL)
                    printf ("My text: <%s>\n", szOut);
            else
                    printf ("Schiefgegangen\n");
    
            if (szOut != NULL) free   (szOut);
            if (pFile != NULL) fclose (pFile);
            CleanList (pCharList);
    
            return 0;
    }
    

    🤡



  • hartmut, dein beispiel ist absoluter overkill.
    🙂



  • @hartmut: ehrlich gesagt, finde ich das unnötig kompliziert und Speicherfressend. Eine ganze Struktur für jedes Zeichen finde ich ganz schon übertrieben.

    Ich verwende immer

    char *get_next_line(FILE *fp) 
    { 
        int c, buff_len, str_len; 
        char *buff, *tmp; 
    
        buff = NULL; 
        buff_len = str_len = 0; 
    
        for(c = fgetc(fp); (c != '\n' && c != EOF) ; c = fgetc(fp)) 
        {   
            str_len++; 
            if(str_len >= buff_len) 
            {   
                buff_len = 2*str_len; 
    
                tmp = realloc(buff, buff_len); 
                if(tmp == NULL) 
                    return buff; 
                buff = tmp; 
            }   
    
            buff[str_len - 1] = c; 
            buff[str_len] = 0; 
        }   
    
        return buff; 
    }
    

    um Zeilen zu lesen, daraus eine get_file_content() Funktion zu basteln, sollte nicht schwer sein.



  • supertux schrieb:

    for(c = fgetc(fp); (c != '\n' && c != EOF) ; c = fgetc(fp))
    

    das sieht aber hässlich aus. mach doch 'ne do..while daraus.
    🙂



  • +fricky schrieb:

    supertux schrieb:

    for(c = fgetc(fp); (c != '\n' && c != EOF) ; c = fgetc(fp))
    

    das sieht aber hässlich aus.

    finde ich nicht 😉 aber Geschmack ist subjektiv.

    so, hab auch ne get_file_content mit dazu passender free Funktion geschrieben:

    /* returns NULL terminated list of char* Pointers */
    char **get_file_content(FILE *fp)
    {
        char **buff, **tmp, *line;
        int len = 0;
    
        buff = calloc(1, sizeof *buff);
        if(buff == NULL)
            return NULL;
    
        buff[0] = NULL;
    
        while(line = get_next_line(fp))
        {   
            tmp = realloc(buff, (len+2) * sizeof *buff);
            if(tmp == NULL)
                return buff;
            buff = tmp;
    
            buff[len++] = line;
            buff[len] = NULL;
        }   
    
        return buff;
    }
    
    void free_file_content(char **fc)
    {
        int i = 0;
        if(fc == NULL)
            return;
    
        while(fc[i])
            free(fc[i++]);
    
        free(fc);
    }
    


  • ^^lass es vom mod in die faq aufnehmen.
    🙂



  • supertux schrieb:

    @hartmut: ehrlich gesagt, finde ich das unnötig kompliziert und Speicherfressend. Eine ganze Struktur für jedes Zeichen finde ich ganz schon übertrieben.

    Semi Off-Topic:
    Kompliziert - OK: War auch nicht ganz ernst gemeint.
    Speicherintensiv: Weniger, die Struct enthaelt nur einen char und einen Pointer. Das verdoppeln des Heaps ("buff_len = 2*str_len; tmp = realloc(buff, buff_len);") ist u.U. sehr viel speicherintensiver.

    ---

    Das Problem mit meinem Vorschlag ist ein anderes: Die Rekursion wird ueber den Stack abgehandelt, wenn z. B. ueber 10^6 Elemente eingelesen werden, geht dieser dann schon mal in die Knie und Du hast einen Stackoverflow. Und hier wuerde ich Pruegel verdientermassen einstecken muessen.



  • hartmut1164 schrieb:

    Und hier wuerde ich Pruegel verdientermassen einstecken muessen.

    allein schon die idee, eine ganze datei zeichenweise in eine verkettet liste zu verwandeln, ist der pure wahnsinn. mach doch demnächst pro zeichen ein unterverzeichnis (das zeichen selbst ist dann der name einer einzigen datei im verzeichnis).
    🙂



  • +fricky schrieb:

    hartmut1164 schrieb:

    Und hier wuerde ich Pruegel verdientermassen einstecken muessen.

    allein schon die idee, eine ganze datei zeichenweise in eine verkettet liste zu verwandeln, ist der pure wahnsinn.

    Nicht ganz: Hier ist das mit Kannonen auf Spatzen geschossen, aber wenn Du Dir einmal einen Datenfile einliesst, z. B. ueber einen Socket, und weisst nicht wie gross die Datenmengen sind, willst aber direkt eine Rueckmeldung geben, falls inconsitente Daten uebertragen werden, dann muss man solche Listen und deren Zeigerverknuepfung dynamisch beim Einlesen aufbauen.



  • hartmut1164 schrieb:

    Semi Off-Topic:
    Kompliziert - OK: War auch nicht ganz ernst gemeint.
    Speicherintensiv: Weniger, die Struct enthaelt nur einen char und einen Pointer. Das verdoppeln des Heaps ("buff_len = 2*str_len; tmp = realloc(buff, buff_len);") ist u.U. sehr viel speicherintensiver.

    Bei n Zeichen fordert get_next_line maximal 2*n Bytes an (
    22log2n2\cdot2^{\lfloor\log_2n\rfloor} Bytes um genau zu sein)

    Bei n Zeichen fordert ReadList genau sizeof(struct SingleChar)*n Bytes an, was ja 8*n Bytes bedeutet (wegen Padding Bytes). Und du nennst meine Methode speicherintensiver? (außerdem habe ich ~ log_2(n) malloc/realloc Aufrufe und du genau n )

    edit:

    +fricky schrieb:

    ^^lass es vom mod in die faq aufnehmen.
    🙂

    gute Idee, hab den Code schon öfters hier gepostet.



  • hartmut1164 schrieb:

    ...aber wenn Du Dir einmal einen Datenfile einliesst, z. B. ueber einen Socket, und weisst nicht wie gross die Datenmengen sind, willst aber direkt eine Rueckmeldung geben, falls inconsitente Daten uebertragen werden, dann muss man solche Listen und deren Zeigerverknuepfung dynamisch beim Einlesen aufbauen.

    nö, das könnteste genau so machen wie z.b. mit supertuxens realloc-methode. wobei ich sowieso mehr ein fan von häppchenweiser verarbeitung bin. komplettes einlesen von datenmengen, die beliebig gross sein können, ist immer gefährlich (ausser man setzt sich ein limit).
    🙂


Log in to reply