1

I have this code and I don't understand how it works:

void print(char * fileName)
{
    FILE * fp;
    int ch;
    fp = fopen(fileName, "r");
    while (ftell(fp) < 20)
    {
        ch = fgetc(fp);
        putchar(ch);
    }
    fclose(fp);
}

How does ftell(fp) work in the loop? Because there is nothing inside the loop that get it up. How it is progressive?

user16217248
  • 3,119
  • 19
  • 19
  • 37
  • 2
    There is `fgetc()` in the loop. That advances the file position, which is what `ftell()` reports. When the file is first opened in `"r"` mode, the file position is `0`. Each call to `fgetc()` will advance the file position by `1`. – Weather Vane May 31 '20 at 19:05
  • 2
    ... except in Windows environment with a file opened in text mode, where line endings are *two* characters and one of them is skipped. So you'll receive *one* character `'\n'` newline but the file pointer advances by `2`. – Weather Vane May 31 '20 at 19:15
  • Since it looks like this code may be taking advantage of implementation-specific behavior, can you tell us what platform this code is meant for? Any ideas about what it might be intended to do - how it is used, what kind of files it is used with? – Nate Eldredge May 31 '20 at 19:30

2 Answers2

0

ftell() gets you the current value of the position indicator of the stream(in your case, it basically returns the character position it is currently pointing to right now).

fgetc() gets the next character (an unsigned char) from the specified stream and advances the position indicator for the stream. This function returns the character read as an unsigned char cast to an int or EOF on end of file or error

Flow of your program

What that means in very simple terms is -

  • fgetc() is reading one character after character from the file and advancing the pointer to the next character.

  • ftell() is returning you the current position in in bytes from the beginning of the file. This means it tells the position of the character it is pointing right now(since 1 char takes 1 byte).

  • So, your program reads from the file until ftell() returns the position which is less than 20.This means that it will keep looping until 20 characters have been read from your file.

Hope this clears your doubt !

Community
  • 1
  • 1
Abhishek Bhagate
  • 5,583
  • 3
  • 15
  • 32
0

ftell returns the current value of the file position indicator, and fgetc does advance the file position indicator within the loop.


But this program is wrong. For a stream opened in text mode ("r"), the return value of ftell cannot be used portably for anything else except for seeking to a previous position. From C11 draft n1570 7.21.9.4p2

[...] For a text stream, its file position indicator contains unspecified information, usable by the fseek function for returning the file position indicator for the stream to its position at the time of the ftell call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.

Indeed it doesn't make any sense to use ftell in this program. Either open the file in binary mode, "rb", and then it is guaranteed that

[...] the value is the number of characters from the beginning of the file.

or for counting characters read from text file, use a counter variable:

int c_read = 0;
while (c_read < 20)
{
    ch = fgetc(fp);
    putchar(ch);
    c_read ++;
}

Finally neither your original version or mine does not work correctly if the file has less than 20 characters. In that case EOF is returned from fgetc and putchar would write (unsigned char)EOF to the stream (most likely a byte of value 255!)

Thus the correct code would be

int c_read = 0;
while (c_read < 20)
{
    ch = fgetc(fp);
    if (ch == EOF) {
        // report the error
        perror("Failed to read 20 characters");
        break;
    }
    putchar(ch);
    c_read ++;
}
  • "Wrong" might be an overstatement - the program may simply be relying on some non-portable behavior of `ftell` on a specific implementation. For instance, the CR/LF issue on Windows cited by Weather Vane in a comment above. In that case, the "correct" code you suggest would actually not work as desired. – Nate Eldredge May 31 '20 at 19:28
  • @NateEldredge: I can prove this program outputs some number of characters between 1 and 20. There aren't many valid implementations of ftell(). – Joshua Apr 06 '23 at 21:42