Question

I am trying to run the following program, in which I dynamically allocate memory to a variable using a function called reserve. When I run the application, I get segmentation fault because of allocating the memory in a separate function for an empty pointer, but If I want allocate the memory in the main, I don't get this error. So what am I doing wrong?

Here is the code:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct{

unsigned char state;

/* socket fd of the client */
int fd;

/* File path requested by the client */
char file_path [255];

/* Current file offset */
unsigned long int offset;

} STATE;


void reserve(int length, void *context_data ,void *buffer)
{
    context_data = (char *) malloc(length);
    memcpy(context_data, buffer, length);
}

int main()
{
    STATE test;
    int length = sizeof(STATE);
    char buffer[1500];
    char *ptr = buffer;

    test.state = 10;
    strcpy(test.file_path, "Hello How are you");

    memcpy(ptr, &test, length);
    ptr += length;

    char *context_data;
    reserve(length, context_data, buffer);

    STATE *temp = (STATE *) context_data;
    printf("File Path %s\n", temp->file_path);
    printf("State %d\n", temp->state);
 }
Was it helpful?

Solution

In this code:

void reserve(int length, void *context_data ,void *buffer)
{
    context_data = (char *) malloc(length);
    memcpy(context_data, buffer, length);
}

The context_data parameter is passed by value, so context_data inside of reserve and context_data outside of reserve aren't the same pointer. Consequently, when you reassign context_data locally inside this function, the context_data pointer in main isn't updated, causing the crash.

To fix this, either take in a pointer to the context_data variable to update, like this:

void reserve(int length, void **context_data ,void *buffer)
{
    *context_data = malloc(length);
    memcpy(*context_data, buffer, length);
}
reserve(length, &context_data, buffer);

Or, alternatively, have reserve return the updated pointer:

void* reserve(int length,void *buffer)
{
    void* context_data = (char *) malloc(length);
    memcpy(context_data, buffer, length);
    return context_data;
}
void* context_data = reserve(length, buffer);

Hope this helps!

OTHER TIPS

Notice that context_data is passed by value. So the local copy in reserve is changed, but not the original one. As a result, the context_data in main() is not initialized. So you got the crash.

The problem is your main() function has no current means of learning where the allocation took place. You're passing the pointer from main() to reserve() which is fine to allow the subroutine to modify what the pointer points at... but that's not what you need; you need to have reserve() modify where the pointer points.

void reserve(int length, void **context_data ,void *buffer)
{
    *context_data = malloc(length);
    memcpy(*context_data, buffer, length);
}

// in main():
char *context_data;
reserve(length, &context_data, buffer);

In pass by reference, you pass the address of the variable. Here your variable is a pointer, hence pass the address of the pointer.

Call it like:

reserve(length, &context_data, buffer);

And change the function definition:

void reserve(int length, void **p_context_data ,void *buffer)
{
*p_context_data = malloc(sizeof(char)*length);
.....

You pass a char* into reserve() but you should pass char** like this:

char *context_data;
reserve(length, &context_data, buffer);

then reserve should look like this:

void reserve(int length, void **context_data ,void *buffer) {
  *context_data = (char *) malloc(length); 
  memcpy(*context_data, buffer, length); 
}

Variable void* context_data in function reserve() is a local variable, which means that it is different from variable char* context_data in function main(). Its value will not propagate back to the main() from reserve(). You pass a value of context_data to reserve() (the undefined value), and then use it as STATE* temp, but the value is still undefined.

If you would like to update a local variable of main() function, you have to pass a pointer to that variable. In your case, you have to pass pointer to pointer, i.e. your code should look like this:

void reserve(int length, void **context_data, void *buffer)
{
    *context_data = (char *) malloc(length);
    memcpy(*context_data, buffer, length);
}

int main()
{
    ...

    char* context_data;
    reserve(length, &context_data, buffer);
    ...
}

Or, you can also change your reserve() function and make it return a pointer to allocated memory.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top