C - Malloc和memcpy(内存管理)

时间:2011-10-08 17:11:18

标签: c struct malloc memcpy

我对C有点新意,我无法理解内存是如何工作的,特别是像memcpy这样的内置函数。

这是struct我正在使用

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

这是我正在使用的辅助功能:

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;
}

现在在main函数中我没有问题:

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

但是这引发了一个Seg Fault:

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

我的问题是为什么?我该如何避免呢? 请记住我是C的新手,所以C处理内存对我来说有点新鲜

谢谢。

编辑:它有效!非常感谢你。完全错过了数据指针。根据valgrind,现在一切都很好。

4 个答案:

答案 0 :(得分:6)

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

失败,因为data->data void *类型指向某个未分配的垃圾/无效地址。 data具有字符串文字的地址,该字符串文字存储在只读部分中(就像在可执行文件的.rodata中并加载到内存中,这是不可写的。 ,如果你没有将这样的字符串地址分配给指针变量,那么它将保存一些无效/垃圾地址值,该值未被分配或初始化为一些有效的允许位置。所以首先分配缓冲区。

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

malloc将返回至少size * sizeof (char)个字节的地址块的第一个位置地址。现在,您可以将size个字节复制到data->data指向的内存位置。

当你使用free (addr)调用完成内存块后,请记住释放已分配的内存块。


我看到你试图以一种非常奇怪的方式分配data缓冲区(?):

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

额外分配的size字节以及struct data_t。但在任何情况下,data组件仍指向某个无法更改的位置。 请使用:

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

首先释放:

free (dt->data);

然后

free (dt);

答案 1 :(得分:3)

你的第一个错误是:

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

这将创建一个大小为struct data_t + size的内存块。我认为你期望的是data_t中的数据字段可以使用这个内存,但它不能,因为数据不能保存这个内存的地址。

你的第二个错误是假设你将以下字符串的值复制到“data”中:

data->data="123456a";

这里实际发生的事情是内存中有一个字符串“123456a”,它存在于程序的整个生命周期中。当您将“123456a”分配给data->数据时,实际发生的是您正在获取此字符串“123456a”的地址并将其放入data->数据中,您不会复制该值(“123456a”)但是“123456a”的位置或地址(0x23822 ...)。

你最后的错误是:

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

您尝试将值“123456a”复制到数据指向的内存中。什么是指向的数据?它指向一个包含先前分配的字符串“123456a”的只读内存区域。换句话说,你告诉你的程序要写入“123456a”的地址。

这是一个能够达到预期效果的程序:

#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;
}

答案 2 :(得分:1)

注意void *data是一个指针,在data_create中,你没有为它分配空间,你只需指向一个只读的字符串常量"1234567890a"

main中,您创建另一个字符串常量"123456a",然后使void *data指向字符串常量,这是只读的。

因此,当您调用memcpy写入无法写入的内存地址(或未初始化)时,您会收到错误。

答案 3 :(得分:0)

data-&gt;数据是指针。而这个指针指向无处。在进行memcpy之前,你应该分配空间并使data-&gt;数据指向这个空间。

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

然后只要data-&gt; data!= NULL

,memcpy就不会失败

操作

data->data = "123"

没问题,因为“123”是在编译时分配的,所以data-&gt;数据指向字符串“123”的开头,但调用memcpy(data->data,"123",4)将失败,因为指向数据数据的指针未初始化,指向内存中一些无法读取的随机位置。