了解关于结构数组的 Malloc 和 Realloc
Understanding Malloc and Realloc in regards to an array of structs
我已经为 malloc 和 realloc 背后的想法苦苦挣扎了一段时间,目前我在动态创建结构数组方面遇到了问题。我有一个 struct triangle
,它本身由一个 struct coordinates
数组组成。我希望能够拥有一个尽可能大的 triangles
数组,但是每次我尝试增加数组的长度时,似乎什么都没有发生。 Realloc 不会失败,malloc 也不会。但是新的三角形没有插入到我的数组中。这是我的代码供参考。
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct coordinate {
int x;
int y;
};
struct triangle {
struct coordinate point[3];
};
static size_t size = 0;
static void addTriangle(struct triangle **triangles, struct triangle *t) {
struct triangle *ts = (struct triangle*) realloc(*triangles, (size+1) * sizeof(struct triangle));
if(ts == NULL) {
free(ts);
exit(EXIT_FAILURE);
}
*triangles = ts;
triangles[size] = t;
size++;
}
int main() {
struct triangle* triangles = (struct triangle *) malloc(sizeof(struct triangle));
if(triangles == NULL) {
free(triangles);
exit(EXIT_FAILURE);
}
for(int i = 0; i < 2; i++) {
struct coordinate *a = malloc(sizeof(struct coordinate));
a->x = 1 * i;
a->y = 2 * i;
struct coordinate *b = malloc(sizeof(struct coordinate));
b->x = 3 * i;
b->y = 4 * i;
struct coordinate *c = malloc(sizeof(struct coordinate));
c->x = 5 * i;
c->y = 6 * i;
struct triangle *t = malloc(sizeof(struct triangle));
t->point[0] = *a;
t->point[1] = *b;
t->point[2] = *c;
addTriangle(triangles, t);
}
}
我已经尝试了我发现的每一种变体,但我宁愿不要盲目地加入 & 和 * 直到有什么事情发生。
按原样,您的程序在将未初始化的 *triangles
传递给 realloc
时会调用未定义的行为:https://taas.trust-in-soft.com/tsnippet/t/9ff94de4。您可能打算在 main
.
中调用它时传递 &triangles
将 main
中的调用更改为 addTriangle(&triangles, t);
,下一个问题是 addTriangle
: https://taas.trust-in-soft.com/tsnippet/t/658228a1 中的越界访问。同样,这可能是因为您的间接级别错误,意思是 (*triangles)[size]
而不是 triangles[size]
.
如果我将 triangles[size] = t;
行更改为 (*triangles)[size] = *t;
则不会出现未定义的行为。你应该检查这个程序是否仍然做你想要的,因为它被修改了:https://taas.trust-in-soft.com/tsnippet/t/8915bd2d
最终版本:
#include <string.h>
#include <stdlib.h>
struct coordinate {
int x;
int y;
};
struct triangle {
struct coordinate point[3];
};
static size_t size = 0;
static void addTriangle(struct triangle **triangles, struct triangle *t) {
struct triangle *ts = (struct triangle*) realloc(*triangles, (size+1) * sizeof(struct triangle));
if(ts == NULL) {
free(ts);
exit(EXIT_FAILURE);
}
*triangles = ts;
(*triangles)[size] = *t; // a struct assignment
size++;
}
int main() {
struct triangle* triangles = (struct triangle *) malloc(sizeof(struct triangle));
if(triangles == NULL) {
free(triangles);
exit(EXIT_FAILURE);
}
for(int i = 0; i < 2; i++) {
struct coordinate *a = malloc(sizeof(struct coordinate));
a->x = 1 * i;
a->y = 2 * i;
struct coordinate *b = malloc(sizeof(struct coordinate));
b->x = 3 * i;
b->y = 4 * i;
struct coordinate *c = malloc(sizeof(struct coordinate));
c->x = 5 * i;
c->y = 6 * i;
struct triangle *t = malloc(sizeof(struct triangle));
t->point[0] = *a;
t->point[1] = *b;
t->point[2] = *c;
addTriangle(&triangles, t); /* pass the address of triangles
so that addTriangle can modify this variable's contents */
}
}
旁注与您询问的问题没有直接关系
只要你用C编程,请do not cast the result ofmalloc
。只需写 struct triangle* triangles = malloc(...
.
正如@aschepler 在评论中指出的那样,该程序仍然泄漏从 main
分配的内存块。这些可以在每次迭代结束时释放,而不添加任何未定义的行为:https://taas.trust-in-soft.com/tsnippet/t/a0705262。这样做,您可能会意识到 t->point[0] = *a;
, ... 实际上是结构赋值,并且没有必要首先分配一个单独的 struct coordinate
:您可以只填写每个 struct coordinate
struct triangle
的成员。此外,也没有必要在 main
中分配 struct triangle
:你可以为此使用局部变量,因为无论如何结构的内容将被函数 [=18= 复制]到main
的局部变量triangles
指向的数组。
如果 triangles
是 main
中的空指针,您也不需要调用 free(triangles)
:
struct triangle* triangles = (struct triangle *) malloc(...
if(triangles == NULL) {
free(triangles);
exit(EXIT_FAILURE);
}
允许将空指针传递给 free
,这会如您所愿(它什么也不做),但是因为您知道 triangles
是 NULL
then
分支,只需调用 exit
.
正在处理 realloc
on the other hand is a subtle subject 的失败。您的程序做错了,但这并不重要,因为它会立即调用 exit
。
将有关 main
的局部变量 triangles
指向的已分配数组的信息存储在静态文件范围变量 size
中是不一致的。两者关系密切,应该属于同一范畴。由于需要addTriangle
才能改变size
,所以不能简单地将size
移动为main
的局部变量,而是可以将[=34]的局部变量移动=] 的 main
到文件范围,在 size
旁边。毕竟,如果您更愿意将 size
设为 main
的局部变量,则需要将其地址传递给函数 addTriangle
,以便后者可以更新前者。
您可以将整个 for
循环替换为
struct triangle t = {{{i, 2*i},{3*i,4*i},{5*i,6*i}}};
addTriangle(&triangles, &t);
请注意参数前的&
,因为你要传递两者的地址
我已经在评论中注意到 triangles[size] = t;
应该是 (*triangles)[size] = *t;
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct coordinate {
int x;
int y;
};
struct triangle {
struct coordinate point[3];
};
static size_t size = 0;
static void addTriangle(struct triangle **triangles, struct triangle *t) {
struct triangle *ts = realloc(*triangles, (size+1) * sizeof(struct triangle));
if(ts == NULL) {
exit(EXIT_FAILURE);
}
*triangles = ts;
(*triangles)[size] = *t;
size++;
}
int main() {
struct triangle* triangles = malloc(sizeof(struct triangle));
if(triangles == NULL) {
exit(EXIT_FAILURE);
}
for(int i = 0; i < 2; i++) {
struct triangle t = {{{i, 2*i},{3*i,4*i},{5*i,6*i}}};
addTriangle(&triangles, &t);
}
for(int i = 0; i < size; i++) {
printf("%d %d, %d %d, %d %d\n", triangles[i].point[0].x,
triangles[i].point[0].y,
triangles[i].point[1].x,
triangles[i].point[1].y,
triangles[i].point[2].x,
triangles[i].point[2].y);
}
}
将函数调用改为
addTriangle(&triangles, t);
我已经为 malloc 和 realloc 背后的想法苦苦挣扎了一段时间,目前我在动态创建结构数组方面遇到了问题。我有一个 struct triangle
,它本身由一个 struct coordinates
数组组成。我希望能够拥有一个尽可能大的 triangles
数组,但是每次我尝试增加数组的长度时,似乎什么都没有发生。 Realloc 不会失败,malloc 也不会。但是新的三角形没有插入到我的数组中。这是我的代码供参考。
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct coordinate {
int x;
int y;
};
struct triangle {
struct coordinate point[3];
};
static size_t size = 0;
static void addTriangle(struct triangle **triangles, struct triangle *t) {
struct triangle *ts = (struct triangle*) realloc(*triangles, (size+1) * sizeof(struct triangle));
if(ts == NULL) {
free(ts);
exit(EXIT_FAILURE);
}
*triangles = ts;
triangles[size] = t;
size++;
}
int main() {
struct triangle* triangles = (struct triangle *) malloc(sizeof(struct triangle));
if(triangles == NULL) {
free(triangles);
exit(EXIT_FAILURE);
}
for(int i = 0; i < 2; i++) {
struct coordinate *a = malloc(sizeof(struct coordinate));
a->x = 1 * i;
a->y = 2 * i;
struct coordinate *b = malloc(sizeof(struct coordinate));
b->x = 3 * i;
b->y = 4 * i;
struct coordinate *c = malloc(sizeof(struct coordinate));
c->x = 5 * i;
c->y = 6 * i;
struct triangle *t = malloc(sizeof(struct triangle));
t->point[0] = *a;
t->point[1] = *b;
t->point[2] = *c;
addTriangle(triangles, t);
}
}
我已经尝试了我发现的每一种变体,但我宁愿不要盲目地加入 & 和 * 直到有什么事情发生。
按原样,您的程序在将未初始化的 *triangles
传递给 realloc
时会调用未定义的行为:https://taas.trust-in-soft.com/tsnippet/t/9ff94de4。您可能打算在 main
.
&triangles
将 main
中的调用更改为 addTriangle(&triangles, t);
,下一个问题是 addTriangle
: https://taas.trust-in-soft.com/tsnippet/t/658228a1 中的越界访问。同样,这可能是因为您的间接级别错误,意思是 (*triangles)[size]
而不是 triangles[size]
.
如果我将 triangles[size] = t;
行更改为 (*triangles)[size] = *t;
则不会出现未定义的行为。你应该检查这个程序是否仍然做你想要的,因为它被修改了:https://taas.trust-in-soft.com/tsnippet/t/8915bd2d
最终版本:
#include <string.h>
#include <stdlib.h>
struct coordinate {
int x;
int y;
};
struct triangle {
struct coordinate point[3];
};
static size_t size = 0;
static void addTriangle(struct triangle **triangles, struct triangle *t) {
struct triangle *ts = (struct triangle*) realloc(*triangles, (size+1) * sizeof(struct triangle));
if(ts == NULL) {
free(ts);
exit(EXIT_FAILURE);
}
*triangles = ts;
(*triangles)[size] = *t; // a struct assignment
size++;
}
int main() {
struct triangle* triangles = (struct triangle *) malloc(sizeof(struct triangle));
if(triangles == NULL) {
free(triangles);
exit(EXIT_FAILURE);
}
for(int i = 0; i < 2; i++) {
struct coordinate *a = malloc(sizeof(struct coordinate));
a->x = 1 * i;
a->y = 2 * i;
struct coordinate *b = malloc(sizeof(struct coordinate));
b->x = 3 * i;
b->y = 4 * i;
struct coordinate *c = malloc(sizeof(struct coordinate));
c->x = 5 * i;
c->y = 6 * i;
struct triangle *t = malloc(sizeof(struct triangle));
t->point[0] = *a;
t->point[1] = *b;
t->point[2] = *c;
addTriangle(&triangles, t); /* pass the address of triangles
so that addTriangle can modify this variable's contents */
}
}
旁注与您询问的问题没有直接关系
只要你用C编程,请do not cast the result of
malloc
。只需写struct triangle* triangles = malloc(...
.正如@aschepler 在评论中指出的那样,该程序仍然泄漏从
main
分配的内存块。这些可以在每次迭代结束时释放,而不添加任何未定义的行为:https://taas.trust-in-soft.com/tsnippet/t/a0705262。这样做,您可能会意识到t->point[0] = *a;
, ... 实际上是结构赋值,并且没有必要首先分配一个单独的struct coordinate
:您可以只填写每个struct coordinate
struct triangle
的成员。此外,也没有必要在main
中分配struct triangle
:你可以为此使用局部变量,因为无论如何结构的内容将被函数 [=18= 复制]到main
的局部变量triangles
指向的数组。如果
triangles
是main
中的空指针,您也不需要调用free(triangles)
:struct triangle* triangles = (struct triangle *) malloc(... if(triangles == NULL) { free(triangles); exit(EXIT_FAILURE); }
允许将空指针传递给
free
,这会如您所愿(它什么也不做),但是因为您知道triangles
是NULL
then
分支,只需调用exit
.正在处理
realloc
on the other hand is a subtle subject 的失败。您的程序做错了,但这并不重要,因为它会立即调用exit
。将有关
main
的局部变量triangles
指向的已分配数组的信息存储在静态文件范围变量size
中是不一致的。两者关系密切,应该属于同一范畴。由于需要addTriangle
才能改变size
,所以不能简单地将size
移动为main
的局部变量,而是可以将[=34]的局部变量移动=] 的main
到文件范围,在size
旁边。毕竟,如果您更愿意将size
设为main
的局部变量,则需要将其地址传递给函数addTriangle
,以便后者可以更新前者。
您可以将整个 for
循环替换为
struct triangle t = {{{i, 2*i},{3*i,4*i},{5*i,6*i}}};
addTriangle(&triangles, &t);
请注意参数前的&
,因为你要传递两者的地址
我已经在评论中注意到 triangles[size] = t;
应该是 (*triangles)[size] = *t;
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct coordinate {
int x;
int y;
};
struct triangle {
struct coordinate point[3];
};
static size_t size = 0;
static void addTriangle(struct triangle **triangles, struct triangle *t) {
struct triangle *ts = realloc(*triangles, (size+1) * sizeof(struct triangle));
if(ts == NULL) {
exit(EXIT_FAILURE);
}
*triangles = ts;
(*triangles)[size] = *t;
size++;
}
int main() {
struct triangle* triangles = malloc(sizeof(struct triangle));
if(triangles == NULL) {
exit(EXIT_FAILURE);
}
for(int i = 0; i < 2; i++) {
struct triangle t = {{{i, 2*i},{3*i,4*i},{5*i,6*i}}};
addTriangle(&triangles, &t);
}
for(int i = 0; i < size; i++) {
printf("%d %d, %d %d, %d %d\n", triangles[i].point[0].x,
triangles[i].point[0].y,
triangles[i].point[1].x,
triangles[i].point[1].y,
triangles[i].point[2].x,
triangles[i].point[2].y);
}
}
将函数调用改为
addTriangle(&triangles, t);