C - 使用 strtok 的分段错误



我有这段代码,它读取多个文件并打印某个值。读取文件后,在某个时刻我的while循环停止并显示分段错误...

这是我的代码

int main () {
const char s[2] = ",";
const char s2[2] = ":";
char var1[] = "fiftyTwoWeekHigh"";
char *fiftyhigh;
char *fiftyhigh2;
char *fiftyhigh_token;
char *fiftyhigh2_token;

char var2[] = "fiftyTwoWeekLow"";
char *fiftylow;
char *fiftylow2;
char *fiftylow_token;
char *fiftylow2_token;
char var3[] = "regularMarketPrice"";
char *price;
char *price2;
char *price_token;
char *price2_token;

FILE *fp;
char* data = "./data/";
char* json = ".json";
char line[MAX_LINES];
char line2[MAX_LINES];
int len;
char* fichier = "./data/indices.txt";
fp = fopen(fichier, "r");
if (fp == NULL){
printf("Impossible d'ouvrir le fichier %s", fichier);
return 1;
}
while (fgets(line, sizeof(line), fp) != NULL) {
char fname[10000];
len = strlen(line);
if (line[len-1] == 'n') {
line[len-1] = 0;
}

int ret = snprintf(fname, sizeof(fname), "%s%s%s", data, line, json);
if (ret < 0) {
abort();
}
printf("%sn", fname);

FILE* f = fopen(fname, "r");
while ( fgets( line2, MAX_LINES, f ) != NULL ) {
fiftyhigh = strstr(line2, var1);
fiftyhigh_token = strtok(fiftyhigh, s);
fiftyhigh2 = strstr(fiftyhigh_token, s2);
fiftyhigh2_token = strtok(fiftyhigh2, s2);
printf("%sn", fiftyhigh2_token);
fiftylow = strstr(line2, var2);
fiftylow_token = strtok(fiftylow, s);
fiftylow2 = strstr(fiftylow_token, s2);
fiftylow2_token = strtok(fiftylow2, s2);
printf("%sn", fiftylow2_token);
price = strstr(line2, var3);
price_token = strtok(price, s);
price2 = strstr(price_token, s2);
price2_token = strtok(price2, s2);
printf("%sn", price2_token);

//printf("n%st%st%st%st%s", line, calculcx(fiftyhigh2_token, price2_token, fiftylow2_token), "DIV-1", price2_token, "test");

}
fclose(f);
}
fclose(fp);
return 0;
}

输出为:

./data/k.json
13.59
5.31
8.7
./data/BCE.json
60.14
46.03
56.74
./data/BNS.json
80.16
46.38
78.73
./data/BLU.json
16.68
2.7
Segmentation fault

这就像我的程序停止了,因为它无法访问某个文件的特定数据......有没有办法分配更多内存?因为我的MAX_LINES已经设置为 6000。

我假设文件中的行如下所示:

{"fiftyTwoWeekLow":32,"fiftyTwoWeekHigh":100, ... }

换句话说,它是某种JSON格式。我假设该行以"{"开头,因此每一行都是一个 JSON 对象。

您将该行读入line2中,现在包含:

{"fiftyTwoWeekLow":32,"fiftyTwoWeekHigh":100, ... }

请注意末尾终止字符串的。另请注意,"fiftyTwoWeekLow"排在第一位,事实证明这非常重要。

现在让我们在这里跟踪代码:

fiftyhigh = strstr(line2, var1);
fiftyhigh_token = strtok(fiftyhigh, s);

首先,您致电strstr以找到"五十二周高点"的位置。这将返回指向该字段名称在行中的位置的指针。然后调用strtok以查找将此值与下一个值分隔的逗号。我认为这是事情开始出错的地方。调用strtok后,line2如下所示:

{"fiftyTwoWeekLow":32,"fiftyTwoWeekHigh":100 ... }

请注意,strtok修改了字符串:逗号已替换为。这样您就可以将返回的指针fiftyhigh_token用作字符串,而无需查看逗号后面的所有内容。

fiftyhigh2 = strstr(fiftyhigh_token, s2);
fiftyhigh2_token = strtok(fiftyhigh2, s2);
printf("%sn", fiftyhigh2_token);

接下来,查找冒号,然后使用指向冒号的指针调用strtok。由于您要传递给strok的分隔符是冒号,因此strtok忽略冒号并返回下一个标记,该标记(因为我们正在查看的字符串在"100"之后结束,没有更多的冒号)是字符串的其余部分,换句话说,数字。

所以你已经得到了你的号码,但可能不是你预期的方式?第二次调用strtok实际上没有意义,因为(假设 JSON 格式正确)"100"的位置只是fiftyhigh2+1

现在我们尝试找到"五十二周低点":

fiftylow = strstr(line2, var2);
fiftylow_token = strtok(fiftylow, s);
fiftylow2 = strstr(fiftylow_token, s2);
fiftylow2_token = strtok(fiftylow2, s2);
printf("%sn", fiftylow2_token);

这基本上是相同的过程,调用strtok后,line2如下:

{"fiftyTwoWeekLow":32"fiftyTwoWeekHigh":100 ... }

请注意,您只能找到"fiftyTwoWeekLow",因为它位于行中的"fiftyTwoWeekHigh"之前。如果它是在之后,那么你将无法找到它,因为之前在"五十二周高"之后添加了。在这种情况下,strstr会返回 NULL,这将导致strtok返回 NULL,然后您肯定会在将 NULL 传递给strstr后出现 seg 错误。

因此,代码对字段在行中的显示顺序非常敏感,并且可能会失败,因为某些行的字段顺序不同。或者,也许某些行中缺少某些字段,这将具有相同的效果。

如果要解析 JSON,则实际上应该使用为此目的设计的库。但是,如果您真的想使用strtok那么您应该:

  1. 阅读line2.
  2. 调用strtok(line2, ",")一次,然后在循环中重复调用strtok(NULL, ","),直到返回 null。这会将行分解为每个看起来像"someField":100的令牌。
  3. 将字段名称和值与每个标记隔离开来(只需调用strchr(token, ':')即可查找值)。不要在此处调用strtok,因为它会更改strtok的内部状态,并且您将无法使用strtok(NULL, ",")继续处理该行。
  4. 测试字段名称,并根据其值设置适当的变量。换句话说,如果是"fiftyTwoWeekLow"字段,请设置一个名为 fiftyTwoWeekLow 的变量。您不必费心去掉引号,只需将它们包含在您正在比较的字符串中即可。
  5. 处理完所有令牌(strtok返回 NULL)后,对设置的变量执行一些操作。

您可能要传递",{}"作为分隔符strtok,以摆脱围绕该行的任何左大括号和右大括号。或者,您可以在每个令牌中查找它们,并在它们出现时忽略它们。

您也可以将""{},:"作为分隔符传递给strtok。这将导致strtok发出交替的字段名称和值序列。您可以调用strtok一次以获取字段名称,再次调用以获取值,然后测试字段名称并对该值执行某些操作。

使用strtok是一种非常原始的解析 JSON 的方法,但只要您的 JSON 仅包含简单的字段名称和数字,并且不包含任何本身包含分隔符字符的字符串,它就可以工作。

  • 你的意思是"\0"吗?
if (line[len-1] == 'n') {
line[len-1] = 0;
}

我建议您使用gdb来查看段错误发生的位置以及原因。 我认为您不必分配更多内存。但是段错误可能会发生,因为您不再有数据,并且您仍然打印结果。

例如,使用if(price2_token!=NULL) printf("%sn", price2_token);

相关内容

  • 没有找到相关文章

最新更新