0

I'm trying to read data into an array of structs from a text file of the form:

code string

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINESIZE 300

typedef struct{
    int code;
    char *name;
}JOB;

int countLines(FILE *fp)
{
    int count = 0;
    for (int c; (c = fgetc(fp)) != EOF; )
        if (c == '\n')
            ++count;
    return count;
}

int main(int argc, char **argv)
{
    FILE *fin = fopen("search_file.txt", "r");
    
    if(!fin)
    {
        fprintf(stderr, "Error opening the file.\n");
        exit(EXIT_FAILURE);
    }

    int nEntries = countLines(fin);
    fseek(fin, 0L, SEEK_SET);
    //printf("%d", nEntries);
    JOB *arr = (JOB *)malloc(nEntries * sizeof(JOB));
    int k = 0;
    char buf[MAXLINESIZE];
    
    while(!feof(fin))
    {
        fscanf(fin, "%d", &arr[k].code);
        fgetc(fin);
        fgets(buf, sizeof(buf), fin);
        buf[strlen(buf) - 1] = '\0';
        arr[k].name = strdup(buf);
        k++; 
    }

    for(k = 0; k < nEntries; k++)
    {
        printf("[%d] Code : %d | Job: %s\n", k+1, arr[k].code, arr[k].name); 
    }

    fclose(fin);
    return 0;
}

Right now, it's storing the code and the string from the file inside the corresponding members, but after displaying everything from the file, I get the error:

corrupted size vs. prev_size

Aborted (core dumped)

Any idea why this is happening?

EDIT: text file example:

123 something something
456 abc
678 a b c defg
Andrei0408
  • 197
  • 7
  • 3
    [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Eugene Sh. Oct 12 '21 at 13:35
  • `buf[strlen(buf) - 1] = '\0';` - what are you trying to do here? `strlen` is only working with `\0` terminated string already. – Eugene Sh. Oct 12 '21 at 13:37
  • I saw that too, @EugeneSh., but upon reflection, I realized that it will remove the trailing newline that `fgets()` puts in the buffer. Of course, if the line is too long for the buffer then it will remove actual data. – John Bollinger Oct 12 '21 at 13:38
  • @EugeneSh. Isn't it an attempt to remove a newline from fgets. – Support Ukraine Oct 12 '21 at 13:39
  • @EugeneSh. trimming the newline so that the next fscanf can happen. – Andrei0408 Oct 12 '21 at 13:39
  • Have you checked the value of `nEntries` and the largest value of `k`? – Support Ukraine Oct 12 '21 at 13:41
  • [How to trim newline](https://stackoverflow.com/q/2693776/6699433) – klutt Oct 12 '21 at 13:42
  • @4386427 Hm, I checked the value of nEntries before and it's fine, but now that you mentioned I just checked the value of ```k``` after the loop, and that's where it crashes. No idea why – Andrei0408 Oct 12 '21 at 13:43
  • 3
    Since you start out by counting lines, it would make sense to attempt to read the specific number of lines you found, instead of reading until you encounter end-of-file. – John Bollinger Oct 12 '21 at 13:43
  • For this to be a [mcve], we need the input that causes the crash. – Nate Eldredge Oct 12 '21 at 13:43
  • Alternatively, if you read to EOF then you should at least confirm that you read the number of entries you expected to read. – John Bollinger Oct 12 '21 at 13:45
  • Additionally, beware of getting tripped up in the event that the file does not end with a newline. – John Bollinger Oct 12 '21 at 13:48
  • Tools that are your friend: a memory usage analyzer such as Valgrind; a debugger such as gdb. – John Bollinger Oct 12 '21 at 13:51
  • 1
    Add some error handling to `fgets`. The EOF check should be done there, not in the loop condition. – Lundin Oct 12 '21 at 13:58
  • Counting the newlines first, and then assuming that `fgets` will return exactly that number of times, is not safe. You will have problems if a file contains a line longer than `MAXLINESIZE`, or if the file doesn't end in a newline, or if somebody modifies the file while you are processing it. These are the kind of thing that leads to security flaws. Instead, just read through the file one time with `fgets`, and use `realloc` to grow the `arr` array as needed. – Nate Eldredge Oct 12 '21 at 14:03
  • @Lundin you're right, fgets was the problem. I checked for NULL after fgets and now it's working as intended. Thank you all for you responses! I will know mark the question as answered. EDIT: could you maybe copy your comment and paste is as an answer so I can close it and give you the credit – Andrei0408 Oct 12 '21 at 14:06
  • No, `fgets` was not the problem. Using `while(!feof(fin))` instead of checking the return values of your I/O functions -- not only `fgets`, but `fscanf` and `fgetc` too! -- was the problem. Also, allowing the program to read more entries than you allocated for. – John Bollinger Oct 12 '21 at 14:13
  • @JohnBollinger Yes, I know ```while(!feof(fin))``` is a bad practice, I normally use ```fgets``` and test for ```null``` in order to read line by line, but this is what I was instructed to use this time – Andrei0408 Oct 12 '21 at 14:18
  • 1
    If you are instructed to use `while(!feof(fin))` then you should complain to your instructor. To comply with the instructions anyway, do this: (1) read each whole line at once via `fgets()`, then parse it via string functions; the point is to perform only one I/O call per line. (2) Perform the first of those `fgets()` calls prior to entering the loop, and each subsequent one at the bottom of the loop instead of at the top. Also, make sure you do not read more lines than you allocated for, possibly by dynamically reallocating as needed. – John Bollinger Oct 12 '21 at 14:23

0 Answers0