Thread: Reading a file into char* (again)

  1. #1
    Registered User
    Join Date
    Jun 2011
    Posts
    1

    Reading a file into char* (again)

    <<< Split from ancient reading a file line by line and char * >>>

    I wanted this problem solved, and me not being satisfied with the results I found, I implemented my own code that performs this.

    Code:
    /************************************************************************************
     *   Author: Michael Bentley
     *   Date Created: June 28, 2011
     *   Description:  This library file provides three useful methods and one struct that
     *                 are useful for loading the contents of a file into memory and 
     *                 separated by lines.
     *   Note:         All newlines are removed in all of the provided methods
     *   
     *   Functions:
     *   char* read_one_line (FILE *file)
     *                 Reads from the current location in the file to the end of a line
     *                 or the end of the file.  No matter how long the line is, this
     *                 function will allocate memory just large enough to fit the line
     *                 without the newline character.  The user that calls this function
     *                 is responsible for freeing the pointer that is returned.
     *   
     *   lines* load_file_to_memory (char *filename)
     *                 Opens the file and creates a linked list structure containing the
     *                 lines in the file.  The user that calls this function is 
     *                 responsible for freeing the linked list that is returned by
     *                 calling the free_lines() function in this library.
     *   
     *   void free_lines (lines* head_node)
     *                 Frees a previously allocated linked list.  This function will 
     *                 traverse the linked list and free all of the memory.
     * 
     ************************************************************************************/
    
    #ifndef __MIKE_FILE_TO_MEMORY_H
    #define __MIKE_FILE_TO_MEMORY_H
    
    // A linked list containing the lines of a file
    typedef struct { // lines
        lines* prev;
        lines* next;
        char* line;
    } lines;
    
    char* read_one_line (FILE *file) {
        // The size of each read.  If too large, this method will waste memory
        // when the line isn't too long.  If too small, the linked list will be
        // too long when reading very long lines.
        int buffer_size = 512;
        
        // We need to account for a very large line, so we will make a linked list
        // then find out how long the line was and malloc that size in one go.
        lines* head_buffer;
        lines* current_buffer, prev_buffer;
        while (feof(fp) != NULL  &&  ferror(fp) != NULL) {
            // Allocate the memory and link it onto the end of our linked list
            prev_buffer = current_buffer;
            current_buffer = (lines*) malloc (sizeof(lines));
            current_buffer->line = (char*) malloc (buffer_size * sizeof(char));
            if (prev_buffer != NULL) prev_buffer->next = current_buffer;
            else head_buffer = current_buffer;
            current_buffer->prev = prev_buffer;
            
            // Read the rest of the line, or at least as much as the buffer can
            // hold.
            fgets (current_buffer->line, buffer_size, file);
            
            // If we reached the end of the line, exit the loop
            int length_filled = strlen(current_buffer->line);
            if (current_buffer->line[length_filled - 1] == '\n') { // newline character found
                current_buffer->line[length_filled - 1] = '\0';
                break;
            }
            else if (feof(fp) == NULL) // This was the last line in the file
                break;
        }
        if (ferror(fp))
            return NULL;
        
        // Now find out how long the line was
        current_buffer = head_buffer;
        int line_size = 0;
        while (current_buffer->next != NULL) {
            line_size += buffer_size;
            current_buffer = current_buffer->next;
        }
        line_size += strlen(current_buffer->line);
        
        // Allocate the return string memory size and copy the line into it
        char* return_string = (char*) malloc (line_size * sizeof(char));
        current_buffer = head_buffer;
        while (current_buffer != NULL) {
            strcpy (&(return_string[strlen(return_string)]), current_buffer->line);
            current_buffer = current_buffer->next;
        }
        
        // Free the temperary memory used by this function
        free_lines (head_buffer);
        
        return return_string;
    }
    
    lines* load_file_to_memory (char *filename) {
        FILE *file = fopen (filename, "r");
        
        lines* head_node;
        lines* current_line, prev_line;
        while (feof(fp) != NULL  &&  ferror(fp) != NULL) {
            // Allocate the memory and link it onto the end of our linked list
            prev_line = current_line;
            current_line = (lines*) malloc (sizeof(lines));
            if (prev_line != NULL) prev_line->next = current_line;
            else head_node = current_line;
            current_line->prev = prev_line;
            
            // Read the current line in the file.
            current_line->line = read_one_line (file);
        }
        if (ferror(fp))
            return NULL;
        
        fclose (file);
    }
    
    void free_lines (lines* head_node) {
        lines* current_line = head_node;
        while (current_line != NULL) {
            free (current_line->line);
            if (current_line->next != NULL) {
                current_line = current_line->next;
                free (current_line->prev);
            }
            else {
                free (current_line);
                current_line = NULL;
            }
        }
    }
    
    
    #endif // __MIKE_FILE_TO_MEMORY_H
    Last edited by Salem; 06-28-2011 at 03:18 PM. Reason: splitting

  2. #2
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Memory Allocation
    Example how to use realloc() to read arbitrary long line. duh~

  3. #3
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Is there any particular reason you bumped a six year old thread?
    Quote Originally Posted by musicaly View Post
    I wanted this problem solved, and me not being satisfied with the results I found, I implemented my own code that performs this.
    Oh. Right. Well let's hope you don't decide that you want the other 30,000 old threads solved eh?


    Quzah.
    Hope is the first step on the road to disappointment.

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by musicaly View Post
    I wanted this problem solved, and me not being satisfied with the results I found, I implemented my own code that performs this.
    First, read the forum guidelines, especially #3, which says don't bump old threads. Start your own if you have a problem/question. Otherwise, a "mom! look at me!" thread will get railed with criticism, like this:

    Second, your code doesn't "perform this". It's rife with errors, and doesn't even come close to compiling. Here are the results of my 5 minute overview:
    Good job on the commenting, seriously. Most noobs, and many more experienced coders don't comment very well, and it's incredibly important.

    Fix all these compilation errors and warnings:
    Code:
    $ gcc -Wall file.c
    file.c:34: error: expected specifier-qualifier-list before ‘lines’
    file.c:39: error: expected ‘)’ before ‘*’ token
    file.c: In function ‘load_file_to_memory’:
    file.c:102: error: ‘FILE’ undeclared (first use in this function)
    file.c:102: error: (Each undeclared identifier is reported only once
    file.c:102: error: for each function it appears in.)
    file.c:102: error: ‘file’ undeclared (first use in this function)
    file.c:102: warning: implicit declaration of function ‘fopen’
    file.c:106: warning: implicit declaration of function ‘feof’
    file.c:106: error: ‘fp’ undeclared (first use in this function)
    file.c:106: error: ‘NULL’ undeclared (first use in this function)
    file.c:106: warning: implicit declaration of function ‘ferror’
    file.c:108: error: incompatible types when assigning to type ‘lines’ from type ‘struct lines *’
    file.c:109: warning: implicit declaration of function ‘malloc’
    file.c:109: warning: incompatible implicit declaration of built-in function ‘malloc’
    file.c:111: error: invalid type argument of ‘->’ (have ‘lines’)
    file.c:114: error: ‘lines’ has no member named ‘prev’
    file.c:117: error: ‘lines’ has no member named ‘line’
    file.c:117: warning: implicit declaration of function ‘read_one_line’
    file.c:122: warning: implicit declaration of function ‘fclose’
    file.c: In function ‘free_lines’:
    file.c:128: error: ‘NULL’ undeclared (first use in this function)
    file.c:129: warning: implicit declaration of function ‘free’
    file.c:129: warning: incompatible implicit declaration of built-in function ‘free’
    file.c:129: error: ‘lines’ has no member named ‘line’
    file.c:130: error: ‘lines’ has no member named ‘next’
    file.c:131: error: ‘lines’ has no member named ‘next’
    file.c:132: error: ‘lines’ has no member named ‘prev’
    Problems:
    1. You need to #include a few standard header files.
    2. You're using include guards on a .c file, and you don't actually have a header file.
    3. You need to separate the typedef and struct lines, and give your struct a tag, if you want the struct to contain a pointer to itself.
    4. Don't cast the return value of malloc.
    5. Don't use feof to control a loop. Read why here.
    6. You should just make a regular array for reading from fgets, instead of malloc'ing a fixed size buffer.
    7. Your allocation/reallocation scheme is not optimal. See Bayint's link for a better alternative.
    8. You also don't need the allocate/copy bit at the end of read_one_line. Just allocate exactly what you need as you read with fgets, and store directly in there.
    9. You don't check to see if you successfully opened the file in load_file_to_memory.
    10. You have a type mismatch in load_file_to_memory here: prev_line = current_line; prev_line is a struct, current_line is a pointer. You can't assign one to the other.
    11. The following line: current_line->prev = prev_line; makes current_line->prev point to a stack variable. Once load_file_to_memory returns, that memory is invalid, so a seg fault awaits, since you can never detect the beginning of the list (first_node->prev doesn't point to NULL).

    That's where I gave up. I'm positive there's more to fix, but without compilable code, that's all I feel like doing. You have lots to learn and a lot of issues to resolve before I would call this one done.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reading a char from file
    By suzee_q00 in forum C Programming
    Replies: 4
    Last Post: 03-11-2008, 10:57 PM
  2. Reading '\r' char from a file
    By salvadoravi in forum C Programming
    Replies: 1
    Last Post: 12-29-2007, 06:44 AM
  3. Reading char arrays from a binary file
    By eaane74 in forum C++ Programming
    Replies: 17
    Last Post: 11-20-2007, 04:19 PM
  4. Reading char matrix from file
    By TriKri in forum C Programming
    Replies: 5
    Last Post: 07-19-2006, 02:05 AM
  5. Reading in a Char*[] from file
    By PunkyBunny300 in forum C++ Programming
    Replies: 1
    Last Post: 12-13-2003, 01:50 PM