cstringfiledynamic-list

C Reading a file to dynamic list, dynamic string


I have a list

typedef struct LISTA lista;
struct LISTA
{
    char *linia;
    int numer;
    struct lista *next;
};

Ad I need to get a .txt file, with unknown lengths of the lines, saved to it. With "linia" being the line dynamically malloc()-ed to it , and "numer" being a number of the line.

I tried to get it it to work trough reading it char by char, but with my limited knowledge in C I got very quickly tangled in it. I found several solutions here, but most of them had one or another issue, some were extremely complicated, and I couldn't understand what it did, and others lacked the '\0' at the end of string.

I would be really glad with an example and explanation what it does and how. I actually want to learn it, not just finish this stupid assignment

The actual assignment is making a grep-like program in C but I think I can get the rest of the mechanics done, I got stumped on saving it all to a dynamic list.


Solution

  • See the code bellow. It reads text file to a dynamic list, dynamic string. char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected); is crucial here.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct list
    {
        char *linia;
        int numer;
        struct list *next;
    };
    
    typedef struct list LIST;
    
    char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead){ 
        char *line;       // buffer for our string
        int ch;           // we will read line character by character
        size_t len = 0;   // number of characters read (character counter)
        size_t lineSize = typicalSize;  // initial size of the buffer allocated for the line
        *nrOfCharRead = 0;
    
        if(!fp) return NULL; // protection
    
        // allocating the buffer
        line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is up to typicalSize
    
        if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
    
        while (1) { // loop forever     
            ch = fgetc(fp);       // getting character by character from file
    
            if (ch == '\n') break; // end of line detected - breaking the loop 
            if( ch == EOF)  {
                *endOfLineDetected = 1;
                break; // end of file detected - breaking the loop
             }
    
            line[len++] = ch;     // store the character in the line buffer, increase character counter
    
            if (len == lineSize){ // we reached the end of line buffer (no more room)
    
            lineSize = lineSize + 64; // we have to increase the line size 
            line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
    
            if (!line) return line; // if we fail to allocate memory we will return NULL
            }
        }
    
        if( (len == 0) && *endOfLineDetected) return NULL; // empty file
    
        line[len++] ='\0';  // ending the string (notice there is no '\n' in the string)
        *nrOfCharRead = len;
    
        return line;       // return the string
    }
    
    int main(void) 
    {
        FILE *fp = NULL;   // file handle
        char *line; // 
        int endOfLineDetected = 0;
        size_t nrOfCharRead = 0;
    
        LIST *current, *head; // pointers to list elements
    
        head = current = NULL; // init to NULL
    
        fp = fopen("document.txt", "r"); // open file for reading
        int nr = 0;
    
        while( line = getLineOfAnySize(fp,128,&endOfLineDetected,&nrOfCharRead) ){ // read the file
    
             if( (nrOfCharRead == 0) && endOfLineDetected) break;             
    
            // create new list element 
    
            LIST *node = malloc (sizeof(LIST));
    
            nr = nr + 1;  
            node->linia = line;   // initialize the linia
            node->numer = nr;     // update the line number
    
            node->next = NULL; // next element do not exist yet
    
            if(head == NULL)
            {
                current = head = node;
            } else 
            {
                current = current->next = node;
            }
    
            if (endOfLineDetected) break;
        }
    
        if (fp) fclose(fp); // remember to close the file
    
        //print, go via all elements of the list till you get NULL next element
        for(current = head; current ; current=current->next){
            printf("line nr=%d line= %s",current->numer, current->linia );
        }
        return 0;
    }