临时为算术转换 void* 的正确方法是什么?
What is the correct way to temporarily cast void* for arithmetic?
我是 C 新手,但当了几年程序员,所以我正在尝试学习 C,方法是从 2008 年开始学习斯坦福大学的课程,并在 C 中的 Vectors 上做 Assignment 3。
它基本上只是一个通用数组,所以数据作为 void *
保存在结构中。编译器标志 -Wpointer-arith
已打开,所以我无法执行 arithmetic(我明白原因)。
数据周围的结构不能知道数据是什么类型,以便它对调用者是通用的。
为了简化事情,我正在尝试以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
void *data;
int aindex;
int elemSize;
} trial;
void init(trial *vector, int elemSize)
{
vector->aindex = 0;
vector->elemSize = elemSize;
vector->data = malloc(10 * elemSize);
}
void add(trial *vector, const void *elemAddr)
{
if (vector->aindex != 0)
vector->data = (char *)vector->data + vector->elemSize;
vector->aindex++;
memcpy(vector->data, elemAddr, sizeof(int));
}
int main()
{
trial vector;
init(&vector, sizeof(int));
for (int i = 0; i < 8; i++)
{add(&vector, &i);}
vector.data = (char *)vector.data - ( 5 * vector.elemSize);
printf("%d\n", *(int *)vector.data);
printf("%s\n", "done..");
free(vector.data);
return 0;
}
但是我在使用 free(): invalid pointer
时遇到了一个错误。所以我在上面 运行 valgrind
并收到以下内容:
==21006== Address 0x51f0048 is 8 bytes inside a block of size 40 alloc'd
==21006== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==21006== by 0x1087AA: init (pointer_arithm.c:13)
==21006== by 0x108826: main (pointer_arithm.c:29)
此时我的猜测是我没有正确执行 char*
,或者可能使用 memcpy
incorrectly
您的代码有些混乱,其中可能隐藏着一两个误解。
几点观察:
- 您不能更改
malloc()
返回的指针,然后将新值传递给free()
。传递给 free()
的每个值必须与分配函数之一返回的值完全相同。
- 如您所料,复制最好由
memcpy()
完成,您必须转换为 char *
才能进行算术运算。
附加值的函数可以是:
void add(trial *vector, const void *element)
{
memcpy((char *) vector->data + vector->aindex * vector->elemSize, element);
++vector->aindex;
}
当然这不会处理向量溢出,因为长度没有存储(我不想假设它是硬编码为 10)。
为每个对象更改 vector
中的 data
值非常奇怪,并且会使事情变得更加混乱。当你需要访问元素时,只需添加所需的偏移量,这非常便宜而且非常简单。
如果事先不知道数组的数据类型,那么在第一次初始化时必须假设一定的内存量,例如32字节或100字节。然后,如果 运行 内存不足,您可以使用 realloc 扩展并将之前的数据复制到新插槽。 C++ 向量 IIRC 遵循 x2 或 x2.2 比率重新分配,不确定。
接下来是您的free
。这里有一件大事你必须知道。如果用户向您发送他们自己的内存分配对象怎么办?例如他们之前分配的char*
?如果您只是删除向量的数据成员,那是不够的。您需要请求一个函数指针,以防数据类型需要特别注意作为您要添加的输入。
最后你在这一行犯了一个大错误:
if (vector->aindex != 0)
vector->data = (char *)vector->data + vector->elemSize;
您正在修改您的指针地址!!!您的初始地址在这里丢失了!你绝不能这样做。使用临时 char*
来保存您的初始数据地址并对其进行操作。
发生这种情况是因为您向向量添加了八个元素,然后 "roll back" 指针仅移动了五步,然后才尝试 free
。您可以通过使用 vector->aindex
来决定要展开多少索引来轻松解决此问题。
然而,问题的根本原因是您修改了vector->data
。您应该首先避免修改它,而是依赖 add
函数内部的临时指针:
void add(trial *vector, const void *elemAddr, size_t sz) {
char *base = vector->data;
memcpy(base + vector->aindex*sz, elemAddr, sz);
vector->aindex++;
}
注意sz
的使用,需要传sizeof(int)
给它
代码中的另一个问题是当您通过将 vector.data
转换为 int*
进行打印时。这可能会奏效,但更好的方法是编写一个类似的 read
函数来提取数据。
我是 C 新手,但当了几年程序员,所以我正在尝试学习 C,方法是从 2008 年开始学习斯坦福大学的课程,并在 C 中的 Vectors 上做 Assignment 3。
它基本上只是一个通用数组,所以数据作为 void *
保存在结构中。编译器标志 -Wpointer-arith
已打开,所以我无法执行 arithmetic(我明白原因)。
数据周围的结构不能知道数据是什么类型,以便它对调用者是通用的。
为了简化事情,我正在尝试以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
void *data;
int aindex;
int elemSize;
} trial;
void init(trial *vector, int elemSize)
{
vector->aindex = 0;
vector->elemSize = elemSize;
vector->data = malloc(10 * elemSize);
}
void add(trial *vector, const void *elemAddr)
{
if (vector->aindex != 0)
vector->data = (char *)vector->data + vector->elemSize;
vector->aindex++;
memcpy(vector->data, elemAddr, sizeof(int));
}
int main()
{
trial vector;
init(&vector, sizeof(int));
for (int i = 0; i < 8; i++)
{add(&vector, &i);}
vector.data = (char *)vector.data - ( 5 * vector.elemSize);
printf("%d\n", *(int *)vector.data);
printf("%s\n", "done..");
free(vector.data);
return 0;
}
但是我在使用 free(): invalid pointer
时遇到了一个错误。所以我在上面 运行 valgrind
并收到以下内容:
==21006== Address 0x51f0048 is 8 bytes inside a block of size 40 alloc'd
==21006== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==21006== by 0x1087AA: init (pointer_arithm.c:13)
==21006== by 0x108826: main (pointer_arithm.c:29)
此时我的猜测是我没有正确执行 char*
,或者可能使用 memcpy
incorrectly
您的代码有些混乱,其中可能隐藏着一两个误解。
几点观察:
- 您不能更改
malloc()
返回的指针,然后将新值传递给free()
。传递给free()
的每个值必须与分配函数之一返回的值完全相同。 - 如您所料,复制最好由
memcpy()
完成,您必须转换为char *
才能进行算术运算。
附加值的函数可以是:
void add(trial *vector, const void *element)
{
memcpy((char *) vector->data + vector->aindex * vector->elemSize, element);
++vector->aindex;
}
当然这不会处理向量溢出,因为长度没有存储(我不想假设它是硬编码为 10)。
为每个对象更改 vector
中的 data
值非常奇怪,并且会使事情变得更加混乱。当你需要访问元素时,只需添加所需的偏移量,这非常便宜而且非常简单。
如果事先不知道数组的数据类型,那么在第一次初始化时必须假设一定的内存量,例如32字节或100字节。然后,如果 运行 内存不足,您可以使用 realloc 扩展并将之前的数据复制到新插槽。 C++ 向量 IIRC 遵循 x2 或 x2.2 比率重新分配,不确定。
接下来是您的free
。这里有一件大事你必须知道。如果用户向您发送他们自己的内存分配对象怎么办?例如他们之前分配的char*
?如果您只是删除向量的数据成员,那是不够的。您需要请求一个函数指针,以防数据类型需要特别注意作为您要添加的输入。
最后你在这一行犯了一个大错误:
if (vector->aindex != 0)
vector->data = (char *)vector->data + vector->elemSize;
您正在修改您的指针地址!!!您的初始地址在这里丢失了!你绝不能这样做。使用临时 char*
来保存您的初始数据地址并对其进行操作。
发生这种情况是因为您向向量添加了八个元素,然后 "roll back" 指针仅移动了五步,然后才尝试 free
。您可以通过使用 vector->aindex
来决定要展开多少索引来轻松解决此问题。
然而,问题的根本原因是您修改了vector->data
。您应该首先避免修改它,而是依赖 add
函数内部的临时指针:
void add(trial *vector, const void *elemAddr, size_t sz) {
char *base = vector->data;
memcpy(base + vector->aindex*sz, elemAddr, sz);
vector->aindex++;
}
注意sz
的使用,需要传sizeof(int)
给它
代码中的另一个问题是当您通过将 vector.data
转换为 int*
进行打印时。这可能会奏效,但更好的方法是编写一个类似的 read
函数来提取数据。