程序读取文件,但"跳过"不应该跳过它们的行

时间:2016-01-20 12:41:14

标签: c struct

所以基本上我有一个程序可以读取文件的特定格式,如下所示:

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;
};

4 个答案:

答案 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)

  1. 空间不足@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);
    
  2. 检查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");
    }
    
  3. 代码将fscanf()fgets()混合。这通常是一个问题,因为许多格式过去不会消耗'\n`` and then a following fgets()simply reads just that one character. Reccomedn only using fgets()`。

  4. 也可能是其他重要问题。

答案 3 :(得分:0)

这是问题的根源。

在循环中阅读评论:

当读取行(读取注释时)不以#开头时,代码已经从输入文件读取宽度+高度值。

因此代码需要从already read行解析这些值。