Search code examples
cpointersstatic-fileschar-pointer

Issue opening a double pointer char element for reading it as text file


I'm new in C programming and I am trying to open a .txt file for reading it.

I have a text file with different file names I want to read, each one in a different line. I created a function txt_to_stations() that reads this file and returns a double pointer to char, I guess it has to be a double pointer because I want to save a string of char strings. This is the function.

char** txt_to_stations(const char* txt_file) {

    FILE* file;
    file = fopen(txt_file, "r");
    int line_count = 0;
    int char_count = 0;
    int len = 1;
    char tmp_station[25];
    char** stations = (char**)malloc(len*sizeof(char*));
    char character;
    while(!feof(file)) {
        character = fgetc(file);
        if(character != '\n') {
            tmp_estation[char_count] = character;
            char_count++;
        }else if(character == '\n') {
            stations = (char**)realloc(stations, len*sizeof(char*));
            stations[line_count] = (char*)malloc(char_count*sizeof(char));
            strcpy(stations[line_count], tmp_station);
            len++;
            line_count++;
            char_count = 0;
        }
    }
    fclose(file);
    return stations;
}

My text file is this one. "stations.txt"

weatherdata-429-81.csv
weatherdata-429-84.csv
weatherdata-429-88.csv

The problem comes when I try from the main function to read this files. The function works great because if I char** stations = txt_to_stations("stations.txt") and then for example printf("station1: %s\n", stations[0]) it prints weatherdata-429-81.csv in the terminal.

But if I define a new file in main function

FILE* reading;
reading = fopen(stations[0]);
if(reading == NULL) {
    printf("csv file cant be opened");
}

It prints "csv file cant be opened", which means fopen(stations[0]) == NULL, but it does not because if I simply change stations[0] by fopen("weatherdata-429-81.csv") it works. It may be a rookie error, but I understand that stations[0] == weatherdata-429-81.csv (as char*)

I really tried converting stations[0](char*) to a const char*, and also in "stations.txt" writing each name into double quotes, but anyway it did not work at all. How can I fix this?


Solution

  • I ran your code through a debugger, and found some mistakes. I commented them(and some other points) out for you.

    char** txt_to_stations(const char* txt_file)
    {
        FILE* file;
        file = fopen(txt_file, "r");
        if(file == NULL)  // You forgot to error-check file. fopen is one
                          // of the most likely functions to return NULL,
                          // so you really can't forget that
        {
            printf("Error opening file.");
            exit(0); // Exits your program, regardless of where
                     // you are, defined in stdlib.h
        }
    
        int line_count = 0;
        int char_count = 0;
        int len = 2;   // I made len slightly bigger, nothing with a
                       // little bit of buffer and also allows you
                       // to keep space for the NULL terminator
    
        char tmp_station[25] = {0}; // It is always a good idea to zero out
                                    // an array you're creating. While testing
                                    // I found some stray garbage characters
                                    // at the end of one of the strings...
    
        char** stations = (char**) malloc(len * sizeof(char*));
    
        char character;
    
        while (1) // This should run forever and you should break out
                  // of this loop when you reach the end of the file
        {
            // This is one way to properly find the end of a file.
            // Don't put feof call inside the while condition
            if (feof(file))
                break;
    
            // fgets() would save you a lot of time, but oh well,
            // I don't want to change your code too much...
            character = fgetc(file);
            if(character != '\n')
            {
                tmp_station[char_count] = character;
                char_count++;
            }
            else // Removed the if here because it was redundant... else
                 // it means that it must be a newline character
            {
                tmp_station[char_count] = '\0';  // You forgot to null-terminate
                                                 // the string you took into
                                                 // tmp_station. This is the
                                                 // main reason the function
                                                 // wasn't working
                stations = (char**) realloc(stations, len*sizeof(char*));
                stations[line_count] = (char*) malloc(char_count*sizeof(char));
                strcpy(stations[line_count], tmp_station);
                len++;
                line_count++;
                char_count = 0;
    
                // It's a good idea to terminate an array of pointers
                // with NULL. How will you know you reached the end
                // of the array?
                stations[line_count] = NULL;
            }
        }
        fclose(file);
        return stations;
    }
    

    There's a tiny little problem with your code as of now. See, because you only import a line into the array of pointers if and only if a newline is found, that means if the last line of your stations.txt file does not have a newline, that line will not get imported into the array. There are two solutions.

    1. Add an extra newline at the end of your text file like this
    weatherdata-429-81.csv
    weatherdata-429-84.csv
    weatherdata-429-88.csv
    
    1. Change the code so you can import the last line regardless of whether it has a newline character or not.

    2. Use fgets(). It will keep reading the entire file until it reaches the end of the file, so you can store whatever it returns inside an array and manually remove the newline characters that it generates yourself.