【问题标题】:Unexpected behavior in printing a char array in C在 C 中打印 char 数组时的意外行为
【发布时间】:2014-04-09 07:07:44
【问题描述】:

我最近在必须编写的一段代码中遇到了一个有趣的问题。尽管我使用与原始方法不同的方法解决了该问题,但我想看看是否有人知道为什么原始方法不起作用。这是压缩代码sn-ps。

原文代码:

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 语句进行验证。

【问题讨论】:

  • 仔细检查score_matrix的数组边界,记住每个索引都是从零开始的。
  • score_matrixnewlinex 是如何声明的?
  • ...x 是如何计算的?
  • result = strtok(NULL, " "); 是什么意思??
  • @wyas 太好了,现在阅读我的评论并理解为什么重用相同的行缓冲区并在其中存储偏移量(这都是 strotok 所做的;在提供的缓冲区中返回终止的子字符串)是 错误。这些行似乎报告的数据与 last 行相同,这绝非巧合。如果您仍然需要int 的数据,只需使用“固定”版本并避免只能通过动态分配(以及以后的动态清理)解决的问题。

标签: c


【解决方案1】:

您重复使用相同的行缓冲区是错误的。第一个样本的输出让你产生一种错误的成功感,而实际上它一点也不正确。修改循环以转储提取并保存的令牌的地址将显示以下证据:

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

【讨论】:

  • @wyas 很高兴它有帮助。严重地。如果您对此事有任何发言权,请使用int 解决方案(并且在使用它们之前检查您的lib-calls的返回值=P)
  • int 解决方案将继续存在,但我只是好奇为什么这一切都与chars 一起走下坡路。很高兴知道 C 和往常一样危险 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 2012-11-11
相关资源
最近更新 更多