對 “C語言指標變數作為函式引數” 的個人理解

莫懶發表於2020-09-25


此文為自己的一些理解和看法,如有錯誤,請各位大佬指出。

C指標

C中每個變數都有一個記憶體空間,每一個記憶體空間都有自己的地址,我們可以對變數使用 & 來獲取變數地址,如下所示:

//執行程式碼
#include<stdio.h>

int main() {
	int num = 1;
	float fnum = 2.1f;
	char letter = 'a';

	printf("num 的地址為 %p\n", &num);
	printf("fnum 的地址為 %p\n", &fnum);
	printf("letter 的地址為 %p\n", &letter);

	return 0;
}
//執行結果
num 的地址為 000000CE34B6FB54
fnum 的地址為 000000CE34B6FB74
letter 的地址為 000000CE34B6FB94

何為指標

指標是一個變數,它的值為另一個變數的地址,即,記憶體空間的直接地址。我們在使用指標儲存其他變數地址之前,先進行宣告。

DataType *ptr;
//DataType為變數型別,ptr為指標名稱
int *iptr;		/*整型指標*/
float *fptr;		/*float型指標*/
char *cptr;	/*字元型指標*/

所有資料型別對應指標的值的型別都是一樣的,都是一個代表記憶體地址的十六進位制數。
不同資料型別的指標之間唯一的不同是,指標所指向的變數或常量的資料型別不同。

指標的使用

建立一個指標iptr儲存num的地址。其中對指標使用星號*獲取指標指向的值。

#include<stdio.h>

int main() {
	int num = 1;
	int* iptr = &num;

	printf("變數 num 的值為 %d\n", num);
	printf("指標 iptr 所指向的值為 %d\n", *iptr);
	printf("變數 num 的地址為 %p\n", &num);
	printf("指標 iptr 所儲存的地址為 %p\n", iptr);

	return 0;
}
變數 num 的值為 1
指標 iptr 所指向的值為 1
變數 num 的地址為 000000A1E514F594
指標 iptr 所儲存的地址為 000000A1E514F594

函式引數

當呼叫函式時,把實參的值複製給形參,然後函式用形參來進行相關操作。在函式內形參的值變化並不會影響實參的值變化。

#include<stdio.h>

void test(int num) {
	printf("test中 num的值為%d 地址為%p\n", num, &num);
}

int main() {
	int num = 1;
	
	printf("main中 num的值為%d 地址為%p\n", num, &num);
	test(num);

	return 0;
}
main中 num的值為1 地址為000000D6EA4FFC24
test中 num的值為1 地址為000000D6EA4FFC00

可以看出當函式呼叫時,形參只是複製了實參的值,它們的記憶體地址是不一樣的。
所以當形參改變自己的值時,相應的實參是不會變化的。

#include<stdio.h>

void test(int num) {
	printf("test中 num的值為%d 地址為%p\n", num, &num);
	num = 2;
	printf("test中 num的值為%d 地址為%p\n", num, &num);
}

int main() {
	int num = 1;
	
	printf("main中 num的值為%d 地址為%p\n", num, &num);
	test(num);
	printf("main中 num的值為%d 地址為%p\n", num, &num);

	return 0;
}
main中 num的值為1 地址為000000062894FA04
test中 num的值為1 地址為000000062894F9E0
test中 num的值為2 地址為000000062894F9E0
main中 num的值為1 地址為000000062894FA04

test函式內改變num的值時,是對形參num操作,因此實參num的值仍為1。

指標作為函式引數

為何函式需要指標作為引數呢?
從上面可以看出,當我們想用test函式對main中的num值進行修改時,其實main中的num是沒有變化的。如果我們想要通過函式操作改變main中num值時,該怎麼操作呢?這就需要指標來進行相關的操作,從而實現我們的需求(ps:當然我們也可以通過return返回我們需要的值)。

為什麼通過指標能修改實參值

我們通過下面的一個例子來說明

#include<stdio.h>

void test(int *num_ptr) {
	printf("test中 num_ptr儲存的地址為%p 所指向的值為%d\n", num_ptr, *num_ptr);
	*num_ptr = 2;
	printf("test中 num_ptr儲存的地址為%p 所指向的值為%d\n", num_ptr, *num_ptr);
}

int main() {
	int num = 1;
	
	printf("main中 num的地址為%p 值為%d\n", &num, num);
	test(&num);
	printf("main中 num的地址為%p 值為%d\n", &num, num);

	return 0;
}
main中 num的地址為000000943AB2F6B4 值為1
test中 num_ptr儲存的地址為000000943AB2F6B4 所指向的值為1
test中 num_ptr儲存的地址為000000943AB2F6B4 所指向的值為2
main中 num的地址為000000943AB2F6B4 值為2

此時test的實參為num的地址,形參num_ptr複製的是num的地址。雖然在函式中對形參的值進行改變時,實參不會受到影響。但有趣的是,num_ptr的值是地址,當我們通過修改此指標指向的內容時,num_ptr還是儲存的是num的地址,num的地址沒有收到影響但num值已經改變。

舉個例子,把實參當一把鑰匙,形參當做另外配的鑰匙。
在函式內你重新改造形參鑰匙(即更改內容),實參鑰匙沒有影響。
如果這時候有一個房間,實參是房間的鑰匙(指標為鑰匙,指向的記憶體為房間),由於形參鑰匙與實參鑰匙一樣,故通過形參鑰匙可以修改房間的佈局(修改指向的記憶體內容)。當函式執行完後,形參鑰匙被丟棄,房間佈局已改變。
如果拿到形參鑰匙,對鑰匙進行改造,形參鑰匙就只能開另外一個房間。而原房間不受影響。

一句話

形參只是複製實參的值,形參如何變化不管實參的事。但形參通過指標修改指向的內容,就會影響實參所指向的內容,雖然此時形參和實參的值一樣。

相關文章