为了了解更多 C 语言,我正在尝试重新创建基本数据结构。这是我尝试数组的一个最小示例,该数组可以编译并运行,但 valgrind 检测到问题:
#include <stdlib.h>
#include <stdio.h>
typedef void * vp_t;
typedef struct {
int len;
vp_t *start;
} arr_t;
arr_t * array_new(int len) {
arr_t *arr = malloc(sizeof(arr_t));
arr->start = malloc(len * sizeof(vp_t));
arr->len = len;
return arr;
}
void array_set(arr_t *arr, int i, vp_t vp) {
vp_t *dest = arr->start + i * sizeof(vp_t);
*dest = vp;
}
int array_get(arr_t *arr, int i) {
int *p = *(arr->start + i * sizeof(vp_t));
return *p;
}
void array_delete(arr_t *arr) {
free(arr->start);
free(arr);
}
int main() {
int x=0, y=1, z=2;
arr_t *arr = array_new(3);
array_set(arr, 0, &x);
array_set(arr, 1, &y);
array_set(arr, 2, &z);
for (int i = 0; i < 3; ++i) printf("%i ", array_get(arr, i));
putchar('\n');
array_delete(arr);
return 0;
}
程序按预期输出
1 2 3
。然而,当我第二次和第三次调用 array_set 函数时,valgrind 检测到了一个问题。针对此处的示例代码运行 valgrind,我得到:
==91933== Invalid write of size 8
==91933== at 0x109244: array_set (min.c:22)
==91933== by 0x109312: main (min.c:39)
==91933== Address 0x4a990d0 is 32 bytes before an unallocated block of size 4,194,032 in arena "client"
==91933==
==91933==
==91933== Process terminating with default action of signal 11 (SIGSEGV)
==91933== Access not within mapped region at address 0x2003A98F4C
==91933== at 0x109244: array_set (min.c:22)
==91933== by 0x109327: main (min.c:40)
min.c:22
指的是array_set函数中的*dest = vp
。 min.c:39
指的是array_set(arr, 1, &y)
。 Valgrind 不抱怨第 38 行,array_set(arr, 0, &x)
。
我一直在研究gdb,但我还没弄清楚。感谢您的浏览。
当您需要寻址数组时,只需将多少个单元格(除了单元格大小)添加到指针即可。
void array_set(arr_t *arr, int i, vp_t vp) {
vp_t *dest = arr->start + i;
*dest = vp;
}
int array_get(arr_t *arr, int i) {
int *p = *(arr->start + i);
return *p;
}
arr->start 的类型为 vp_t,因此当您向指针添加 1 时,编译器将增加所需的数量 (sizeof(vp_t)) 以转到下一个单元格。
这就是解决方案,但首先为什么,你需要一个 void ** 数组,如果你想创建一个整数数组,请使用 int** 创建,只有当你需要任何类型的数组时才推荐使用 void 数组。 不管怎样,错误在于你创建了一个 void* (一维),而实际上,应该是一个二维数组 void **
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int len;
void **start;
} arr_t;
arr_t * array_new(int len) {
arr_t *arr = malloc(sizeof(arr_t));
arr->start = malloc(len * sizeof(void*));
arr->len = len;
return arr;
}
void array_set(arr_t *arr, int i, void *vp) {
arr->start[i] = vp;
}
int array_get(arr_t *arr, int i) {
return *(int*)arr->start[i];
}
void array_delete(arr_t *arr) {
free(arr->start);
free(arr);
}
int main() {
int x=0, y=1, z=2;
arr_t *arr = array_new(3);
array_set(arr, 0, &x);
array_set(arr, 1, &y);
array_set(arr, 2, &z);
for (int i = 0; i < 3; ++i) printf("%i ", array_get(arr, i));
putchar('\n');
array_delete(arr);
return 0;
}