函式呼叫時用const保護指標

木凌雲 發表於 2022-12-01

當呼叫函式並且把指向變數的指標作為引數傳入時,通常會假設函式將修改變數(否則,為什麼函式需要指標呢?)。例如,如果在程式中看到語句

f(&x);

大概是希望f改變x的值。但是,f僅需檢查x的值而不是改變它的值也是可能的。指標可能高效的原因是:如果變數需要大量的儲存空間,那麼傳遞變數的值會浪費時間和空間。

可以使用單詞const來表明函式不會改變指標引數所指向的物件。const應放置在形式引數的宣告中,後面緊跟著形式引數的型別說明:

void f(const int *p)
{
    *p = 0; // wrong
}

這一用法表明p是指向“常整數”的指標。試圖改變*p是編譯器會檢查的一種錯誤。

問: 宣告void f(const int *p);是說函式f不能修改p嗎?

答:不是。這說明不能改變指標p指向的整數物件,但是並不阻止f改變p自身。

void f(const int *p)
{
    int j;
    *p = 0;    // wrong
    p = &j;    // legal
}

因為實際引數是按值傳遞的,所以透過使指標指向其他地方的方法給p賦新值不會對函式外部產生任何影響。

#include <stdio.h>

void f(const int *p);

int main(void)
{
	int i = 6; 
	int j = 10;
	printf("i = %d, j = %d\n", i, j);
	f(&j);
	printf("i = %d, j = %d\n", i, j);
	return 0;
}

void f(const int *p)
{
	int j = 33;
	p = &j;
}

/* result
i = 6, j = 10
i = 6, j = 10
*/

問:宣告指標型別的形式引數時,像下面這樣在引數名前面放置單詞const是否合法?

答:是合法的。然而效果不同於把const放在p的型別前面。在p的型別前面放置const可以保護p指向的物件。在p的型別後面放置const可以保護p本身:

void f(int * const p);
{
    int j;
    
    *p = 0;     // legal
    p = &j;     // wrong
}

這一特性並不經常用到。因為p很少是另一個指標(呼叫函式時的實際引數)的副本,所以極少有什麼理由保護它。更罕見的一種情況是需要同時保護p和它所指向的物件,這可以透過在p的型別前和後都放置const來實現。

void f(const int * const p)
{
    int j;
    
    *p = 0;    // wrong
    p = &j;    //wrong
}