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

因为strtok()修改了输入字符串,所以在调用getDollars()后无法在getCents()函数中找到分隔符时会遇到问题。

请注意, strtok()在找不到分隔符时返回空指针。 您的代码不会检查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。

这个:

 char price[4] = "2.20"; 

price上省略了nul终结者。 我想你想要这个:

 char price[5] = "2.20"; 

或更好:

 char price[] = "2.20"; 

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

在使用strtok之前,你几乎应该总是复制一个字符串(以避免Jonathan Leffler指出的问题)。