Search code examples
cfilememoryfopenfread

C, Eliminating loop when calling fread?


In C I wrote this code:

char tmp[strlen(argv[1]) + 1];
for (int j = 0; j < strlen(argv[1]) + 1; ++j) {
    fread(&tmp[j], 1, 1, file);
}

I prefer to eliminate the for loop to make the code shorter so is it equal to this (option A):

char tmp[strlen(argv[1]) + 1];
fread(&tmp, 1, strlen(argv[1]) + 1, file);

and this (option B):

char tmp[strlen(argv[1]) + 1];
fread(&tmp, strlen(argv[1]) + 1, 1 ,file);

From what I read on fread the answer is yes for both but want to understand what's preferable A or B?


Solution

  • None of the options is preferrable in my opinion and without knowing what you want to achieve, there is no answer to that.

    From Syntax, your code would compile and is correct. From the logic point of view its unusable.

    You do not know in your code how much data has been actually read, so you cannot work with the data stored in tmp. If your file contents are larger than your array or the file does not contain a null-terminator (which it most likely does not if its a textfile) you have no indicator of any kind how much chars got read into your array.

    At the very least you should store the return value of fread to know how much data has been actually read and how much data is valid in your array. Another way would be to initialize your array completly with zero bytes (either by = {}; or by memset) to make sure after valid data a nullterminator is found or your array is completly full, so you can terminate when reading from the array.

    Keep some things in mind:

    1. Loops are not evil nor clutter code or slow down execution in such an extend that you can justify not using them when reading user input (which a file is imho)
    2. You are dealing with user input, so expect unexpected data and unexpected sizes. Your code should deal with that in order to write robust and error-tolerant code.
    3. Read errors can occur. So if you want to read the full file, be prepared for that. For example reading will be terminated if your program gets interrupted by a signal (at least on linux). So you might need multiple attempts so read your entire file. Signals happen and you cannot guarantee that they will not. E.g. if you forked another process and the other process dies, it will trigger SIGCHILD. Just as an example.
    4. You use the strlen of argv[1] as your array length. That does not tell you if the contents of file will fit into that. So your should clarify your question on what your program actually should do. Also if you think that file will fit in tmp based on the length or argv[1], its still a file you read which might contain unexpected stuff.