Search code examples
ccastingpointer-arithmetic

Unable to pass integer array as argument to function whose local argument is character pointer


I have a main function that declares an integer array. I want to pass this array to a function whose parameter is of type char *. I cannot alter the signature of the called function.

My aim is to copy the contents of main's integer array data1 into disp's integer array data2, but when I try the following code, I get incorrect values. data2[0]= 10,data2[1]= 0,data2[2]= 0,data2[3]= 0,data2[4]= 20.

How can I correct it to yield data2[0]= 10,data2[1]= 20,data2[2]= 30,data2[3]= 40,data2[4]= 50 ?

Note: It is not mandatory that data2 be the same size as data1. It could be the same size or larger. I expect the first five elements of data2 to end up the same as the corresponding elements of data1.

#include<stdio.h>

void disp(char *buffer)
{
    int itr, data2[5];
    for(itr=0;itr<5;itr++)
    {
        data2[itr]=(int*)buffer[itr];
        printf("data2[%d]= %d\n",itr,data2[itr]);
    }
}

int main(void)
{
    int data1[5]={10,20,30,40,50};
    disp((char*)data1);
    return 0;
}

Solution

  • The function call seems not to be the problem. You are permitted to cast data1 to type char * as you do, and as is needful for matching the type of the function parameter. This is in fact a special case in that it is even allowed to access the pointed-to data via the resulting char *.

    The problem is in reading the data back out inside disp(). This statement:

            data2[itr]=(int*)buffer[itr];
    

    is broken because the indexing operator, [], has higher precedence than the cast operator. As a result, you are reading the itrth byte of the data to which buffer points, converting that to type int *, converting the result implicitly to int (turn up your compiler's warning level if it's not already warning about that) and storing the final result in data2. Probably passing through type int * as an intermediate form is effectively a no-op.

    The simplest change you could make would be to insert parentheses to override the default operator precedence:

            data2[itr] = ((int*)buffer)[itr];
    

    That converts buffer back to an int * first, and access the itrth int to which it points, which is what you want.

    Personally, however, if I were relying on the argument to actually be an int * but could not update the parameter type formally (but somehow could nevertheless modify the function implementation) then I would create a correctly-typed copy as the very first thing I did:

    void disp(char *buffer) {
        int *int_buffer = (int *) buffer;
    

    Then I could later just do

        // ...
    
            data2[itr] = int_buffer[itr];
    
        // ...
    

    and generally conduct business almost as if I had been able to set the parameter type appropriately.

    Alternatively, for this particular use, you have the option of simply performing a bulk copy:

        memcpy(data2, buffer, 5 * sizeof(*data2));
    

    Done, except for printing out the result.