c語言之——const關鍵字

一、簡介

(1)const關鍵字,在C語言中用來修飾變量,表示這個變量不可更改。

我們可能首先想到的是經過它修飾的變量便是常量了。其實我們這種想法是錯誤的,其實 const 修飾的變量是隻讀的,其本質還是變量。它只是告訴編譯器該變量不能出現在賦值符號的左邊。

那麼,const修飾的變量真的不能修改嗎?我麼看如下代碼

#include <stdio.h>

int main(void)
{
	const int a = 5;
	//a = 6;				// error: assignment of read-only variable ‘a’
	int *p;
	p = (int *)&a;			// 這裏報警高可以通過強制類型轉換來消除
	*p = 6;
	printf("a = %d.\n", a);	// a = 6,結果證明const類型的變量被改了
	return 0;
}
  • const修飾的變量其實是可以改的(前提是gcc環境下)。
  • 對於某些編譯器,const修飾的變量是不可以改的。const修飾的變量到底能不能真的被修改,取決於具體的環境,C語言本身並沒有完全嚴格一致的要求。
  • 在gcc中,const是通過編譯器在編譯的時候執行檢查來確保實現的(也就是說const類型的變量不能改是編譯錯誤,不是運行時錯誤。)所以我們只要想辦法騙過編譯器,就可以修改const定義的常量,而運行時不會報錯。

對於const與編譯器的關係詳見如下文章:https://blog.51cto.com/12810168/2095264

圖片.png

 

二、const關鍵字與指針

const修飾指針有4種形式,區分清楚這4種即可全部理解const和指針。

第一種:const int *p;

第二種:int const *p;

第三種:int * const p;

第四種:const int * const p;

關於指針變量的理解,主要涉及到2個變量:第一個是指針變量p本身,第二個是p指向的那個變量(*p)。一個const關鍵字只能修飾一個變量,所以弄清楚這4個表達式的關鍵就是搞清楚const放在某個位置是修飾誰的。

const後面要是直接跟着指針變量,就是修飾指針變量。例如 int * const p3;       // p本身是cosnt的,p指向的變量不是const的

  • 常量指針是指針指向的內容是常量;
  • 指針常量是指指針本身是個常量,不能在指向其他的地址;
  • 指向常量的常指針,以上兩種的結合。
#include <stdio.h>

int main(void)
{
	int a = 5;
	
	// 第一種
	const int *p1;		// p本身不是cosnt的,而p指向的變量是const的
	// 第二種
	int const *p2;		// p本身不是cosnt的,而p指向的變量是const的
	
	
	// 第三種
	int * const p3;		// p本身是cosnt的,p指向的變量不是const的
	// 第四種
	const int * const p4;// p本身是cosnt的,p指向的變量也是const的
	
	*p1  = 3;		// error: assignment of read-only location ‘*p1’
	p1 = &a;		// 編譯無錯誤無警告
	
	*p2 = 5;		// error: assignment of read-only location ‘*p2’
	p2 = &a;		// 編譯無錯誤無警告
	
	*p3 = 5;		// 編譯無錯誤無警告
	p3 = &a;		// error: assignment of read-only variable ‘p3’
	
	p4 = &a;		// error: assignment of read-only variable ‘p4’
	*p4 = 5;		// error: assignment of read-only location ‘*p4’

	return 0;
}

note:const與typedef結合使用時,需要注意:

(1)typedef int *PINT; const PINT p2; 相當於是int *const p2;

(2)typedef int *PINT; PINT const p2; 相當於是int *const p2;

(3)如果確實想得到const int *p;這種效果,只能typedef const int *CPINT; CPINT p1;

 

三、const關鍵字與函數形參

(1)const一般用在函數參數列表中,用法是const int *p;(意義是指針變量p本身可變的,而p所指向的變量是不可變的)。

(2)const用來修飾指針做函數傳參,作用就在於聲明在函數內部不會改變這個指針所指向的內容,所以給該函數傳一個不可改變的指針(char *p = "linux";這種)不會觸發錯誤;而一個未聲明爲const的指針的函數,你給他傳一個不可更改的指針的時候就要小心了。

(3)編程中函數的輸入和輸出都是靠函數形參的,返回值只是用來表示函數執行的結果是對(成功)還是錯(失敗)。如果這個參數是用來做輸入的,就叫輸入型參數;如果這個參數的目的是用來做輸出的,就叫輸出型參數。(在典型的linux風格函數中,返回值是不用來返回結果的,而是用來返回0或者負數用來表示程序執行結果是對還是錯,是成功還是失敗)。

#include <stdio.h>

int multip5_3(int a, int *p);


int main(void)
{
	int a, b = 0, ret = -1;
	
	a = 30;
	ret = multip5_3(a, &b);
	if (ret == -1)
	{
		printf("出錯了\n");
	}
	else
	{
		printf("result = %d.\n", b);
	}
	

	return 0;
}


int multip5_3(int a, int *p)
{
	int tmp;

	tmp = 5 * a;
	if (tmp > 100)
	{
		return -1;
	}
	else
	{
		*p = tmp;
		return 0;
	}
}

小結:

看到一個函數的原型後,怎麼樣一眼看出來哪個參數做輸入哪個做輸出?函數傳參如果傳的是普通變量(不是指針)那肯定是輸入型參數;如果傳指針就有2種可能性了,爲了區別,經常的做法是:如果這個參數是做輸入的(通常做輸入的在函數內部只需要讀取這個參數而不會需要更改它)就在指針前面加const來修飾;如果函數形參是指針變量並且還沒加const,那麼就表示這個參數是用來做輸出型參數的。

譬如C庫函數(#include <string.h> 和 #include <stdio.h>)中strcpy函數

char *strcpy(char* dest, const char *src);

REF:

https://blog.51cto.com/12810168/2095264

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章