结论提到前面来:永远要意识到传参是在操作参数的拷贝。 所有人都知道如果参数是一个出参,那么需要传它的地址。 原因是函数传参本质上都是值传递,即拷贝了一份传递进来的内存对象。 如果直接传值,那么函数中操作的是它的副本。 但传指针的话,函数中操作的虽仍是一个副本,但这个副本是指针,其指向了本体的地址。于是可以通过这个指针来操作实际的本体。

一种常见的情况,如果需要获取一个在线设备列表。首先我们需要一个数组,数组长度未知。那么要做两件事,1是分配空间,2是填充数据。 一般的做法是:

T* p = NULL;
GetOnlineDevice(&p);

问题来了,如果直接传p行不行?p不就是指针么? 函数中会拿到p的副本,指向了数组头元素,那么操作p+i就可以操作数组了。 其实答案也在这句话中,就是你不知道这个i是多少,更重要的是,这个p指向的本体是谁?在这里是NULL,那么你操作了p指向的本体就是在操作NULL,很恐怖。

再想得统一一点,为什么要传地址?因为你要改变这个参数本身的。如果不传地址则操作的是参数的值的副本。如果你需要填充一个数组对象,当你有一个一级指针时,其实你并不需要改变这个指针的(你是要改变指针指向的那片地址里的)。那其实就不需要传地址。那么为什么上面的情况要传地址呢?因为你需要改变这个指针的了,你需要让这个指针指向一个新分配的空间。

所以这里传地址,是为了改变p的值,也就是它的指向。如果我自己分配了p的值呢?那确实可以不用传地址。函数可以变成这样:

int num = 0;
GetOnlineDeviceNum(&num);
T* p = (T*)malloc(sizeof(p) * num);
GetOnlineDevice(p);

一句话,传地址是为了改变参数的值,否则你操作的永远是参数的副本。

加深一下印象: 如果上面的代码只传p:没法改变p的值,也就是p的指向。 永远要意识到传参是在操作参数的拷贝。

相关笔记

  • 指针和数组
  • 浅拷贝&深拷贝