在计算机中,程序运行时,数据要被存储到内存中,而每个内存都有一个内存地址,如下图:
内存地址为1001存储着数值1,内存地址为1002存储着数值2.(这里内存地址只是为了方便而这样写,计算机的内存地址表示不一定这样)
然后咱们看链表的存储结构:
typedef struct Node
{
int data;
struct Node* next;
}LNode, *LinkList;
// LNode为结构体,LinkList为结构体指针
其中LNode表示结构体,LinkList表示结构体指针。
再看传入结构体指针LinkList L 的 DontChange_point()函数:
void DontChange_point(LinkList L)
{
printf("函数DontChange_point中L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
L = (LinkList)malloc(sizeof(LNode));
L->data = 2;
L->next = NULL;
printf("现在L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
return;
}
再看传入指向结构体指针的指针LinkList *L(二级指针)的Change_point()函数:
void Change_point(LinkList* L)
{
printf("L指向的地址为:%p\n", L);
printf("存储L的地址为:%p\n", &L);
*L = (LinkList)malloc(sizeof(LNode));
(*L)->data = 2;
(*L)->next = NULL;
return;
}
那传入结构体的指针和指向结构体指针的指针区别呢?
先看下图:
首先咱们将结构体存储在1(内存地址为1001)处,而指向结构体的指针 L 保存的便是结构体的地址1001(即解引此地址(*L)可以得到结构体),而这个结构体指针需要内存来存储它,故其也有一个地址(即内存地址2001保存了L,L保存了地址2001上的数据(即1001),解引此地址(2001)可以得到内存地址1001,再解引1001便可得到结构体,双重解引),即内存地址2001保存着内存地址1001(也就是L),而内存地址1001保存着结构体。
可能这有点迷糊,咱们可以这样理解就是咱们可以把内存地址想成一个盒子,将结构体想成是一件物品,编号为1001(相当于内存地址1001)的盒子(即L)装着这个物品(即结构体),如果我们将这个盒子打开就可以得到这个物品(结构体),其实这个过程相当于解引结构体指针(指针解引),然后咱们再把编号为2001的盒子把编号为1001的盒子(即L)装起来,咱们是不是要打开两次盒子(一次为2001,一次为1001)才能得到这个物品(相当于双重解引)。
传入结构体指针
,相当于把内存地址1001赋给了DontChange_point函数中的 L(传址),但 L不一定需要指向这块内存地址(1001),其也可以指向别的内存地址,当其指向别的地址,然后再进行操作,会不会影响我们之前传入的内存1001里的结构体呢?如:
void DontChange_point(LinkList L)
{
printf("函数DontChange_point中L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
L = (LinkList)malloc(sizeof(LNode));
L->data = 2;
L->next = NULL;
printf("现在L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
return;
}
这个指针L指向了用malloc()函数分配的内存,并且进行了修改L指向的结构体的操作,但它会影响我们之前传入的地址所指向的结构体吗?咱们用程序说话:
int main(void)
{
LinkList L;
L = (LinkList)malloc(sizeof(LNode));
L->data = 1;
L->next = NULL;
printf("L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
DontChange_point(L);
printf("现在main()函数中L指向的data为:%d\n", L->data);
return 0;
}
程序输出:
在main()函数结构体指针L指向的地址和刚传入DontChange_point()函数的地址L是一致的,但保存这个结构体指针的地址确是
不一致
的,说明是两个变量(main函数里的L和DontChange_point()函数的L)是不一样的。故后面改变DontChange_point()函数的L的指向,影响不到main()函数里的L,故在DontChange_point()函数的L对结构体的操作影响不了main()函数中L指向的结构体,而事实也证明如此,两次输出都是1,并没有因为DontChange_point()函数的L的操作而改变为结构体的data由1变为2.
如下图:
刚开始,
DontChange_point()函数的L的指向
后面DontChange_point()函数的L经过malloc()函数进行分配:
而
传入指向结构体指针的指针
,相当于把main()函数中保存L的地址给传进去了,然后再这块地址上做的操作会不会影响外面main()函数中的L呢?咱们直接上程序:
void Change_point(LinkList* L)
{
printf("L指向的地址为:%p\n", L);
printf("存储L的地址为:%p\n", &L);
*L = (LinkList)malloc(sizeof(LNode));
(*L)->data = 2;
(*L)->next = NULL;
return;
}
int main(void)
{
LinkList L;
L = (LinkList)malloc(sizeof(LNode));
L->data = 1;
L->next = NULL;
printf("L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
Change_point(&L); // 获取保存L的地址
printf("现在main()函数中L指向的data为:%d\n", L->data);
return 0;
}
咱们在Change_point()函数中,将传入保存mian()函数中L的地址赋给了Change_point()函数L,再对这块内存要保存的数据进行修改(修改这块内存要保存的地址,利用malloc()函数进行分配),即这块内存上的数据要改变,而main()函数的L指向的是这块内存的数据,故其也跟着改变,那事实是不是这样呢,咱们看程序输出。
程序输出:
程序输出说明,在Change_point()函数的操作影响到了外面main()函数的L,并且Change_point()函数中的L和外面main()函数保存结构体指针L的地址是一致的,说明对Change_point()函数中L的地址上所改变的内容会影响到main()函数的L(因为main()函数中的L是保存这块内存的数据信息)。程序输出也证明了事实如此,在没执行函数前,L->data = 1,指行函数后L->data = 2。
如下图:
刚开始:(下面的L均代表的是main()函数中的L)
利用malloc()函数进行操作后:
LinkList &L是C++的指针引用,其相当于LinkList *L,分析也类似分析LinkList *L,这里就不介绍了。
总的来说:
在参数为结构体指针的函数里,你可以对这个结构体指针所指向的内容进行修改,但函数外的结构体指针一直会指向这块内存(不会因为函数参数所指向别处,而跟着指向别处)。也就是说如果函数的参数(结构体指针)没有改变指向(指向别处),函数对指针所指向的内容进行修改,函数外的结构体指针(传入函数的指针)所指向的内容也会改变,但若函数的参数改变指向(即不指向传入指针指向的内存地址,其修改的内容不会影响到函数外结构体指针所指向的内容,即函数外结构体指针之前指向的内容不会改变)。
参数为结构体指针的函数,不会修改函数外结构体指针所指向的内存地址,但可以修改结构体指针指向的结构体。
在参数为指向结构体指针的指针,
会影响到函数外的结构体指针所指向的地址
,进而影响结构体指针指向的结构体。
所以当我们的函数不需要修改函数外结构体指针所指向的内存地址,同时又想修改结构体指针所指向的结构体,便可以将函数的参数设为结构体指针。但如果我们的函数想修改函数外结构体指针所指向的内存地址时,我们便要传入指向结构体指针的指针,不可传入结构体指针。
内容到此结束,谢谢大家的阅读!!
测试程序:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node* next;
}LNode, *LinkList;
void Change_point(LinkList* p);
void DontChange_point(LinkList p);
int main(void)
{
LinkList L;
L = (LinkList)malloc(sizeof(LNode));
L->data = 1;
L->next = NULL;
printf("L指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
DontChange_point(L);
printf("现在main()函数中L指向的data为:%d\n", L->data);
Change_point(&L);
printf("现在main()函数中L指向的data为:%d\n", L->data);
return 0;
}
void Change_point(LinkList* L)
{
printf("L指向的地址为:%p\n", L);
printf("存储L的地址为:%p\n", &L);
*L = (LinkList)malloc(sizeof(LNode));
(*L)->data = 2;
(*L)->next = NULL;
return;
}
void DontChange_point(LinkList L)
{
printf("函数DontChange_point中L(没改变其指向)指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
L = (LinkList)malloc(sizeof(LNode));
L->data = 2;
L->next = NULL;
printf("现在L(改变了其指向)指向的地址为:%p\n", L);
printf("L指向的data为:%d\n", L->data);
printf("存储L的地址为:%p\n", &L);
return;
}