Search code examples
cdouble-pointerstrdup

pointer to pointer to structure with malloc and strdup


My main intention is to pass a pointer to a structure, to a function, which will allocate memory and fill all its values. After returning back i will print it on screen.

Structure looks like this.

struct isolock{
    char *name;
    unsigned int state;};
typedef struct isolock lock;

Please note i can not change declaration of this structure. My main function is very simple like this.

int main(){
    int i = 0;
    isolock *lock = NULL;
    fillArray(&lock);

    //print struct contents
    for(i=0;(lock+i)->name;i++){
            printf("name = %s status = %u \n", (lock+i)->name,(lock+i)->state);
    }

}

fillArray function is suppose to allocate n + 1 memory blocks for my structure where n is the actual number of locks present. whereas last (n+1)th block will be filled with zero. So that while printing from main, i can just check for this condition, without need of worrying about length of structures which i have allocated.

My problem is in fillArray function.

static const char *array[] = {"SWMGMT_LOCK","OTHER_LOCK"};
void fillArray(isolock **dlock){
    int i = 0;
    if (*dlock == NULL){
            *dlock = (isolock *)malloc((sizeof (*dlock)) * 3);      //allocate space for holding 3 struct values

            for(i=0;i<2;i++){
                    (*(dlock) + i)->name = strdup(array[i]);       
                    (*(dlock) + i)->state = (unsigned int)(i+1);                                           
            }
            (*(dlock) + i)->name = 0;   //LINE100
            (*(dlock) + i)->state = 0;
    }
}
o/p:

name =  status = 1 
name = OTHER_FP_LOCK status = 2 

Actually this LINE100 causes problem. It actually replaces already filled structure entry i.e., this line makes dlock[0]->name to be filled with 0. whereas dlock[1] remains unchanged.

My gdb log shows something like this.

All these are logs are taken after allocation and filling values.

    (gdb) p (*(dlock)+0)
    $10 = (isolock *) 0x804b008
    (gdb) p (*(dlock)+1)
    $11 = (isolock *) 0x804b010 
    (gdb) p (*(dlock)+2)                      <== Note here 1
    $12 = (isolock *) 0x804b018
    (gdb) p *(*(dlock)+0)
    $13 = {name = 0x804b018 "SWMGMT_LOCK", state = 1}     <== Note here 2
    (gdb) p *(*(dlock)+1)
    $14 = {name = 0x804b028 "OTHER_FP_LOCK", state = 2}
    (gdb) n
    33    (*(dlock) + i)->state = 0;
    (gdb) 
    35   }
    (gdb) p *(*(dlock)+2)
    $15 = {name = 0x0, state = 0}
    (gdb) p (*(dlock)+2)
    $16 = (isolock *) 0x804b018

From note 1 and note 2 its very clear that, strdup has returned already allocated memory location by malloc i.e., first call to strdup has returned the address of dlock[2]. how could this happen. because of this, (*dlock+2)->name = 0 has caused dlock[0]->name to be filled with 0.

To easily explain this problem, Malloc has returned me three addresses. for easy understanding lets say, {1000,1008,1010} Two times i ve called strdup which has returned {1010,1018}

this 1010 and 1018 are stored in char *name of lock[0] and lock[1] respectively.

Can someone tell me, am i doing something wrong in this code or is this problem of strdup ( allocating a already allocated block of memory)

NOTE: When i have changed char *name to char name[20] and instead of strdup, i used strcpy and it worked perfectly.


Solution

  • A possible cause of the error is your allocation:

    *dlock = (isolock *)malloc((sizeof (*dlock)) * 3);
    

    Here dlock is a pointer to a pointer, so sizeof(*dlock) is the size of a pointer which is not the same as sizeof(struct isolock) (or sizeof(**dlock)).