浅谈指向指针的指针

以便在函数内部修改该指针的值,然后调用func()函数时传入&p作为参数,用来存储单链表中每个节点的数据(即整型变量)和下一级节点地址(即一级指针)!

在C语言中,我们经常会遇到需要传递指针作为参数的情况,但是如果我们需要修改指针本身的值,该怎么办呢?这时候就需要用到“指向指针的指针”了。

所谓“指向指针的指针”,就是一个存储着另一个变量地址(即一级地址)的变量。它本身也是一个地址,即二级地址。通过它可以访问三级或更高级别的数据。

在C语言中定义一个“int**”类型的变量p,其实就相当于定义了一个二维数组。因为p存储了第一维数组元素(即一级地址),而每个一级地址又对应着第二维数组元素(即二级地址)。如下图所示:

那么,“int**”类型变量p究竟有什么作用呢?下面我们通过代码和实例来详细讲解。

首先,在函数调用时,我们可以传递一个指向指针的指针作为参数,以便在函数内部修改该指针的值。例如:

“`

void func(int** p)

{

*p = (int*)malloc(sizeof(int));

**p = 10;

}

int main()

int* p = NULL;

func(&p);

printf(“%d”, *p); //输出10

return 0;

这里定义了一个名为“func”的函数,其参数是一个类型为“int**”的指针变量。在函数内部,我们首先调用了malloc()动态分配了一段大小为“sizeof(int)”的内存空间,并将其地址存储到*p中。接着通过二级解引用符(即两个星号)来访问该内存空间,并将数值设置为10。

在main()函数中,我们定义了一个名为“p”的整型指针变量,并将其初始化为空(NULL)。然后调用func()函数时传入&p作为参数。由于&p是一个二级地址,“int**”类型的形参可以正好接收它。在func()执行完毕后,“*p”就成了10。

除此之外,“指向指针的指针”还可以用于动态数组(即多维数组)和链表等数据结构中。

对于动态数组而言,“int**”类型变量可以帮助我们实现多维数据结构中各个维度之间相互独立、灵活可控、易于修改等优点。例如:

int row = 3, col = 4;

int** p = (int**)malloc(row * sizeof(int*));

for(int i=0; i<row; ++i)

*(p+i) = (int*)malloc(col * sizeof(int));

for(int j=0; j<col; ++j)

*(*(p+i)+j) = (i+1) * (j+1);

{

printf(“%4d”, *(*(p+i)+j));

printf(“n”);

}

浅谈指向指针的指针

这里定义了一个名为“p”的“int**”类型变量,用来存储动态二维数组的首地址。在代码中,我们首先通过malloc()函数分配了一个长度为3的指针数组,并将其地址赋给*p。接着通过循环遍历该数组,并分别调用malloc()函数分配长度为4的整型数组空间,并将其地址存储到对应的一级指针中。

然后,我们再次使用循环遍历整个二维数组,并通过二级解引用符(即两个星号)来访问每个元素并设置数值(此处采用了乘法表的方法)。最后再次遍历整个二维数组并输出结果。

运行程序可以得到如下输出结果:

最后,我们再来看一个关于链表的例子。假设我们需要定义一个单链表,其中每个节点都包含两个整型成员变量:data和next。那么如何通过“指向指针的指针”实现插入新节点和删除节点等操作呢?例如:

typedef struct _Node

int data;

struct _Node* next;

} Node;

void insert(Node** head, int val)

Node* newNode = (Node*)malloc(sizeof(Node));

newNode->data = val;

newNode->next = *head;

*head = newNode;

void remove(Node** head, int val)

Node* curr = *head;

if(curr == NULL) return;

if(curr->data == val)

*head = curr->next;

while(curr != NULL && curr->next != NULL)

if(curr->next->data == val)

curr->next = curr->next->next;

else

curr = curr -> next;

//…

这里首先定义了一个名为“Node”的结构体,用来存储单链表中每个节点的数据(即整型变量)和下一级节点地址(即一级指针)。然后我们定义了两个函数insert()和remove(),分别用于在单链表中插入新节点和删除指定节点。

在insert()函数中,我们首先通过malloc()函数动态分配了一个大小为“sizeof(Node)”的内存空间,并将其地址存储到newNode变量中。然后设置newNode的data成员为val,next成员为原链表头指针*head,最后将newNode赋给*head即可完成插入操作。

在remove()函数中,则需要遍历整个单链表并查找待删除的节点。由于head本身就是一个指向一级指针的二级指针(即“Node**”类型),所以直接使用curr = *head来遍历整个链表即可。如果找到要删除的节点,则将该节点从当前位置断开(即curr->next=curr->next->next),否则继续往下遍历。

最后,在main()函数中定义了一个名为“head”的二级地址变量,并初始化为空(NULL)。然后可以通过调用insert()和remove()等操作来修改该单链表,并输出结果验证程序正确性。

以上就是关于“指向指针的指针”的详细介绍。虽然这种数据类型