strtok 和分段错误问题

发布于 2024-11-06 01:47:01 字数 1402 浏览 1 评论 0原文

我有两个辅助函数来分解小数价格格式的字符串,即。 “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);
}

I have two helper functions to break up strings in the format of decimal prices ie. "23.00", "2.30"

Consider this:

char price[4] = "2.20";

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

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

Now when I run the below I get a segmentation fault:

printf("%u\n", getDollars(string));
printf("%u\n", getCents(string));

However when I run them seperately without one following the other, they work fine. What am I missing here? Do I have to do some sort of resetting of strtok??

My solution:

With the knowledge about strtok I gained from the answer I chose below, I changed the implementation of the helper functions so that they copy the passed in string first, thus shielding the original string and preventing this problem:

    #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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蒗幽 2024-11-13 01:47:01

由于 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。

Because strtok() modifies the input string, you run into problems when it fails to find the delimiter in the getCents() function after you call getDollars().

Note that strtok() returns a null pointer when it fails to find the delimiter. Your code does not check that strtok() found what it was looking for - which is always risky.


Your update to the question demonstrates that you have learned about at least some of the perils (evils?) of strtok(). However, I would suggest that a better solution would use just strchr().

First, we can observe that atoi() will stop converting at the '.' anyway, so we can simplify
getDollars() to:

unsigned getDollars(const char *price)
{
    return(atoi(price));
}

We can use strchr() - which does not modify the string - to find the '.' and then process the text after it:

unsigned getCents(const char *price)
{
    const char *dot = strchr(price, '.');
    return((dot == 0) ? 0 : atoi(dot+1));
}

Quite a lot simpler, I think.


One more gotcha: suppose the string is 26.6; you are going to have to work harder than the revised getCents() just above does to get that to return 60 instead of 6. Also, given 26.650, it will return 650, not 65.

苍景流年 2024-11-13 01:47:01

这:

char price[4] = "2.20";

省略 price 上的 nul 终止符。我认为您想要这样:

char price[5] = "2.20";

或者更好:

char price[] = "2.20";

因此,当您第二次尝试从 price 获取令牌时,您将耗尽缓冲区的末尾。您只是很幸运,getCents() 每次运行时都不会出现段错误。

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

This:

char price[4] = "2.20";

leaves out the nul terminator on price. I think you want this:

char price[5] = "2.20";

or better:

char price[] = "2.20";

So, you will run off the end of the buffer the second time you try to get a token out of price. You're just getting lucky that getCents() doesn't segfault every time you run it.

And you should almost always make a copy of a string before using strtok on it (to avoid the problem that Jonathan Leffler pointed out).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文