我正在尝试使用 C 语言构建一个数据结构,它允许我记录字符串(表示海拔值),其数据描述地图中点的某些特征。 每个点除了对应字符串描述的特征外,还应该有一个对应于经度(列)的坐标和一个对应于纬度(行)的坐标。
我想通过在堆中为行和列分配内存来将此映射输出为空结构。 这个想法是,你有一个指向 char 指针的指针,为此你为一个指向 char 指针的指针数组分配内存,每个指针都指向一行的开头。 第一个数组中包含的每个指向 char 的指针必须为指向 char 的指针数组分配内存。
这将是基本结构。在此阶段不需要为每个 char 指针分配字符串,因为字符串将通过读取文本文件来构造,然后通过分配与其开头相对应的地址来“指向”。 我尝试以这样的方式分配内存,即指针数组被视为以 NULL 结尾的指针数组,即使用空指针而不是空字节来定义行数组的末尾和每个点系列的末尾在列上。 根据测试,该策略效果很好:使用指针算术(即不使用计数器对数组进行索引)和两个整数计数器,它产生了精确的行数,并且对于每行,产生了精确的列数。
但是,当我必须释放内存时,Valgrind 警告我,我的代码正在生成无效的释放内存块。
以下是代码:任何人都可以看到我的错误吗?我错过了什么?
int clean_lines_in_map_structure(char ***map)
{
char ***start;
char ***swap;
start = map;
swap = map;
while (*swap != NULL)
{
map = swap;
swap++;
free(*map);
}
free(start);
return (-1);
}
int allocate_memory_for_map_structure(void) // The real function (but what is
// reality?) takes a pointer to some
// data stored in the data segment,
// e.g. values for "width" and
// "height".
{
char ***map;
char ***swap;
int count;
int width;
int height;
width = 100; // could be any integer value passed to the function
height = 75; // same as above
map = malloc((height + 1) * sizeof(*map));
if (map == NULL)
return (-1);
count = 0;
swap = map;
while (count < height)
{
*swap = malloc((width + 1) * sizeof(**swap));
if (*map == NULL)
return (clean_lines_in_map_structure(map));
swap++;
count++;
}
*swap = NULL;
/* The following two instructions are here only for test. */
test_outcome_of_allocation(map); // I will not add this function's code to the
// question. However, it was a simple test
// that correctly counted the number of rows and
// columns stoppin iterations when NULL
// was reached by dereferencing incremented pointers.
clean_lines_in_map_structure(map);
return (0);
}
我有兴趣了解如何做到这一点,但更感兴趣的是了解我的错误:为什么我写的内容会导致无效的内存释放?
使用双指针初始化和释放数组条目既麻烦又容易出错。您应该使用数组语法。
您似乎依赖于矩阵边界的空指针哨兵。这可以工作,但传递矩阵维度似乎更可靠。
注意
if (*map == NULL)
有错字:应该是if (*swap == NULL)
。
这是修改后的版本:
int clean_lines_in_map_structure(char ***map) {
for (int i = 0; map[i]; i++) {
free(map[i]);
}
free(map);
return -1;
}
int allocate_memory_for_map_structure(void) // The real function (but what is
// reality?) takes a pointer to some
// data stored in the data segment,
// e.g. values for "width" and
// "height".
{
int width = 100; // could be any integer value passed to the function
int height = 75; // same as above
char ***map = malloc(sizeof(*map) * (height + 1));
if (map == NULL)
return -1;
for (int i = 0; i < height; i++) {
map[i] = malloc(sizeof(*map[i]) * (width + 1));
if (map[i] == NULL)
return clean_lines_in_map_structure(map);
// intialize the matrix entries
for (int j = 0; j < width + 1; j++)
map[i][j] = NULL;
}
map[height] = NULL;
/* The following two instructions are here only for test. */
test_outcome_of_allocation(map); // I will not add this function's code to the
// question. However, it was a simple test
// that correctly counted the number of rows and
// columns stoppin iterations when NULL
// was reached by incrementing pointers.
clean_lines_in_map_structure(map);
return 0;
}