在另一个函数中修改指针需要使用多重间接性的概念,我将在后面解释它,@geofftnz提供的解决方案使用了多重间接性。我的目标是尽力解释C语言中的多重间接。
考虑以下两个程序,我将逐步讲解代码。
以下程序不使用多重间接性,因此会出错。
带有错误的程序:
#include <stdio.h>
#include <stdlib.h>
void allocater(int *ptrTempAllctr)
{
ptrTempAllctr = malloc(sizeof(int));
if (ptrTempAllctr == NULL) {
perror("in allocater() memory allocation error");
exit(EXIT_FAILURE);
}
}
int main()
{
int *ptrMain = NULL;
allocater(ptrMain);
if (ptrMain == NULL) {
printf("ptrMain is points to NULL\n");
return 1;
}
return 0;
}
考虑上面的程序(
noIndirection.c
),它有一个变量
ptrMain
,是一个指向整数的指针。如果将其传递给函数,则在函数作用域(体)中创建一个临时指针变量,因为函数参数是临时变量,当它们超出范围时会被删除。
临时指针变量
ptrTempAllctr
(它是一个参数)将指向调用者(
main
)函数的变量
ptrMain
(它指向
NULL
),当它作为参数传递给函数时。
如果我们使用
malloc()
或将另一个指针分配给临时变量
ptrTempAllctr
,那么它将指向它,但在调用者(
main
)函数中的指针变量仍然指向相同的数据(即
NULL
),它在函数调用之前指向的位置。
当被调用的(
allocater()
)函数超出范围时,临时指针变量从堆栈弹出,内存保持未分配状态,我们就会遇到内存泄漏。为了绕过这个限制,我们需要使用多重间接。
多重间接:
Multiple indirection when we use of pointer/s to pointer/s in varying level(with multiple `*`) eg: `int **pp, int ***ppp`, etc.
我们使用取地址符(&
)来给它们赋值。
多重间接指针类型变量是允许我们将其作为指向指针变量本身的指针,从而修复上述程序的错误。这使我们能够通过以下方式将 ptrMain
的地址传递给 allocater()
:
allocater(&ptrMain);
因此,上述程序 noIndirection.c
不允许我们这样做,可以参考程序 withIndirection.c
以实现这种多重间接性。
在这种情况下,我们需要使用整型指针指针(int **ptrMain
) 作为allocater()
函数的函数参数来解决上述有缺陷的程序(noIndirection.c)。
以下程序中使用了多重间接性来解决先前程序中的 bug。
#include <stdio.h>
#include <stdlib.h>
void trueAllocater(int **ptrTrueAllocater)
{
*ptrTrueAllocater = (int *) malloc(sizeof(int));
if (ptrTrueAllocater == NULL) {
perror("in trueAllocater() memory allocation error");
exit(EXIT_FAILURE);
}
}
int main(void)
{
int *ptrMain = NULL;
trueAllocater(&ptrMain);
if (ptrMain == NULL) {
printf("memory not allocated\n");
return EXIT_FAILURE;
}
printf("memory allocated and assigned to ptrMain");
printf(" from trueAllocater\n");
free(ptrMain);
return EXIT_SUCCESS;
}
从现在开始,请参考 withIndirection.c
程序来解决我们的问题。
为了解决我们的问题,我们需要将指针变量 ptrMain
的地址(trueAllocater(&ptrMain);
)传递给 trueAllocater,以便在 trueAllocater()
函数或另一个函数中后续需要修改 ptrMain
所指向的位置时,可以更改它,
为了实现这一点,该函数需要接受具有正确间接级别的指针,也就是在传递变量时对参数声明添加另一个*,对于我的当前理解,确保传递的变量符合要求。
换句话说,我们需要将 trueAllocater()
函数的参数从 int *
更改为 int **
,以满足间接级别。
当函数将调用者参数变量 ptrMain
的实际地址作为参数传递时,函数中的临时 ptrTrueAllocater
参数变量指向主调函数 (main
) 中指针变量 ptrMain
的地址本身,而不是它在函数 (main
) 中指向的内容(即 NULL
)。
如果我们对 ptrTrueAllocater
变量进行解引用,则会显示 ptrMain
所指向的地址,因为临时变量 ptrTrueAllocater
指向调用者 (main
) 的 ptrMain
变量本身,而不是它所包含的内容。
通过对解引用的 ptrTrueAllocater
变量的内容进行查看,可以显示指针变量 ptrMain
所指向的数据的地址,因此需要再次对其进行解引用以获取最终的数据。
因此,我们需要先进行一次解引用以获得 ptrMain
所指向的地址,以便将其指向想要指向的位置,然后再进行两次解引用以获取由 ptrMain
指向的实际数据,即 NULL
。
@PaulWicks 所期望的更改意图是你需要先进行一次解引用以分配或更改其指向的位置。
使用指针进行多重间接引用的目的是创建多维数组并传递需要指向某些内容的指针参数。
我们需要根据我们需要操作的类型来更改变量,如下所示:
每增加一个 *,声明中的指针间接级别就会增加一级,并且每次解引用都会降低指针间接级别,使其更接近数据。
我们可以通过将地址返回给调用函数并将其分配给所需的指针变量来解决这个问题。
是的,我们可以使用这种多级指针语法来创建一维或多维数组。初学者可能会感到困惑,但如果他们花时间阅读大量的代码,他们就能找到它们之间的区别。
如果我错了,请纠正我,提供反馈并让我知道多级指针的其他用途。对我的糟糕英语表示歉意。以下是帮助我理解多级指针的资源:
https://boredzo.org/pointers/#function_pointers
https://cseweb.ucsd.edu/~ricko/rt_lt.rule.html