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

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

原始代码:

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]; ,它是int score_matrix[10][x][y];
  • newline – > char newline[1024];
  • result – > char* result;
  • 此外,结果已通过printf语句validation。

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

 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分配,将整个文件作为单个动态字符缓冲区加载到内存中,并大大改变您的解析循环,但我建议甚至比我建议的单令牌动态分配方法更少。