Home > Mobile >  Memory corruption when attempting to use strtok
Memory corruption when attempting to use strtok

Time:01-01

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: MCU printf crash

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

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;
}
  • Related