Egon Gilstrom Egon Gilstrom - 3 months ago 17
C Question

fgetc dropping characters when reading 2d pixel map with for loop

I am working on inputting a 2d pixel array from a PPM file with the one I am testing being of width and length 5. Also I am aware that in a ppm file that is rgb it has 3 color values not just one. I had forgotten that before I wrote this code, but the problem still persists even with the update to it and the problem still exists in the same way. I have simplified the problem to just the array as to isolate the problem. From what I can tell this seems to be both dropping characters and replacing some with new line characters as well. Any insight into why this is happening would be greatly appreciated and if I forgot to add something I will update this as soon as I am aware.

#include <stdio.h>

int main(int args, char *argv[]) {
int w = 5, h = 5;

FILE *f = fopen(argv[1], "rb");
int c = 'a';//I am setting this so as to avoid the off chance of c being defined as EOF
for(int i = 0; i < h && c != EOF; i++) {
for(int j = 0; j < w && (c = fgetc(f)) != EOF; j++) printf("%c", c);
fgetc(f);//To remove the '\n' character I am not using fgets because it stops at '\n' character and it is possible for a rgb value to be == to '\n'
printf("\n");
}
fclose(f);
return 0;
}


Test File I am using:

12345
abcde
12345
abcde
12345


Output I am getting:

12345

abcd

123
5
ab
de
1


Thanks in advance!

Edit: This is running on the windows 10 command prompt

Answer

The problem is that '\n' on a Windows machine actually ends up producing two characters, a carriage return (ASCII code 13) and a line feed (ASCII code 10). When you open a file in binary mode, those line endings are not translated back to a single character. You're only accounting for one of these characters, so you're getting off by a character on each line you read.

To illustrate this, replace your printf("%c", c);" with printf("%d ", c);. I get the following output:

49 50 51 52 53 
10 97 98 99 100 
13 10 49 50 51 
53 13 10 97 98 
100 101 13 10 49

You can see those 10s and 13s shifting through.

Now try adding a second fgetc(f); to eat the line feed and it will work much better. Keep in mind, however, that this only works on files with CRLF line endings. Port it to Linux or Mac and you will have more troubles.

Comments