Search code examples
cdata-structuresstructqueuefgets

Reading a specific pattern of a txt file in C


I have a txt file with this pattern:

11/01/2010: did not pass the test! :(
5
10/02/2010: not even this time I passed it! >:(
2
16/04/2010: is the third time I retake this exam!!! >:@
1
20/05/2024: finally passed it! :D 
14

I have to put every instance in the file in a queue data structure so defined

struct post {
    char msg[257];
    int n_like;
};

struct feed {
    struct post* storage;
    int busy;
};

void init(struct feed* queue) {
    queue->storage = malloc(sizeof(struct post) * N_QUEUE); //N_QUEUE = 4
    queue->busy = 0;
}

To do this I tried this function, where I read the first whole line using fgets() and then the number below with fscanf(). Then storing everythin through append():

int append(struct feed* queue, struct post s) {
    if (queue->busy >= N_QUEUE) return handle_err(FULL);
    queue->storage[queue->busy] = s;
    queue->busy++;
    return OK;
}

struct post pop(struct feed* queue) {
    if (queue->busy <= 0) handle_err(EMPTY);
    struct post s = queue->storage[0];
    for (int i=0; i<queue->busy-1; i++) {
        queue->storage[i] = queue->storage[i+1];
    }
    queue->busy--;
    return s;
}

int load_user_from_file(char* filename, struct feed* queue) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) return handle_err(FILE_ERR);
    
    struct post s;
    while (fgets(s.msg, 257, fp) != NULL) {
            while (fscanf(fp, "%d", &s.n_like) == 1) {
                append(&(*queue), s);
            }
        }
    return OK;
}

main:

int main() {
    struct feed queue;
    init(&queue);
    char* filename = "user42.txt"; 
    load_user_from_file(filename, &queue);

    return 0;
}

If I let the program run I get, of course, empty strings and zeros. Instead by including the handle_err(), which just triggers errors on screen and exits, I get a full stack error.

int handle_err(int errno) {
    switch (errno) {
        case FILE_ERR:
            printf("\nerror (%d): could not write/read the file\n\n", FILE_ERR);
            break;
        case EMPTY:
            printf("\nerror (%d): queue is empty\n\n", EMPTY);
            break;
        case FULL:
            printf("\nerror (%d): queue reached its full space\n\n", FULL);
            break;
        default: printf("\nunknown error occurred\n\n");
    }
    exit(FALSE);
}

I'm pretty sure there's something wrong in the load_user_from_file function.


Solution

  • While your code is not complete, this is clearly wrong:

        while (fgets(s.msg, 257, fp) != NULL) {
                while (fscanf(fp, "%d", &s.n_like) == 1) {
                    append(&(*queue), s);
                }
            }
    

    With the given input file that will result in more entries than you want to.

    With

    11/01/2010: did not pass the test! :(
    5
    10/02/2010: not even this time I passed it! >:(
    2
    

    The fscanf will first parse 5 and then also 10, leaving "/02/2010: not even this time I passed it! >:(\n" for the next entry.

    In total you will append 7 structs instead of 4.

    As you have a clear relation of one line with date+text and one line with that integer, it does not make any sense to use fscanf in a loop.

    Try something like this:

        while (fgets(s.msg, 257, fp) != NULL)
        {
            char buf[100];
            if ( (fgets(buf, sizeof(buf), fp) != NULL) 
              && (sscanf(buf, "%d", &s.n_like) == 1)
            {
               append(&(*queue), s);
            }
            else
            {   // Adjust error handling for your needs.
                exit(1);
            }
        }