strtok 和分段错误问题
我有两个辅助函数来分解小数价格格式的字符串,即。 “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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于
strtok()
会修改输入字符串,因此在调用getDollars()< 后无法在
getCents()
函数中找到分隔符时,您会遇到问题/代码>。请注意,当
strtok()
找不到分隔符时,它会返回一个空指针。您的代码不会检查strtok()
是否找到了它正在寻找的内容 - 这总是有风险的。您对问题的更新表明您至少已经了解了
strtok()
的一些危险(邪恶?)。不过,我建议更好的解决方案是仅使用strchr()
。首先,我们可以观察到
atoi()
无论如何都会在“.
”处停止转换,因此我们可以简化getDollars()
到:我们可以使用
strchr()
(它不会修改字符串)来查找'.'
,然后处理后面的文字:我认为简单多了。
还有一个问题:假设字符串是 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 thegetCents()
function after you callgetDollars()
.Note that
strtok()
returns a null pointer when it fails to find the delimiter. Your code does not check thatstrtok()
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 juststrchr()
.First, we can observe that
atoi()
will stop converting at the '.
' anyway, so we can simplifygetDollars()
to:We can use
strchr()
- which does not modify the string - to find the'.'
and then process the text after it: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.这:
省略
price
上的 nul 终止符。我认为您想要这样:或者更好:
因此,当您第二次尝试从
price
获取令牌时,您将耗尽缓冲区的末尾。您只是很幸运,getCents()
每次运行时都不会出现段错误。而且您几乎总是应该在对字符串使用
strtok
之前先复制该字符串(以避免 Jonathan Leffler 指出的问题)。This:
leaves out the nul terminator on
price
. I think you want this:or better:
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 thatgetCents()
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).