Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the array at Index 1 is resetting in my compiler? (Undefined Behavior)

I do not understand why my compiler (Microchip XC16) is providing a different result to other compilers.

Below is a sample code that I converted to run on general purpose machines rather than only on the pic33fj256gp710 that I am using. When running the code on the pic (Code example 2) I get a different result where the first array index is reset to 0 (Results 2).

Essentially the idea is to get a string command in through a serial port and configure the device based upon this by breaking apart a string and sorting it.

Is this because the compiler initially passes a pointer to the value until the string is cleared rather than passing the value itself? And how can I force the compiler to pass the value itself if this is the case?

Code Example 1:

char receive_data_2[100] = "XXXX,1,4,20,33,34";

int m = 4;
char intext[10];
int output_values[10];

int number_of_logger_selections = 0;
while(receive_data_2[m] != ' ' && number_of_logger_selections < 10)
{
    int a = 0;
    m++;
    strcpy(intext, "          ");
    do
    { // get parameter number
        intext[a++] = receive_data_2[m++];
    } while(receive_data_2[m] != ',' && receive_data_2[m] != ' ');

    output_values[number_of_logger_selections] = atoi(intext); // save output number to mark 'x'

    printf
        ("\nvalue at output_values[%d] = %d, intext = %s, translated to %d\r\n\n",
         number_of_logger_selections,
         output_values[number_of_logger_selections], intext, atoi(intext));

    number_of_logger_selections++;

    int i;
    for(i = 0; i < number_of_logger_selections; i++)
    {
        printf("value at output_values[%d] = %d\r\n", i, output_values[i]);
    }
}

Results 1:

value at output_values[0] = 1, intext = 1         , translated to 1

value at output_values[0] = 1

value at output_values[1] = 4, intext = 4         , translated to 4

value at output_values[0] = 1
value at output_values[1] = 4

value at output_values[2] = 20, intext = 20        , translated to 20

value at output_values[0] = 1
value at output_values[1] = 4
value at output_values[2] = 20

value at output_values[3] = 33, intext = 33        , translated to 33

value at output_values[0] = 1
value at output_values[1] = 4
value at output_values[2] = 20
value at output_values[3] = 33

value at output_values[4] = 34, intext = 34, translated to 34

value at output_values[0] = 1
value at output_values[1] = 4
value at output_values[2] = 20
value at output_values[3] = 33
value at output_values[4] = 34

Code Example 2:

int m = 4;
        char intext[10];
        int output_values[10];

        number_of_logger_selections = 0;
        while(receive_data_2[m] != ' ' && number_of_logger_selections < 10)
        {
            int a = 0;
            m++;
            strcpy(intext, "          ");
            do
            { // get parameter number
                intext[a++] = receive_data_2[m++];
            } while(receive_data_2[m] != ',' && receive_data_2[m] != ' ');

            output_values[number_of_logger_selections] = atoi(intext); // save output number to mark 'x'

            sprintf(transfer_data_2, "\nvalue at output_values[%d] = %d, intext = %s, translated to %d\r\n\n", number_of_logger_selections, output_values[number_of_logger_selections], intext, atoi(intext));
            SendSerialUserData(ANSI);

            number_of_logger_selections++;

            int i;
            for(i = 0; i < number_of_logger_selections; i++)
            {
                sprintf(transfer_data_2, "value at output_values[%d] = %d\r\n", i, output_values[i]);
                SendSerialUserData(ANSI);
            }
        }

Results 2:

value at output_values[0] = 1, intext = 1         , translated to 1

value at output_values[0] = 1

value at output_values[1] = 4, intext = 4         , translated to 4

value at output_values[0] = 0
value at output_values[1] = 4

value at output_values[2] = 20, intext = 20        , translated to 20

value at output_values[0] = 0
value at output_values[1] = 4
value at output_values[2] = 20

value at output_values[3] = 33, intext = 33        , translated to 33

value at output_values[0] = 0
value at output_values[1] = 4
value at output_values[2] = 20
value at output_values[3] = 33

value at output_values[4] = 34, intext = 34        , translated to 34

value at output_values[0] = 0
value at output_values[1] = 4
value at output_values[2] = 20
value at output_values[3] = 33
value at output_values[4] = 34
like image 984
GMoney Avatar asked Dec 07 '25 06:12

GMoney


2 Answers

intext is a buffer only 10 bytes long, but you're copying 11 bytes into it (10 spaces + 1 NUL terminator). You therefore get Undefined Behaviour, and the terminator probably overwrites whatever follows the buffer in memory. What that is can indeed depend on architecture, compiler, etc., which can explain why you're seeing differences when running on different HW. But remember, Undefined Behaviour is Undefined and anything could happen.

like image 144
Angew is no longer proud of SO Avatar answered Dec 09 '25 23:12

Angew is no longer proud of SO


Your code contains undefined behaviour.

char intext[10];

can hold 10 bytes, but

strcpy(intext, "          ");

will copy 10 spaces plus a string terminator.

What follows may seem strange or illogical, but that is one characteristic of UB - a fault appears at a different place from where the error was made.

like image 27
Weather Vane Avatar answered Dec 09 '25 23:12

Weather Vane