我对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,现在一切都很好。
答案 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)
将失败,因为指向数据数据的指针未初始化,指向内存中一些无法读取的随机位置。