所以基本上我有一个程序可以读取文件的特定格式,如下所示:
P3
# CREATOR: GIMP PNM Filter Version 1.1
400 530
255
189
165
181
181
156
...
我的程序在第一行读取文件的格式,然后是以'#'开头的任何注释,然后是宽度和高度,然后是max rgb值,然后是任何其他rgb值
注意: rgb值中读取的部分不完整,请忽略此问题。现在我的问题..
我想要的输出如确切的文件格式所示,但我得到的结果如下:
P3
# CREATOR: GIMP PNM Filter Version 1.1
255 189
165
如您所见,它完全跳过宽度和高度值,并出于某种原因使用接下来的2个值代替它...
这是我的代码:
#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;
};
答案 0 :(得分:1)
这里有几件事情:
while(i < COMMENT_ARRAY_SIZE && fgets(str, COMMENT_LENGTH, fd) != NULL) {
if(str[0] != '#') {
break;
如果你破坏了,下一次读取(偏移)的位置已经提前了。很自然地,它会像你在这里经历的那样在高级偏移处继续。
另外,
(PPM *) malloc(sizeof(PPM));
投放malloc()
的结果是不必要的,可能会掩盖错误。
答案 1 :(得分:0)
fgets
将整行读入缓冲区。它不以哈希标记开头,你丢失了该行的数据。
解决方案是始终使用fscanf
。当模式不匹配或无法进行转换时,fscanf
会停止扫描。因此,如果您在注释之前强制执行哈希标记,但该行不以井号开头,则该行的其余部分不会受到影响:
#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;
}
但有些事情要记住:
fscanf
不关心或了解新线路;换行符只是空格。这意味着您的第一个哈希标记可能与文件格式P3
位于同一行。EOF
或不是整数的字符串,fscanf
会被卡住。%79[^\n]
最多只能包含79个字符。如果注释行较长,则文件位置不会出现在换行符上,这会使后续行的读取变得清晰。为了避免这种情况,您可以在此之后添加%*[^\n]
:这将强制您读取下一个换行符,但不会存储结果。 (*
表示“不存储scanf
格式的结果”。这样,您可以获得每个注释行的前80个字符,并确保在更长的时间内完整读取该行答案 2 :(得分:0)
空间不足@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);
检查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");
}
代码将fscanf()
与fgets()
混合。这通常是一个问题,因为许多格式过去不会消耗'\n`` and then a following
fgets()simply reads just that one character. Reccomedn only using
fgets()`。
也可能是其他重要问题。
答案 3 :(得分:0)
这是问题的根源。
在循环中阅读评论:
当读取行(读取注释时)不以#开头时,代码已经从输入文件读取宽度+高度值。
因此代码需要从already read
行解析这些值。