C語言(指標)

鋸齒流沙發表於2017-12-27

指標是C語言一個重要的概念,也是C語言的一個特色,正確的使用指標,可以使程式簡潔、緊湊、高效。

指標:是一個特定的型別資料的儲存地址,如一個變數的地址。

兩種儲存變數的方式:直接儲存和間接儲存。

直接儲存:按變數名儲存,在程式中定義的變數,編譯時系統為其分配記憶體單元。

間接儲存:使用指標,將變數的地址儲存賦給指標儲存。

void main(){
	int i = 100;
	int *p = &i;
	printf("這是i的地址:%#x\n 這是p的值:%#x\n", &i, p);
	printf("i的值:%d\n", *p);
	getchar();
}
複製程式碼

執行結果.png

從執行結果我們看到了指標p儲存的時候 i 的地址,*p得到的值是i的值100.

指標是特定資料型別的儲存地址,所以指標有資料型別的,但是地址是沒有型別的。 如上面的程式中,指標的型別是int型別

void main(){
	int i = 100;
	int *p = &i;
	printf("這是i的地址:%#x\n 這是p的值:%#x\n", &i, p);
	printf("i的值:%d\n", *p);
	double j = 23.4;
	p = &j;
	printf("p:%#x,  %lf\n",p,*p);
	getchar();
}
複製程式碼

執行結果.png

上面程式中最終得到的值是0.0000,這是因為指標賦值為double型別變數的地址,而通過sizeof(int)位元組讀取sizeof(double)位元組變數的值,是不允許的。這裡我們可以知道地址只是開始的位置,型別讀取到什麼位置結束。

懸空指標

如果一個指標變數,既沒有賦NULL值,也沒有指向有效的記憶體地址,則成為懸空指標。懸空指標的值是不確定的,直接操作導致系統崩潰,所以應該避免懸空指標的使用,定義指標變數的時候就要初始化。

NULL空指標

void main(){
	int i = 100;
	int *p =	NULL;
	p = &i;
	printf("\n\n\n i的值%d",*p);
	getchar();
}
複製程式碼

20170821151040.png

上面程式 p = NULL就是空指標。給一個指標賦予NULL值,NULL是一個指標值,任何型別的指標都可以賦予該值。

指標的兩個特殊運算子*和&

&:取地址運算子,返回操作物件的記憶體地址

*:間接訪問運算子,取指標所指單元的值。

多級指標

指標儲存的是變數的地址,儲存的這個變數還可以是一個指標變數

void main(){
	int i = 100;
	int* p1 =	NULL;
	//儲存i的地址
	p1 = &i;
	//儲存p1的地址
	int** p2 = &p1;
	//儲存p2的地址
	int*** p3 = &p2;

	printf("\n\n\n p1:%#x\n p2:%#x\n p3:%#x\n",p1,p2,p3);
	getchar();
}
複製程式碼

指標的運算

指標的運算,一般在陣列遍歷時才有意義,基於陣列在記憶體中線性排列的方式。

void main(){
	//陣列在記憶體中連續儲存
	int a[] = {10,20,30};
	//陣列變數名:a就是陣列的首地址
	int *p = a;
	printf("\na:%#x\n",a);
	printf("&a:%#x\n",&a);
	printf("&a[0]:%#x\n",&a[0]);
	printf("p:%#x\n", p);
	printf("開始*p:%d\n", *p);
	//指標的自增,向前移動sizeof(資料型別)個位元組
	p++;
	printf("p++後:%d\n", *p);
	//指標的自減
	p--;
	printf("p--後:%d\n", *p);
	getchar();
}
複製程式碼

執行結果.png

自增1或者自減1運算使指標值增加或者減少所指資料型別的長度值。 指向同一陣列不同元素的指標可以進行相減操作,結果為兩個指標之間相差元素的個數。

通過指標給陣列賦值


void main(){
	int a[5];
	int *p = a;
	int i = 0;
	for (;p < a+5; p++)
	{
		*p = i;
		i++;
	}
	p = a;
	for (int j = 0;  j < 5;  j++)
	{
		printf("\n  %d\n", *p);
		p++;
	}
	getchar();
}

複製程式碼

執行結果.png

函式指標


int add(int* a, int* b){
	return *a + *b;
}

void main(){
	int a, b;
	scanf("\n%d\n", &a);
	scanf("\n%d\n", &b);

	/*
	函式指標
	函式返回值型別,函式指標的名稱,函式的引數列表
	*/
	int(*func_add)(int* a, int* b) = add;
	int rs = func_add(&a, &b);
	printf("add result:%#d\n",rs);
	getchar();
}
複製程式碼

執行結果.png


int add(int a,int b){
	return a + b;
}

int minus(int a,int b){
	return a - b;
}

//msg函式需要傳遞一個函式指標引數
//類似於我們Java中的回撥函式
void msg(int(*func_p)(int a, int b), int m, int n){
	printf("執行回撥函式...\n");
	int r = func_p(m, n);
	printf("執行結果:%d\n",r);
}

void main(){
	//加法
	msg(add, 3, 3);
	//減法
	msg(minus, 5, 1);
	getchar();
}

複製程式碼

執行結果.png

相關文章