尝试使用 strtok 时内存损坏
Memory corruption when attempting to use strtok
当我在我的微控制器上 运行 这段代码时,它在尝试在“price_right_of_period”上打印时崩溃。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DEBUG
char *str = ".45";
int main()
{
char *decimal_pos; // where the decimal place is in the string
char buffer[64]; // temporary working buffer
int half_price_auto_calc = 1;
// the cost of the product price difference for half price mode
int price_save_left, price_save_right = 0;
int price_half_left, price_half_right = 0;
// EG: let's say we get the string ".89"
char *price_left_of_period; // this will contain "2"
char *price_right_of_period; // this will contain "89"
// find where the decimal is
decimal_pos = strstr(str, ".");
if (decimal_pos != NULL)
{
printf("\nThe decimal point was found at array index %d\n", decimal_pos - str);
printf("Splitting the string \"%s\" into left and right segments\n\n", str);
}
// get everything before the period
strcpy(buffer, str); // copy the string
price_left_of_period = strtok(buffer, ".");
// if the dollar sign exists, skip over it
if (price_left_of_period[0] == '$') price_left_of_period++;
#ifdef DEBUG
printf("price_left_of_period = \"%s\"\n", price_left_of_period);
#endif
// get everything after the period
//
// strtok remembers the last string it worked with and where it ended
// to get the next string, call it again with NULL as the first argument
price_right_of_period = strtok(NULL, "");
#ifdef DEBUG
printf("price_right_of_period = \"%s\"\n\n", price_right_of_period);
#endif
if (half_price_auto_calc == 1)
{
// calculate the amount we saved (before the decimal)
price_save_left = atoi((const char *)price_left_of_period);
// halve the value if half price value is true
price_half_left = price_save_left / 2;
// calculate the amount we saved (before the decimal)
price_save_right = atoi((const char *)price_right_of_period);
// halve the value if half price value is true
price_half_right = price_save_right / 2;
#ifdef DEBUG
printf("price_half_left = \"%d\"\n", price_half_left);
printf("price_half_right = \"%d\"", price_half_right);
#endif
}
return 0;
}
代码 运行 在这里工作正常:https://onlinegdb.com/kDAw2cJyz。然而,如上所述,在我的 MCU 上它崩溃了(下图)。
有人知道为什么我的代码会导致这种情况发生吗?代码对我来说看起来不错,但从其他 C 专家那里得到第二意见总是很好 :)
解决方案:
Your code does have one bug. %d\n", decimal_pos - str
doesn't work because decimal_pos - str
has the wrong type to
print through %d. You need to cast it (I doubt that's causing the
crash but you can test by commenting it out and re-testing)
这里的代码确实有bug:
printf("\nThe decimal point was found at array index %d\n", decimal_pos - str);
2 个指针的差异具有类型 ptrdiff_t
,可能与 %d
预期的 int
不同。您应该使用 %td
或将差异转换为 (int)(decimal_pos - str)
。然而,令人惊讶的是,这种类型不匹配是导致您出现问题的原因。
请注意,您复制字符串时未在 strcpy(buffer, str);
中测试其长度,这对于此示例是可以的,但如果 str
指向更长的字符串,则可能会出现未定义的行为。
代码太复杂:不需要 strtok()
,因为您已经有了小数点的偏移量(如果有的话)。您可以将 atoi()
与指向整数部分开头的指针一起使用,而无需使用空字节修补 .
。您也可以使用 strtol()
来避免 strstr()
。
另请注意,在大多数情况下,代码会计算出错误的价格:".45"
将更改为 ".22"
,这大大超过了 50% 的回扣。
您应该将该数字转换为美分的整数并使用它来计算降价。
这是一个简化版本:
#include <stdio.h>
#include <stdlib.h>
int half_price_auto_calc = 1;
char *str = ".45";
int main() {
int cents;
char *p = str;
if (*p == '$')
p++;
// use strtol to convert dollars and cents
cents = strtol(p, &p, 10) * 100;
if (*p == '.') {
cents += strtol(p + 1, NULL, 10);
}
if (half_price_auto_calc) {
cents /= 2;
}
printf("reduced price: $%d.%02d\n", cents / 100, cents % 100);
return 0;
}
当我在我的微控制器上 运行 这段代码时,它在尝试在“price_right_of_period”上打印时崩溃。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DEBUG
char *str = ".45";
int main()
{
char *decimal_pos; // where the decimal place is in the string
char buffer[64]; // temporary working buffer
int half_price_auto_calc = 1;
// the cost of the product price difference for half price mode
int price_save_left, price_save_right = 0;
int price_half_left, price_half_right = 0;
// EG: let's say we get the string ".89"
char *price_left_of_period; // this will contain "2"
char *price_right_of_period; // this will contain "89"
// find where the decimal is
decimal_pos = strstr(str, ".");
if (decimal_pos != NULL)
{
printf("\nThe decimal point was found at array index %d\n", decimal_pos - str);
printf("Splitting the string \"%s\" into left and right segments\n\n", str);
}
// get everything before the period
strcpy(buffer, str); // copy the string
price_left_of_period = strtok(buffer, ".");
// if the dollar sign exists, skip over it
if (price_left_of_period[0] == '$') price_left_of_period++;
#ifdef DEBUG
printf("price_left_of_period = \"%s\"\n", price_left_of_period);
#endif
// get everything after the period
//
// strtok remembers the last string it worked with and where it ended
// to get the next string, call it again with NULL as the first argument
price_right_of_period = strtok(NULL, "");
#ifdef DEBUG
printf("price_right_of_period = \"%s\"\n\n", price_right_of_period);
#endif
if (half_price_auto_calc == 1)
{
// calculate the amount we saved (before the decimal)
price_save_left = atoi((const char *)price_left_of_period);
// halve the value if half price value is true
price_half_left = price_save_left / 2;
// calculate the amount we saved (before the decimal)
price_save_right = atoi((const char *)price_right_of_period);
// halve the value if half price value is true
price_half_right = price_save_right / 2;
#ifdef DEBUG
printf("price_half_left = \"%d\"\n", price_half_left);
printf("price_half_right = \"%d\"", price_half_right);
#endif
}
return 0;
}
代码 运行 在这里工作正常:https://onlinegdb.com/kDAw2cJyz。然而,如上所述,在我的 MCU 上它崩溃了(下图)。
有人知道为什么我的代码会导致这种情况发生吗?代码对我来说看起来不错,但从其他 C 专家那里得到第二意见总是很好 :)
解决方案:
Your code does have one bug.
%d\n", decimal_pos - str
doesn't work becausedecimal_pos - str
has the wrong type to print through %d. You need to cast it (I doubt that's causing the crash but you can test by commenting it out and re-testing)
这里的代码确实有bug:
printf("\nThe decimal point was found at array index %d\n", decimal_pos - str);
2 个指针的差异具有类型 ptrdiff_t
,可能与 %d
预期的 int
不同。您应该使用 %td
或将差异转换为 (int)(decimal_pos - str)
。然而,令人惊讶的是,这种类型不匹配是导致您出现问题的原因。
请注意,您复制字符串时未在 strcpy(buffer, str);
中测试其长度,这对于此示例是可以的,但如果 str
指向更长的字符串,则可能会出现未定义的行为。
代码太复杂:不需要 strtok()
,因为您已经有了小数点的偏移量(如果有的话)。您可以将 atoi()
与指向整数部分开头的指针一起使用,而无需使用空字节修补 .
。您也可以使用 strtol()
来避免 strstr()
。
另请注意,在大多数情况下,代码会计算出错误的价格:".45"
将更改为 ".22"
,这大大超过了 50% 的回扣。
您应该将该数字转换为美分的整数并使用它来计算降价。
这是一个简化版本:
#include <stdio.h>
#include <stdlib.h>
int half_price_auto_calc = 1;
char *str = ".45";
int main() {
int cents;
char *p = str;
if (*p == '$')
p++;
// use strtol to convert dollars and cents
cents = strtol(p, &p, 10) * 100;
if (*p == '.') {
cents += strtol(p + 1, NULL, 10);
}
if (half_price_auto_calc) {
cents /= 2;
}
printf("reduced price: $%d.%02d\n", cents / 100, cents % 100);
return 0;
}