为了能够在任何地方访问动态分配的结构,您需要访问它的位置,以便能够在任何地方引用它,为此,我们使用指针。让我给你举个例子。
假设你有
Point
表示三维空间中的点的数据类型。
typedef struct point_t {
double x;
double y;
double z;
} *Point;
现在您可以创建一个“builder”函数,它与C++中的构造函数没有什么不同,但也不完全一样,您可以在其中设置其初始值并返回其指针。这就是动态分配结构并保留指向它的指针的方式,以便可以在程序的其他部分继续使用它。
Point createPoint(double a, double b, double c) {
Point newPoint = malloc(sizeof(struct point_t));
if (newPoint == NULL) { /* Handle failure here... */ }
SetPoint(&newPoint,a,b,c);
return newPoint;
}
然后你就可以定义
SetPoint
像这样:
void SetPoint(Point* p, double a, double b, double c) {
if (p == NULL) { return; }
*p->x = a;
*p->y = b;
*p->z = c;
}
要实际使用该结构,您必须做两件事。首先,必须构造结构,然后必须将其传递给需要它的其他函数。您已经在工作中看到了这一点
设定值
上述功能。
请注意
Point* p
声明
双指针
到类型的结构
struct point_t
。我们需要一层间接层来处理指针本身,然后需要一层额外的间接层,以便通过引用传递指针并修改其在函数中的内容。如果我们经过一个普通的
指向
句柄时,传递值机制将丢弃函数的效果。
因此,在这个假设的数据结构中
main
函数可能会这样使用它:
int main()
{
Point origin = createPoint(0,0,0);
PrintPoint(origin);
Point p1 = createPoint(1,-1,5);
PrintPoint(p1);
printf("Distance between p1 and the origin: %lf\n", DistanceBetween(p1,origin));
return EXIT_SUCCESS;
}
您可以定义
Print Point
像这样:
void PrintPoint(Point p) {
if (p == NULL) { return; }
printf("(%lf,%lf,%lf)\n", p->x, p->y, p->z);
}
同样,您可以定义
DistanceBetween
函数如下:(记住,三维欧几里德空间中任意两点之间的距离基本上是勾股定理,但有一个额外的维度。
double DistanceBetween(Point a, Point b) {
return sqrt(pow((b->x - a->x),2) + pow((b->y - a->y),2) + pow((b->z - a->z),2));
}
对于一些一般的指示,请记住保持警惕
NULL
指针。它们不仅会导致分段错误或给您带来垃圾结果(有时在imo中情况更糟),而且还会导致代码漏洞,如多年前zlib中的“双重免费”漏洞。最近还有一个漏洞,但我没有阅读漏洞利用摘要。
如果你想安全地使用双自由度,你可以使用里斯教授在《理解和使用C指针》中提到的方法如果我们将其应用于假设
指向
从上面看,它是这样的:
void SafeFree(Point* pointHandle) {
if (*pointHandle == NULL) { return; }
free(*pointHandle);
*pointHandle = NULL;
}
请注意,我们正在传入要通过引用释放的指针(因此您必须像这样释放它:
free(&origin)
例如这样我们就可以将其设置为
无效的
一旦我们释放了它。这样,如果要在同一内存位置调用free,
即使它被另一个指针引用
这
无效的
检查可以避免双重释放内存。
无论如何,这只是一个额外的预防措施,我希望所有这些都能有所帮助,如果你还有任何问题,请告诉我。