fscanf 读取 7 行中的 1 行错误

fscanf reads one line out of 7 wrong

我有一个压缩文本文件,其中包含 7 行很长的文本,其中包含用于解码 JPEG 编码文件的信息。

当我尝试用我的 C 程序逐行读取解压缩的文件时,fscanf,我正确地读取了前 3 行和后 3 行,只有第 4 行没有被读取为符合预期的字符串。

第4行的输出是一个很长的字符串,里面填满了10

如果我用记事本或十六进制编辑器查看输入文件,一切看起来都很好。 如果我手动创建一个具有相同结构(但行较短)的文本文件,fscanf 工作正常。 使用我的程序解压缩文件或手动解压缩文件没有区别。

FILE *tmpdata;
char enc_path[256];
int arrsize;
// Building the absolute Path
sprintf(enc_path, "%s%stmp.txt", dest, src_name);

arrsize = unzip(); // gives back size of the file

// not the best way to create the output strings, 
// but I don't know the size of the lines.

char masse[10];
char ytabelle[arrsize / 3];
char cbtabelle[arrsize / 3];
char crtabelle[arrsize / 2];
char ywerte[arrsize  /3];
char cbwerte[arrsize / 3];
char crwerte[arrsize / 3];

if ((tmpdata = fopen(enc_path, "r")) == NULL) {
    printf("Error: can´t read input file\n");
    return EXIT_FAILURE;
}

fscanf(tmpdata, "%s %s %s  %s %s %s %s", masse, ytabelle, cbtabelle, crtabelle, ywerte, cbwerte, crwerte);

输入文件如下所示:

512x512
Y{42:110000;13:111000;...;0:0;}
CB{42:110000;13:111000;...;0:0;}
CR{42:110000;13:111000;...;0:0;}
000111010010111001110000111100011...
100011011101110001101000011100110...
100011101110110111011001100111011...

如果我打印单独的字符串:

512x512
Y{42:110000;13:111000;...;0:0;}
CB{42:110000;13:111000;...;0:0;}
111001111111111000110000111111000...
000111010010111001110000111100011...
100011011101110001101000011100110...
100011101110110111011001100111011...

也许可以避免堆栈分配??

char masse[10];
char *ytabelle  = malloc(arrsize/3); if (!ytabelle)  exit(EXIT_FAILURE);
char *cbtabelle = malloc(arrsize/3); if (!cbtabelle) exit(EXIT_FAILURE);
char *crtabelle = malloc(arrsize/2); if (!crtabelle) exit(EXIT_FAILURE);
char *ywerte    = malloc(arrsize/3); if (!ywerte)    exit(EXIT_FAILURE);
char *cbwerte   = malloc(arrsize/3); if (!cbwerte)   exit(EXIT_FAILURE);
char *crwerte   = malloc(arrsize/3); if (!crwerte)   exit(EXIT_FAILURE);

/* use as before */

free(ytabelle);
free(cbtabelle);
free(crtabelle);
free(ywerte);
free(cbwerte);
free(crwerte);

您的程序无法正常运行的原因有多种:

  • 您可能会为自动存储分配太多数据(又名在堆栈上),导致不稳定的行为。

  • 文件中的字符串可能包含嵌入的 spaces,导致 fscanf() 读取单词而不是行。

  • 您没有告诉 fscanf() 目标数组的大小。 fscanf() 可能会将数据存储到目标数组的末尾之外,溢出到下一个数组(这可以解释观察到的行为)或导致其他一些未定义的行为。

当目标数组不是简单常量时,传递目标数组的大小非常麻烦。我建议你使用 fgets() 而不是 fscanf() 来读取文件内容并将 malloc() 的数组分配到更大的大小以避免问题:

    FILE *tmpdata;
    char enc_path[256];
    size_t arrsize;

    // Building the absolute path
    snprintf(enc_path, sizeof enc_path, "%s%stmp.txt", dest, src_name);

    arrsize = unzip(); // gives back size of the file

    // not the best way to create the output strings, 
    // but I don't know the size of the lines.

    char masse[16];
    size_t ytabelle_size = arrsize + 2;
    size_t cbtabelle_size = arrsize + 2;
    size_t crtabelle_size = arrsize + 2;
    char *ytabelle = malloc(ytabelle_size);
    char *cbtabelle = malloc(cbtabelle_size);
    char *crtabelle = malloc(crtabelle_size);
    size_t ywerte_size = arrsize + 2;
    size_t cbwerte_size = arrsize + 2;
    size_t crwerte_size = arrsize + 2;
    char *ywerte = malloc(ywerte_size);
    char *cbwerte = malloc(cbwerte_size);
    char *crwerte = malloc(crwerte_size);

    if (!ytabelle ||!cbtabelle ||!crtabelle ||!ywerte ||!cbwerte ||!crwerte) {
        printf("Error: cannot allocate memory\n");
        return EXIT_FAILURE;
    }

    if ((tmpdata = fopen(enc_path, "r")) == NULL) {
        printf("Error: cannot open input file\n");
        return EXIT_FAILURE;
    }

    if (!fgets(masse, sizeof masse, tmpdata)
    ||  !fgets(ytabelle, ytabelle_size, tmpdata)
    ||  !fgets(cbtabelle, cbtabelle_size, tmpdata)
    ||  !fgets(crtabelle, crtabelle_size, tmpdata)
    ||  !fgets(ywerte, ywerte_size, tmpdata)
    ||  !fgets(cbwerte, cbwerte_size, tmpdata)
    ||  !fgets(crwerte, crwerte_size, tmpdata)) {
        printf("Error: cannot read input file\n");
        return EXIT_FAILURE;
    }
    // file contents were read, arrays should have a trailing newline, which
    // you should strip or handle in the decoding phase.
    ...

如果您使用的是 GNUlibc 或一些现代 Posix 系统,您可以在 fscanf() 中使用 m 前缀来为从中读取的单词分配 space文件。使用这个允许更简单但不可移植的解决方案:

    FILE *tmpdata;
    char enc_path[256];
    size_t arrsize;

    // Building the absolute path
    snprintf(enc_path, sizeof enc_path, "%s%stmp.txt", dest, src_name);

    arrsize = unzip(); // gives back size of the file

    // not the best way to create the output strings, 
    // but I don't know the size of the lines.

    char masse[16];
    char *ytabelle = NULL;
    char *cbtabelle = NULL;
    char *crtabelle = NULL;
    char *ywerte = NULL;
    char *cbwerte = NULL;
    char *crwerte = NULL;

    if ((tmpdata = fopen(enc_path, "r")) == NULL) {
        printf("Error: cannot open input file\n");
        return EXIT_FAILURE;
    }

    if (fscanf(tmpdata, "%ms %ms %ms %ms %ms %ms %ms", &masse,
               &ytabelle, &cbtabelle, &crtabelle,
               &ywerte, &cbwerte, &crwerte) != 7) {
        printf("Error: cannot read input file\n");
        return EXIT_FAILURE;
    }
    ...

PS: 与德语不同,英语名词首字母不大写,语言、人名、地名等例外