I have code for processing a file having numbers at the beginning, which I have to read, and then letters. I need to print letters with index corresponding to the numbers at the beginning of the file, where the index is interpreted as position from the beginning of the file. For example, if the first number in the file is 10 then I need to print the tenth character of the file.
The problem is that when I use fscanf, after the first use, ftell gives a negative index of exactly -7 (where is having value -7). This makes the program stop on processing that letter, on account of the attempt to read that letter with scanf returning 0. Why?
#include <stdio.h>
int main() {
char letter;
int num;
long where;
FILE *fp;
if ((fp = fopen("chance.txt","r")) == NULL) {
printf("File corrupted");
return 1;
}
rewind(fp);
while (fscanf(fp,"%d",&num) == 1) {
where = ftell(fp);
fseek(fp,num,SEEK_SET);
letter = (char)fgetc(fp);
printf("%c", letter);
fseek(fp,where,SEEK_SET);
}
fclose(fp);
return 0;
}
The file could look like this
30 23 42
32
"Some text"
The whole file will never be shorter than the biggest index.
Your program compiles cleanly for me, unmodified, on Linux, and it behaves there exactly as you describe it should. I could not use the input file provided in the question for testing, however, because it does not satisfy the requirement that the length of the file be at least as great as the largest index within. (And actually, the length needs to exceed the largest index, even if only by 1 byte, because as the program is using them, the indexes are zero-based.)
If, in your environment, the program presented misbehaves when processing a valid input file, then that most likely arises from the fact that you open the file as a text stream, but use file-positioning functions in a way that is not wholly defined for text streams. POSIX systems do not distinguish between text and binary streams, but some other systems do, with Windows being a prime example.
Consider this code:
Given
fpreferring to a text stream, theftellis fine, and thefseek(fp,where,SEEK_SET)is also fine: as long as the stream is seekable in the first place, you can usefseekwithSEEK_SETto reposition it to a point that was previously recorded viaftell(). However, C does not define the meaning of seeking to an arbitrary position in a text stream, sofseek(fp,num,SEEK_SET)is not fine. That will work as intended on Linux (for example), but not necessarily on some other systems.One solution would be:
Open the file as a binary stream:
(note open mode
"rb"instead of"r").Ensure that the file has single-byte line terminators (at least if it is supposed to yield the same output on Windows as on Linux).
Additionally, even though it may seem tedious, it is wise to check the return values of all function calls that may indicate errors that way, so as to recognize those error signals if they come, and take appropriate action. Often that's just to report the nature of the error and perhaps its location, then terminate. You missed some. I'm not sure whether checking those would have given you useful information, but it might have done.
Side note: it is pointless (but not inherently wrong) to
rewind()a file immediately after opening it.