C - Malloc and memcpy (memory management)

I'm a little new to C, and it's hard for me to understand how memory works, especially built-in functions like memcpy .

Here a struct I use

  struct data_t { int datasize; void *data; }; 

And here is the helper function with which I use it:

 struct data_t *data_create(int size) { struct data_t *dt=malloc(sizeof(struct data_t)+size); dt->datasize=size; dt->data="1234567890a"; return dt; } 

Now in main function I have no problem with this:

 struct data_t *data = data_create(1024); data->data="123456a";//just an example 

But this causes Seg Fault:

 memcpy(data->data,"123456a",strlen("1234567890a")+1); 

My question is why? And how can I avoid this? Please keep in mind that I am new to C, so as C deals with memory, this is a little new to me.

Thanks.

Edit: it works! Many thanks. The data pointer is completely skipped. Now everything works fine according to valgrind.

+7
source share
4 answers

memcpy(data->data,"123456a",strlen("1234567890a")+1);

fails because the type data->data a void * points to some kind of garbage / invalid address that is not allocated. data has the address of the string literal that is stored in the readonly section (for example, in the .rodata executable file and loaded into memory, which is impossible for writing. In addition, if you did not assign such a string address to the pointer variable, then it will contain some invalid / value of the garbage address that is not allocated or initialized by any valid permitted location, so first select the buffer.

 data->data = malloc (sizeof (char) * size); 

malloc will return the first address block location address from atleast size * sizeof (char) bytes. Now you can copy size bytes to this memory location that data->data points to.

Remember to free the allocated memory block when you are finished working with this memory block by calling free (addr) .


I see that you tried to allocate the data buffer in a very strange way (?):

 struct data_t *dt=malloc(sizeof(struct data_t)+size); 

for which additional allocated size bytes along with struct data_t . But be that as it may, the data component still points to a place that cannot be changed. Please, use:

 struct data_t *dt = malloc(sizeof(struct data_t)); dt->data = malloc (sizeof (char) * size); memcpy (data->data, "whatever", sizeof ("whatever")+1); return dt; 

to free first:

 free (dt->data); 

then

 free (dt); 
+6
source

Your first mistake:

 struct data_t *dt=malloc(sizeof(struct data_t)+size); 

This will create a piece of memory of size struct data_t + size. I think you expected that your data field inside data_t could use this memory, but this is not possible because the data does not contain an address in this memory.

Your second mistake was to assume that you are copying the value of the following line to "data":

 data->data="123456a"; 

What actually happened here is that in the memory of “123456a” there is a line that exists for the whole life of your program. When you assign data to “123456a” data->, what actually happens is you take the address of this string “123456a” and put it in data-> data that you are not copying the value (“123456a”), but the location or address (0x23822 ...) "123456a".

Your last mistake:

 memcpy(data->data,"123456a",strlen("1234567890a")+1); 

You tried to copy the value "123456a" into the memory pointed to by the data. What do the data indicate? It points to a read-only area with memory containing the previously assigned line "123456a". In other words, you told your program to write the address "123456a".

Here is a program that will do what you expect:

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> typedef struct { size_t datasize; char *data; } data_t; data_t *data_create(size_t size) { data_t *dt; dt = malloc(sizeof(data_t)); assert(dt != NULL); dt->data = malloc(size); assert(dt->data != NULL); dt->datasize = size; /* need to decide what to do when this happens */ assert((strlen("1234567890a") + 1) < size); strcpy(dt->data, "1234567890a"); return dt; } void data_destroy(data_t *dt) { free(dt->data); free(dt); } int main(void) { data_t *data = data_create(1024); /* data->data="123456a"; DONT DO THIS YOU WILL CAUSE A MEMORY LEAK */ assert(data->datasize >= (strlen("123456a")+1)); memcpy(data->data, "123456a", strlen("123456a")+1); printf("%s\n", data->data); data_destroy(data); return EXIT_SUCCESS; } 
+3
source

Note void *data is a pointer, in data_create you did not allocate a space for it, you just pointed to the string constant "1234567890a" , which is only readable.

In main you create another string constant "123456a" , then you make void *data point to the constant of the line that is only being read.

Therefore, when you call memcpy to write to a memory address that is not written (or not initialized), you receive an error message.

+1
source

data-> data is a pointer. And this pointer points to nowhere. Before doing memcpy, you must allocate a place and make data-> data in that place.

 data->data = malloc(strlen("1234567890a")+1); 

and then memcpy will not work until data-> data! = NULL

do

data->data = "123"

ok, because "123" is allocated at compile time, so data-> data points to the beginning of line "123", but the memcpy(data->data,"123",4) call memcpy(data->data,"123",4) will fail because the data pointer is not initialized and indicates some random location in memory that cannot even be read.

0
source

All Articles