strtok存在问题,导致出现分段错误

6
我有两个辅助函数,用于分解十进制价格格式的字符串,例如“23.00”,“2.30”。
考虑以下内容:
char price[4] = "2.20";

    unsigned getDollars(char *price)
    {
       return atoi(strtok(price, "."));
    }

    unsigned getCents(char *price)
    {
       strtok(price, ".");
       return atoi(strtok(NULL, "."));
    }

现在当我运行下面的代码时,会出现分段错误:
printf("%u\n", getDollars(string));
printf("%u\n", getCents(string));

然而,当我分别运行它们而不是一个接一个地运行时,它们可以正常工作。我错过了什么?我需要重置strtok吗?

我的解决方案:

根据我从下面选择的答案所获得的关于strtok的知识,我改变了辅助函数的实现方式,这样它们首先复制传递进来的字符串,从而保护原始字符串并防止出现这个问题:

    #define MAX_PRICE_LEN 5 /* Assumes no prices goes over 99.99 */

unsigned getDollars(char *price)
{
   /* Copy the string to prevent strtok from changing the original */
   char copy[MAX_PRICE_LEN];
   char tok[MAX_PRICE_LEN];

   /* Create a copy of the original string */
   strcpy(copy, price);

   strcpy(tok, strtok(copy, "."));

   /* Return 0 if format was wrong */
   if(tok == NULL) return 0;
   else return atoi(tok);
}

unsigned getCents(char *price)
{
   char copy[MAX_PRICE_LEN];
   char tok[MAX_PRICE_LEN];
   strcpy(copy, price);

   /* Skip this first part of the price */
   strtok(copy, ".");
   strcpy(tok, strtok(NULL, "."));

   /* Return 0 if format was wrong */
   if(tok == NULL) return 0;
   else return atoi(tok);
}
2个回答

5
因为strtok()会修改输入字符串,所以在调用getDollars()后,在getCents()函数中无法找到分隔符时,会遇到问题。
请注意,当strtok()未能找到分隔符时,它会返回一个空指针。您的代码没有检查strtok()是否找到了它要查找的内容 - 这是非常危险的。
您对问题的更新表明您已经了解了strtok()的某些危险之处。然而,我建议更好的解决方案是只使用strchr()
首先,我们可以观察到atoi()将在'.'处停止转换,因此我们可以简化getDollars()如下:
unsigned getDollars(const char *price)
{
    return(atoi(price));
}

我们可以使用不修改字符串的strchr()函数来找到'.',然后处理它之后的文本。
unsigned getCents(const char *price)
{
    const char *dot = strchr(price, '.');
    return((dot == 0) ? 0 : atoi(dot+1));
}

我认为这要简单得多。


还有一个陷阱:假设字符串是26.6;你需要比上面修改后的getCents()更加努力,才能让它返回60而不是6。此外,对于26.650,它将返回650而不是65。


谢谢你的建议,我已经采纳了。 - Chris

5

This:

char price[4] = "2.20";

price上省略了空终止符。我认为你想要这样:

char price[5] = "2.20";

更好的做法是:
char price[] = "2.20";

因此,第二次尝试从price获取令牌时,您将超出缓冲区的末尾。您只是幸运地得到getCents()不会每次运行时都 segfault。

而且,在使用strtok之前,您几乎总是要复制字符串(以避免Jonathan Leffler指出的问题)。


我认为两个答案/问题都是因素。我的问题是在同一个字符串上(重新)使用strtok()的通用问题。你的情况是这个特定的非字符串的特例。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接