When I run this code on my microcontroller, it crashes when attempting to printf on "price_right_of_period".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DEBUG
char *str = "$3.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 "$2.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;
}
The code runs and works fine here:
Would anyone have any ideas why this might be happening as a result of my code? The code looks right to me but it's always nice to get a second opinion from other C experts :)
SOLUTION:
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)
CodePudding user response:
The code indeed has a bug here:
printf("\nThe decimal point was found at array index %d\n", decimal_pos - str);
The difference of 2 pointers has type ptrdiff_t
which may be different from int
expected for %d
. You should either use %td
or cast the difference as (int)(decimal_pos - str)
. It is however very surprising that this type mismatch be the cause of your problem.
Note that you copy the string without testing its length in strcpy(buffer, str);
which for this example is OK but might have undefined behavior if str
points to a longer string.
The code is too complicated: there is no need for strtok()
as you already have the offset to the decimal point if any. You can use atoi()
with a pointer to the beginning of the integral portion without patching the .
with a null byte. You could also use strtol()
to avoid strstr()
too.
Note also that the code will compute an incorrect price in most cases: "$3.45"
will be changed to "$1.22"
which is substantially more than a 50% rebate.
You should just convert the number as an integral number of cents and use that to compute the reduced price.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
int half_price_auto_calc = 1;
char *str = "$3.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.d\n", cents / 100, cents % 100);
return 0;
}