C語言 | 指針(C語言強化)

博主github:https://github.com/MichaelBeechan
博主CSDN:https://blog.csdn.net/u011344545

******************************************/
————————————————

指針是一個特殊的變量,它裏面存儲的數值被解釋成爲內存裏的一個地址。C裏面所有類型指針本身佔用的內存都是4個字節。要搞清一個指針需要搞清指針的四方面的內容:指針的類型、指針所指向的類型、指針的值或者叫指針所指向的內存區、指針本身所佔據的內存區。
1、指針的類型
從語法的角度看,你只要把指針聲明語句裏的指針名字去掉,剩下的部分就是這個指針的類型。
(1) int*p;//指針的類型是int*
(2) char*p;//指針的類型是char*
2、指針所指向的類型
當你通過指針來訪問指針所指向的內存區時,指針所指向的類型決定了編譯器將把那片內存區裏的內容當做什麼來看待。從語法上看,你只須把指針聲明語句中的指針名字和名字左邊的指針聲明符*去掉,剩下的就是指針所指向的類型。
(1)int*p; //指針所指向的類型是int
(2)char*p; //指針所指向的的類型是char
3、指針的值或者叫指針所指向的內存區或地址
指針的值是指針本身存儲的數值,這個值將被編譯器當作一個地址,而不是一個一般的數值。在32 位程序裏,所有類型的指針的值都是一個32 位整數,因爲32 位程序裏內存地址全都是32 位長。指針所指向的內存區就是從指針的值所代表的那個內存地址開始,長度爲sizeof(指針所指向的類型)的一片內存區。以後,我們說一個指針的值是XX,就相當於說該指針指向了以XX 爲首地址的一片內存區域;我們說一個指針指向了某塊內存區域,就相當於說該指針的值是這塊內存區域的首地址。指針所指向的內存區和指針所指向的類型是兩個完全不同的概念。在例一中,指針所指向的類型已經有了,但由於指針還未初始化,所以它所指向的內存區是不存在的,或者說是無意義的。以後,每遇到一個指針,都應該問問:這個指針的類型是什麼?指針指向的類型是什麼?該指針指向了哪裏?(重點注意)
4、指針本身所佔據的內存區
指針本身佔了多大的內存?你只要用函數sizeof(指針的類型)測一下就知道了。在32 位平臺裏,指針本身佔據了4 個字節的長度。指針本身佔據的內存這個概念在判斷一個指針表達式(後面會解釋)是否是左值時很有用。
5、指針的算術運算
指針可以加上或減去一個整數。指針的這種運算的意義和通常的數值的加減運算的意義是不一樣的,以單元爲單位。例如:
char a[20];
int *p=(int *)a; //強制類型轉換並不會改變a 的類型
p++;
在上例中,指針p 的類型是int*,它指向的類型是int,它被初始化爲指向整型變量a。接下來的第3 句中,指針p 被加了1,編譯器是這樣處理的:它把指針p 的值加上了sizeof(int),在32 位程序中,是被加上了4,因爲在32 位程序中,int 佔4 個字節。由於地址是用字節做單位的,故p 所指向的地址由原來的變量a 的地址向高地址方向增加了4 個字節。
一個指針p 加(減)一個整數n 後,結果是一個新的指針p_new,p_new的類型和p 的類型相同,p_new 所指向的類型和p 所指向的類型也相同。p_new 的值將比p 的值增加(減少)了n 乘sizeof(p 所指向的類型)個字節。就是說,p_new 所指向的內存區將比p 所指向的內存區向高(低)地址方向移動了n 乘sizeof(p所指向的類型)個字節。
指針和指針進行加減:
兩個指針不能進行加法運算,這是非法操作,因爲進行加法後,得到的結果指向一個不知所向的地方,而且毫無意義。兩個指針可以進行減法操作,但必須類型相同,一般用在數組方面。
6、運算符&和*
這裏&是取地址運算符,*是間接運算符。
&a 的運算結果是一個指針,指針的類型是a 的類型加個*,指針所指向的類型是a 的類型,指針所指向的地址嘛,那就是a 的地址。
*p 的運算結果就五花八門了。
總之*p 的結果是p 所指向的東西,這個東西有這些特點:它的類型是p 指向的類型,它所佔用的地址是p所指向的地址。
7、指針表達式
一個表達式的結果如果是一個指針,那麼這個表達式就叫指針表達式。
由於指針表達式的結果是一個指針,所以指針表達式也具有指針所具有的四個要素:指針的類型,指針所指向的類型,指針指向的內存區,指針自身佔據的內存。
當一個指針表達式的結果指針已經明確地具有了指針自身佔據的內存的話,這個指針表達式就是一個左值,否則就不是一個左值。
8、數組和指針的關係
一般而言數組名array 代表數組本身,類型是int[10],但如果把array 看做指針的話,它指向數組的第0 個單元,類型是int* ,所指向的類型是數組單元的類型即int
例:char *str[3]={
			"Hello,thisisasample!",
			"Hi,goodmorning.",
			"Helloworld"
};
上例中,str 是一個三單元的數組,該數組的每個單元都是一個指針,這些指針各指向一個字符串。把指針數組名str當作一個指針的話,它指向數組的第0號單元,它的類型是char **,指向的類型是char *
*str 也是一個指針,它的類型是char *,它所指向的類型是char,它指向的地址是字符串"Hello, this is a sample!"的第一個字符的地址,即’H’的地址。注意:字符串相當於是一個數組,在內存中以數組的形式儲存,只不過字符串是一個數組常量,內容不可改變,且只能是右值.如果看成指針的話,他即是常量指針,也是指針常量.
str+1 也是一個指針,它指向數組的第1 號單元,它的類型是char**,它指向的類型是char*
*(str+1)也是一個指針,它的類型是char*,它所指向的類型是char,它指向"Hi, good morning."的第一個字符’H’
數組的數組名(數組中儲存的也是數組)的問題
聲明瞭一個數組TYPE array[n],則數組名稱array 就有了兩重含義:
第一,它代表整個數組,它的類型是TYPE[n]
第二,它是一個常量指針,該指針的類型是TYPE*,該指針指向的類型是TYPE,也就是數組單元的類型,該指針指向的內存區就是數組第0 號單元,該指針自己佔有單獨的內存區,注意它和數組第0 號單元佔據的內存區是不同的。該指針的值是不能修改的,即類似array++的表達式是錯誤的。
在不同的表達式中數組名array 可以扮演不同的角色。
在表達式sizeof(array)中,數組名array 代表數組本身,故這時sizeof 函數測出的是整個數組的大小。
在表達式*array 中,array 扮演的是指針,因此這個表達式的結果就是數組第0 號單元的值。sizeof(*array)測出的是數組單元的大小。表達式array+n(其中n=0,1,2,…)中,array 扮演的是指針,故array+n 的結果是一個指針,它的類型是TYPE *,它指向的類型是TYPE,它指向數組第n 號單元。故sizeof(array+n)測出的是指針類型的大小。在32 位程序中結果是4。指針和結構類型的關係
Struct MyStruct
{
	int a;
	int b;
	int c;
};
struct MyStruct ss={20,30,40};聲明瞭結構對象ss,並把ss 的成員初始化爲20,30 和40。
struct MyStruct *p=&ss;聲明瞭一個指向結構對象ss 的指針。它的類型是MyStruct *,它指向的類型是MyStruct
int *ps=(int*)&ss;聲明瞭一個指向結構對象ss 的指針。但是ps 和它被指向的類型p 是不同的。
通過p->a; p->b; p->c;方式訪問結構體元素。
指針和函數的關係
指針函數——指針函數是指帶指針的函數,即本質是一個函數。我們知道函數都有返回類型(如果不返回值,則爲無值型),只不過指針函數返回類型是某一類型的指針。其定義格式如下所示:
返回類型標識符 *返回名稱(形式參數表) {
	函數體
}
返回類型可以是任何基本類型和複合類型。返回指針的函數的用途十分廣泛。事實上,每一個函數,即使它不帶有返回某種類型的指針,它本身都有一個入口地址,該地址相當於一個指針。比如函數返回一個整型值,實際上也相當於返回一個指針變量的值,不過這時的變量是函數本身而已,而整個函數相當於一個“變量”。例如下面一個返回指針函數的例子:
float *find();
float *p;
p=find(score,m);
函數指針——指向函數的指針,即指向函數的指針變量函數的指針是指函數的入口地址,和數組名代表數組的首地址一樣,函數名代表函數的入口地址。若有一個指針變量,存放某一個函數的入口地址,我們可以通過指向這個函數的指針變量來調用函數。定義指向函數的指針變量 形式如下:
類型標識符(*變量標識符)();
{
	函數體
}
類型標識符是指針變量所指向的函數類型,變量標識符是指向函數的指針變量名。
例如: int(*p)()
定義了一個指向函數的指針變量p,它可以存放一類整型函數的入口地址,程序中把哪一個函數的入口地址賦給它,它就指向哪一個函數。
說明——形式int*p()定義的是指針函數頭,返回值是指向整型數據的指針值,而不是指向函數的指針變量。
(1)定義指向函數的指針變量,可以指向一類函數。
(2)定義指向函數的指針變量時,括號不能省略。
(3)對指向函數的指針變量p,p+i、p++、p--等運算無意義。
讓指針變量指向函數定義了指向函數的指針變量,就可以在指針變量與特定函數之間建立關聯,讓指針變量指向特定函數。 建立關聯的方法爲:
指針變量=函數名;一定要是同類型的同類型的,例如:
int*p)(int x,int y) int max(int x,int y)
p = max ; //將max函數的首地址賦給指針p
利用指針實現函數調用——指針變量一旦指向某函數,利用指針所指向的變量可以實現函數調用。 一般形式:
(*指針變量)(實參表); 如 (*p)(x,y);
#include<stdio>
int max(int x,int y) /* 聲明一個函數 */
{
	return(x > y ? x : y);
}
void main()
{
	int (*p)(int, int);/* 聲明一個函數指針 */
	int c;
	p = max;/* 將max函數的首地址賦給指針p */
	c=(*p)(a,b);/* 通過函數指針調用函數 */
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章