[英]Program reads file but “skips” lines when they shouldn't be skipped
So basically I have a program that reads in a specific format of a file as shown: 所以基本上我有一个程序,可以读取文件的特定格式,如下所示:
P3
# CREATOR: GIMP PNM Filter Version 1.1
400 530
255
189
165
181
181
156
...
My program reads in the first line as the format of the file, then any comments starting with a '#', then the width and height, then the max rgb value and then any other rgb values. 我的程序在第一行中读取文件格式,然后以“#”开头的所有注释,然后是宽度和高度,然后是最大rgb值,然后是任何其他rgb值。
NOTE: the part reading in the rgb values is incomplete so ignore this for my question. 注意: rgb值中的零件读取不完整,因此请忽略此问题。 Now to my issue..
现在到我的问题。
The output i want is as shown as the exact file format, but the result i get is as follows: 我想要的输出显示为确切的文件格式,但是我得到的结果如下:
P3
# CREATOR: GIMP PNM Filter Version 1.1
255 189
165
As you can see, it completely skips the width and height values and uses the next 2 values in place of it for some reason... 如您所见,由于某种原因,它完全跳过了width和height值并使用接下来的2个值代替它。
Here is my code: 这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COMMENT_LENGTH 256
#define COMMENT_ARRAY_SIZE 10
#define MAX_PIXEL_HEIGHT 480
#define MAX_PIXEL_WIDTH 640
typedef struct PPM {
char format[2]; //2 letter code for PPM format
char comments[COMMENT_LENGTH][COMMENT_ARRAY_SIZE]; //comment array
int width; //number of columns
int height; //number of rows
int max; //maximum colour value (usually 255)
int rgbPixels[MAX_PIXEL_WIDTH * MAX_PIXEL_HEIGHT][3]; //integers between 0 and max for pixel i's RGB values
}PPM;
struct PPM * getPPM(FILE *fd);
int main(int argc, char **argv) {
FILE *file = fopen("ape.ppm", "r");
if(file == NULL) return 0;
else {
struct PPM *newPPM = getPPM(file);
return 0;
}
}
struct PPM * getPPM(FILE *fd) {
if(fd == NULL) {
return NULL;
}
struct PPM *newPPMFile = (PPM *) malloc(sizeof(PPM));
fscanf(fd, "%2s\n", newPPMFile->format);
printf("%2s\n", newPPMFile->format);
//check for comments
int i = 0;
char str[COMMENT_LENGTH];
while(i < COMMENT_ARRAY_SIZE && fgets(str, COMMENT_LENGTH, fd) != NULL) {
if(str[0] != '#') {
break;
} else {
strcpy(newPPMFile->comments[i], str);
printf("%s", newPPMFile->comments[i]);
}
}
//read width and height
fscanf(fd, "%d %d", &newPPMFile->width, &newPPMFile->height);
printf("%d %d\n", newPPMFile->width, newPPMFile->height);
//read max
fscanf(fd, "%d", &newPPMFile->max);
printf("%d\n", newPPMFile->max);
//read rgb data in rgb array (INCOMPLETE)
//close file
fclose(fd);
return newPPMFile;
};
There are a couple things here: 这里有几件事:
while(i < COMMENT_ARRAY_SIZE && fgets(str, COMMENT_LENGTH, fd) != NULL) {
if(str[0] != '#') {
break;
The position for the next read (offset) has already advanced, if you break or not. 如果不中断,则下一个读取(偏移)的位置已经提前。 So naturally, it'll continue at the advanced offset, like you experienced here.
因此,自然会像您在此处体验的那样,以高级偏移量继续。
Also, 也,
(PPM *) malloc(sizeof(PPM));
Casting the result of malloc()
is unnecessary and potentially masks errors. 强制转换
malloc()
的结果是不必要的,并且可能掩盖错误。
fgets
reads the full line into the buffer. fgets
将整行读入缓冲区。 It it doesn't begin with a hash mark, you lose the data on that line. 它不是以井号开头的,您会丢失该行上的数据。
A solution is to use fscanf
throughout. 一个解决方案是始终使用
fscanf
。 fscanf
stops scanning when the pattern isn't matched or if a conversion can't be made. 当模式不匹配或无法进行转换时,
fscanf
停止扫描。 So if you enforce a hash mark before the comment, but the line doesn't begin with a hash mark, the rest of the line is untouched: 因此,如果您在注释之前强制使用井号,但该行不是以井号开头,则其余部分保持不变:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int width, height, max;
char buf[80]; // temporary buffer
FILE *fd = fopen("kk", "r");
if(fd == NULL) return 1; // TODO: Error message
fscanf(fd, "%79s", buf);
if (strcmp(buf, "P3") != 0) return 1; // TODO: Error message
while (fscanf(fd, " # %79[^\n]%*[^\n]", buf) == 1) {
printf("Comment: %s\n", buf);
}
fscanf(fd, "%d %d", &width, &height); // TODO: Check success
printf("%d x %d\n", width, height);
fscanf(fd, "%d", &max); // TODO: Check success
printf("max: %d\n", max);
fclose(fd);
return 0;
}
There are some things to keep in mind, though: 不过,请记住以下几点:
fscanf
does not care or know about new lines; fscanf
不在乎或不知道fscanf
行; new-line characters are just white space. P3
. P3
在同一行。 EOF
or a string that isn't an integer, fscanf
gets stuck. EOF
或不是整数的字符串,则fscanf
会卡住。 %79[^\\n]
will read only up to 79 characters. %79[^\\n]
最多只能读取79个字符。 If the comment line is longer, the file position will not be on the new-line character, this srewing up the reading of subsequent lines. %*[^\\n]
after that: This will enforce that you read to the next new-line character, but it won't store the results. %*[^\\n]
:这将强制您读取到下一个换行符,但不会存储结果。 ( *
means "don't store result" in scanf
formats.) That way you get up to the first 80 characters of each comment line and also ensure that the line is read completely if it is longer. *
表示scanf
格式的“不存储结果”。)这样,您最多可以获取每条注释行的前80个字符,并且还可以确保较长的行可以完全读取。 Insufficient space @errikos . 空间不足@errikos 。
// char format[2]; //2 letter code for PPM format char format[2 + 1]; //2 letter code for PPM format ... // 2 is the max width of non-white-space characters to scan fscanf(fd, "%2s\\n", newPPMFile->format);
Check the return values form fscanf()
检查
fscanf()
的返回值
// fscanf(fd, "%d %d", &newPPMFile->width, &newPPMFile->height); if (fscanf(fd, "%d %d", &newPPMFile->width, &newPPMFile->height) != 2) { fprintf(stderr, "Error reading width & height\\n"); }
Code mixes fscanf()
with fgets()
. 代码将
fscanf()
与fgets()
。 Tis often is a problem as many formats used to not consume that trailing '\\n`` and then a following
fgets() simply reads just that one character. Reccomedn only using
Tis通常是一个问题,因为许多格式以前都不使用该结尾的
'\\n`` and then a following
fgets() simply reads just that one character. Reccomedn only using
simply reads just that one character. Reccomedn only using
fgets()`. simply reads just that one character. Reccomedn only using
fgets()推荐。
Possibly other important issues too. 可能还有其他重要问题。
here is the root of the problem. 这是问题的根源。
in the loop reading comments: 在循环中阅读评论:
when the line is read (when reading comments) that does not start with a #, then the code has already read width+height values from the input file. 当读取不是以#开头的行时(读取注释时),则该代码已从输入文件中读取width + height值。
So the code needs to parse those values from the already read
line. 因此,代码需要从
already read
行中解析这些值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.