Confusion about C pointers

120 Views Asked by At

I am sending this message to clear my confusion that I could not manage and handle.

The foo1 function code should work. I am giving the code details for you.

When I run the code, the result is a segmentation error at line 12. Then I made a little change in foo2 in different syntax notation. foo2 is working. But I want to learn more deeply how pointers work. Which kind of error can cause this error. If I don't use line 12 everything looks fine. What would be the main reason for this issue. Could you please assist me?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int foo1(char ***BufferArray,char *item,int idx);
int foo2(char ***BufferArray,char *item,int idx);
int main(){
    char **ptr=malloc(sizeof(char*)*3);
    char a[]="hello0";
    char b[]="hello1";
    char c[]="hello2";
    foo1(&ptr,a,0);
    //foo1(&ptr,b,1);//Exception has occurred. Segmentation fault //line 12
    printf("[%s]",*(ptr+0));
    printf("[%s]",*(ptr+1));
    getchar();
    return(0);
}

int foo1(char ***BufferArray,char *item,int idx){
    int n;
    n=1;
    **(BufferArray+idx)=malloc(sizeof(char)*strlen(item));
    strcpy(**(BufferArray+idx),item);
    return(0);
}

int foo2(char ***BufferArray,char *item,int idx){
    int n;
    char **temp=*BufferArray;
    *(temp+idx)=malloc(sizeof(char)*strlen(item));
    strcpy(*(temp+idx),item);
    *BufferArray=temp;
    return(0);
}
2

There are 2 best solutions below

3
Vlad from Moscow On

You are passing to the function foo1

foo1(&ptr,b,1);

a pointer to the pointer ptr defined like

char **ptr=malloc(sizeof(char*)*3);

So to access the pointer within the function you may use an expression either like *BufferArray or like *( BufferArray + 0 ) or like BufferArray[0].

In the function foo2 you are in fact using one of these expressions

char **temp=*BufferArray;

An expression like that *(BufferArray+idx) used in the function foo1 where the variable idx is greater than 0 tries to access memory outside the passed pointer that invokes undefined behavior when the expression is further dereferenced.

Pay attention to that strings contain trailing zero character '\0'. You need to reserve memory also to it if you are going to copy a string in the allocated memory. That is you need to write for example

*(temp+idx)=malloc(sizeof(char)*strlen(item) + 1);
                                             ^^^                  
strcpy(*(temp+idx),item);

Using sizeof( char ) in the call of malloc is redundant and makes the line kess readable. Instead you could write simply

*(temp+idx)=malloc( strlen(item) + 1 );
0
Ian Abbott On

The main problem in foo1() is lack of consideration of operator precedence. **(BufferArray+idx) should be *(*BufferArray)+idx). This could also be written *(BufferArray[0]+idx) or (*BufferArray)[idx] or BufferArray[0][idx].

The original **(BufferArray+idx) is equivalent to *BufferArray[idx] (i.e. *(BufferArray[idx])) or BufferArray[idx][0]. In the call foo1(&ptr,b,1), BufferArray points to the char **ptr variable in main() and idx is 1. BufferArray+idx points to the location just past the end of the ptr variable itself. The pointer value is valid because pointing just past the end of a variable is allowed, but dereferencing that pointer results in undefined behavior (UB) in the same way that accessing an element just past the end of an array results in UB.


As pointed out by others, the call *(temp+idx)=malloc(sizeof(char)*strlen(item)); does not allocate room to store a null terminator character at the end of the string, so the subsequent call strcpy(*(temp+idx),item); writes past the end of the allocated memory (strcpy(a,b) copies strlen(b)+1 characters, including the null terminator character), resulting in UB.