在C中打印char数组时出现意外行为

时间:2014-04-09 07:07:45

标签: c

我最近在一段代码中遇到了一个有趣的问题。虽然我使用与原始方法不同的方法解决了这个问题,但我想看看是否有人知道为什么原来的方法不起作用。以下是精简代码片段。

原始代码:

int i, j, k;
for (i=0; i!=10, (result = fgets(newline, 1024, stream))!=NULL; i++)
{
    result = strtok(newline, " ");
    for (j=0; j!=x; j++) {
        for (k=0; k!=y; k++) {
            score_matrix[i][j][k] = result;
             printf("%d ", atoi(score_matrix[i][j][k]));
            result = strtok(NULL, " ");
        }
    }
     printf("\n");
}

在上面的代码中,`stream'是一个CSV文件。无论如何,上面的代码打印出CSV文件,因为它应该是:

19 17 20 18 
9 6 10 9 
12 11 10 16 
3 7 9 10 
0 5 8 6 
15 13 15 15 
20 18 18 16 
17 19 19 18 
13 15 14 12 
10 13 18 15 

但是,当我使用与上面相同的相同的代码时,只删除一些不相关的行:

int i, j, k;
for (i=0; i!=10; i++) {
    for (j=0; j!=x; j++) {
        for (k=0; k!=y; k++) {
            printf("%d ", atoi(score_matrix[i][j][k]));
        }
    }
    printf("\n");
}

打印出来:

10 13 18 15 
10 0 3 8 
10 13 18 15 
10 0 3 18 
10 0 3 18 
10 13 18 15 
10 13 18 15 
10 13 18 15 
10 13 18 15 
10 13 18 15 

这是非常错误的。 固定代码(除了将矩阵转换为int并删除atoi之外):

int i, j, k;
for (i=0; i!=10, (result = fgets(newline, 1024, stream))!=NULL; i++)
{
    result = strtok(newline, " ");
    for (j=0; j!=x; j++) {
        for (k=0; k!=y; k++) {
            score_matrix[i][j][k] = atoi(result);
            printf("%d ", score_matrix[i][j][k]);
            result = strtok(NULL, " ");
        }
    }
    printf("\n");
}

int i, j, k;
for (i=0; i!=10; i++) {
    for (j=0; j!=x; j++) {
        for (k=0; k!=y; k++) {
            printf("%d ", score_matrix[i][j][k]);
        }
    }
    printf("\n");
}

现在两个都打印正确的东西:

19 17 20 18 
9 6 10 9 
12 11 10 16 
3 7 9 10 
0 5 8 6 
15 13 15 15 
20 18 18 16 
17 19 19 18 
13 15 14 12 
10 13 18 15

也许我在这里遗漏了一些明显的东西,但我很好奇为什么会这样。

编辑:

  • x - >通过论证传递。在这种情况下,它是2。
  • score_matrix - >好的代码是char* score_matrix[10][x][y];,好的是int score_matrix[10][x][y];
  • newline - > char newline[1024];
  • result - > char* result;
  • 此外,结果已通过printf语句验证。

1 个答案:

答案 0 :(得分:2)

重复使用相同的行缓冲区是错误的。第一个样本的输出正在让你陷入虚假的成功感,而实际上它是任何东西都是正确的。修改循环以转储提取和保存的令牌的地址将显示以下证据:

score_matrix[i][j][k] = result;
printf("%p ", result);
result = strtok(NULL, " ");

您会看到输出多维数据集中的许多令牌共享相同的缓冲区地址,这当然是因为您为每个标记化传递了相同的行缓冲区newline,并且在此过程中删除了内容在任何先前的循环中。

如果您想存储实际的char *,除非您必须不要。而是执行您的固定版本之一:转换为int并将int存储为矩阵值。否则你需要这样的东西来加载:

int i, j, k;
for (i=0; i!=10, (result = fgets(newline, 1024, stream))!=NULL; i++)
{
    result = strtok(newline, " ");
    for (j=0; j!=x; j++) {
        for (k=0; k!=y; k++) {
            score_matrix[i][j][k] = strdup(result); // NOTE: POSIX strdup() function
            printf("%d ", atoi(score_matrix[i][j][k]));
            result = strtok(NULL, " ");
        }
    }
     printf("\n");
}

以后需要对所有动态分配进行hella-cleanup。您可以进行单个mondo分配,将整个文件作为单个动态字符缓冲区加载到内存中并大大改变您的解析循环,但我建议甚至比我建议单令牌动态分配更少方法