c - 在 C 中 strtok() 适用于“,”(逗号),但不适用于空格“”。使用空格时出现段错误
问题描述
我是新来的。这是我的第一篇文章!所以我用 C 编写了代码来接收一个逗号分隔的文本文件并将其读入一个二维数组。我为此使用了 strtok() 。有效。下面是代码:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
FILE *data = fopen(argv[1], "r");
if (data == NULL)
{
printf("Could not open 11.txt\n");
return 1;
}
char table[20][20][3];
char buffer[60];
int i = 0;
while (fscanf(data, "%s", buffer) != EOF)
{
int j = 0;
for (char *s = strtok(buffer, ","); s != NULL; s = strtok(NULL, ","))
{
for (int k = 0; k < strlen(s) + 1; k++)
{
table[i][j][k] = s[k];
}
j++;
}
i++;
}
printf("%s\n", table[19][0]);
return 0;
}
我试图读入二维数组的数据如下所示:
08,02,22,97
49,49,99,40
81,49,31,73
52,70,95,23
它是一个 20x20 矩阵,数字用逗号分隔。上面的程序工作正常(我打印出这个二维数组的一个元素来检查程序是否工作)。但是当数字用空格分隔时:
08 02 22 97
49 49 99 40
81 49 31 73
52 70 95 23
当我在 strtok() 函数中用“”替换“,”时,我得到一个段错误。我不知道为什么会这样。感谢您的帮助!
编辑: 错误已修复! 来自莫斯科的@Vlad 非常正确地指出 fcanf() 不是用于将带有空格的字符串读入缓冲区的正确函数。他建议改用可以读取空白的 fgets() 。我仍然面临段错误,因为 strtok() 返回的第一个令牌是指向 NULL 的指针。我不确定为什么要这样做,因为当我在如图所示的 while 循环中不使用 fgets() 给 strtok() 提供一个具有相同字符串的数组时,没有任何问题:
char str[] = "08 02 22 97";
因此,为了解决这个问题,如果 strtok() 返回 NULL 指针,我在 for 循环中设置了一个条件以跳到下一次迭代。第二个问题是我的缓冲区不够大(空格是 4 个字节,而 char 是 1 个字节)。解决了这两个问题,我的代码就可以工作了!
以下是更正后的代码:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
FILE *data = fopen(argv[1], "r");
if (data == NULL)
{
printf("Could not open 11.txt\n");
return 1;
}
char table[20][20][3];
char buffer[61];
int i = 0;
while (fgets(buffer, sizeof(buffer), data) != NULL)
{
int j = 0;
for (char *s = strtok(buffer, " "); s != NULL; s = strtok(NULL, " "))
{
if (s == NULL)
{
continue;
}
else
{
for (int k = 0; k < strlen(s) + 1; k++)
{
table[i][j][k] = s[k];
}
j++;
}
}
i++;
}
printf("%i\n", atoi(table[19][19]));
return 0;
}
解决方案
fscanf
带有格式说明符的函数%s
读取数据,直到遇到空白字符。因此,您不能fscanf
像在 while 语句中使用它一样使用该函数
while (fscanf(data, "%s", buffer) != EOF)
读取包含嵌入空格的字符串。
而是使用标准 C 函数fgets
。
注意那个而不是这个for循环
for (int k = 0; k < strlen(s) + 1; k++)
{
table[i][j][k] = s[k];
}
strcpy
例如,您可以使用标准字符串函数
strcpy( table[i][j], s );
还有这个电话
printf("%s\n", table[20][0]);
调用未定义的行为,因为对于声明为
char table[20][20][3];
第一个索引的有效范围是]0, 20)。也就是说,您可能不会使用值 20 作为索引。
推荐阅读
- java - HERE 映射 Android:RouteManager 类在哪里?
- mysql - laravel api 返回空值
- routes - Laravel 5.5 - 使用 Route::resource 在 URL 中传递变量?
- python-3.x - 如何在 Python 中求解三个二次微分方程?
- php - PHP多维数组SQL请求到JSON
- android - 在回收站视图android中回扫后无法清除部分滑动删除按钮
- c# - 如何仅使用 Automapper 的接口映射两个对象?
- haskell - 不能使用美元 ($) 代替括号
- javascript - 如何在图像幻灯片上放置黑色叠加层
- python - 如何从python中的uuid中提取时间信息