大神們經(jīng)常說C語言是一種底層語言氏身,不像python啊巍棱,java啊這種高級編程語言。一直理解的不大好蛋欣,也不明白為啥C語言就底層了拉盾。只是覺得老拿C語言做單片機嵌入式的開發(fā),是不是就是底層了豁状。最近看數(shù)據(jù)結(jié)構(gòu)和算法,一會一個指針一會一個指針的總是弄混倒得,感覺對指針有一種若即若離的感覺泻红,既陌生有熟悉。決定重新回過頭來看他霞掺。
1指針
- 地址和指針有著千絲萬縷的關(guān)系谊路,計算機內(nèi)存中的每個位置都有一個地址標識,C語言中用指針來表示地址菩彬,聲明一個指針變量并不會自動給他分配任何內(nèi)存缠劝。在對指針進行間接訪問前,指針必須初始化:要么指向現(xiàn)有內(nèi)存(賦值)骗灶,要么動態(tài)分配新的內(nèi)存(malloc)惨恭。
- C標準定義了NULL指針,它作為一個特殊的指針常量耙旦,表示不指向任何位置脱羡,因而對一個NULL指針進行解引用操作同樣也是非法的。因而在對指針進行解引用操作的所有情形前,如常規(guī)賦值锉罐、指針作為函數(shù)的參數(shù)帆竹,首先必須檢查指針的合法性- 非NULL指針。
- 所有的指針進行顯示的初始化是種好做法
如果知道指針被初始化為什么地址脓规,就該把它初始化為該地址栽连,否則初始化為NULL
在所有指針解引用操作前都要對其進行合法性檢查,判斷是否為NULL指針侨舆,這是一種良好安全的編程風(fēng)格
1.1指針運算
- 自增自減:指向下一個地址或指向上一個地址
- 同類型指針相減:如果兩個指針指向同一個數(shù)組秒紧,相減的結(jié)果就是兩個指針之間的元素數(shù)目。注意:指針相加沒有意義态罪;不同類型的指針相減也沒有意義
- 指針加上或減去一個整型值:如一個float類型的指針加3表示指針的值增加3個float類型的大小噩茄。
- 如果對一個指針進行減法運算,產(chǎn)生的指針指向了數(shù)組中第1個元素前面的內(nèi)存位置复颈,那么它是非法的绩聘。
- 加法運算稍微不同,如果產(chǎn)生的指針指向了數(shù)組中最后一個元素后面的那個內(nèi)存地址耗啦,它是合法的,但不能對該指針執(zhí)行解引用操作凿菩,不過之后就不合法了(這和STL中迭代器尾部元素可指向尾部元素的下一個位置是一樣的道理)
插播:typedef 和#define有什么區(qū)別呢?
#define 是預(yù)處理指令帜讲,在編譯預(yù)處理時進行簡單地替換 衅谷,不做正確性檢查。
#define A 3+4
在程序中遇到3*A則會將A進行簡單的替換->3*3+4=13
再例如:
#define int_ptr int* int_ptr a,b; //a是int*類型的似将,而b是int型的
typedef int* int_ptr int_ptr a,b; //a和b都是int*類型的
typedef是在編譯時處理的获黔,他是在自己的作用域里給一個已經(jīng)存在的類型一個別名。
typedef char ElemType 把一個char型起一個別名叫ElemType在验,這樣的好處是玷氏,當你想將程序中的數(shù)據(jù)類型換成int型的時候,不用一個一個修改腋舌,只需修改typedef char ElemType為typedef int ElemType即可盏触。
1.2void *指針
C中提供一個特殊的指針類型: void *,它可以保存任何類型對象的地址。
void *表明該指針與一地址值相關(guān)块饺,但不清楚存儲在此地址上的對象的類型拄查。void *指針只支持以下幾種操作:
- 與另一個指針比較
- 給另外一個void *指針賦值
- void *指針當函數(shù)參數(shù)或返回值
不允許使用void *指針操作它指向的對象拴袭,值得注意的是函數(shù)返回void *類型時返回一個特殊的指針類型麻献,而不是向返回void 類型那樣無返回值赌渣。
1.3函數(shù)指針和指針函數(shù)
- 函數(shù)指針 int* f(int a, int b):本質(zhì)是個指針,它指向的是函數(shù)淮腾,指向函數(shù)的指針包含了函數(shù)的地址召庞,可以通過它來調(diào)用函數(shù)岛心。
- 指針函數(shù) int (*f)(int a, int b):本質(zhì)是個函數(shù),它的返回值是某個類型的指針
2 數(shù)組和指針
知乎上有個大神說:在軟開行業(yè)里有一句話叫沒有什么是不能通過增加一個抽象層解決的篮灼。比如說忘古,數(shù)組就是對“一系列連續(xù)內(nèi)存單元”的抽象,它的外觀表現(xiàn)為“一個固定大小的容器”知乎連接诅诱。從這個角度上來理解髓堪,似乎數(shù)組比指針更“高級”一些,指針相對更底層娘荡。
2.1數(shù)組名
- 聲明時:數(shù)組的屬性和指針的屬性不同干旁,在聲明數(shù)組時,同時分配了用于容納數(shù)組元素的空間炮沐;而聲明一個指針時争群,只分配了用于容納指針本身的空間。
- 表達式中:需要注意大年,數(shù)組名是指向數(shù)組第一個元素的首地址换薄,其本質(zhì)是一個常量指針(常指針),指針自身的值不能被改變翔试,如聲明一個數(shù)組:int arr[3]={1,2,3}轻要,則不能出現(xiàn)arr++,或arr+=3這類語句。但是可以有int num=*(arr+2)指向第三個元素
- 通過數(shù)組名引用數(shù)組元素時:改變第二個元素的值為100垦缅,arr[1]=100;當使用[]的方式引用數(shù)組元素時冲泥,在編譯器中都會轉(zhuǎn)換成指針的形式操作,arr+1和&arr[1]是一樣的壁涎,都表示第二個元素的首地址凡恍。
- 作為函數(shù)參數(shù):不管以指針的形式還是數(shù)組名的形式作為函數(shù)的參數(shù)時都會被轉(zhuǎn)換成指針。
void array_to_pointer(int *ia){……} //無需轉(zhuǎn)換
void array_to_pointer(int ia[ ]){……} //被轉(zhuǎn)換成*ia
void array_to_pointer(int ia[100 ]){……} //被轉(zhuǎn)換成*ia
void array_test(int ia[100])//ia被轉(zhuǎn)換成了指針不再是常指針了U颉=涝汀!
{
double da[10];
printf("%d", sizeof( ia ));
ia++; //沒錯誤庞溜,按指針進行處理而非數(shù)組名
//da++; //編譯錯誤,數(shù)組名是常指針
}
2.2指向數(shù)組的指針
指向數(shù)組的指針主要是用來對二維數(shù)組進行操作的碑定。
理解一下 int (*p)[100]:由于括號的優(yōu)先級是最高的流码,所以首先執(zhí)行解引用,表明了p是一個指針延刘,接下來是數(shù)組下標的引用漫试,說明p指向的是某種類型的數(shù)組,前面的int表明p指向的這個數(shù)組的每個元素都是整數(shù)碘赖。
當對一個一位數(shù)組的數(shù)組名取&操作時驾荣,返回的是一個指向數(shù)組的指針外构。
例如:
int arr[100]={0};//聲明一個數(shù)組
int *p=&arr;//一個指向數(shù)組的指針
int *q=arr; //arr是數(shù)組的首地址,q指向了數(shù)組的第一個元素
2.3指針數(shù)組
在聲明一個指向數(shù)組的指針時千萬不要丟到那個括號播掷,如:int (*p) [100]; 如果丟掉了括號那就完全改變了意圖审编,從而意外地聲明了一個指針數(shù)組。
指針數(shù)組就是一個數(shù)組他的所有元素都是指針歧匈。
int (\*p)[100];//指向數(shù)組的指針
int* p[100];//指針數(shù)組垒酬,以p為數(shù)組名的數(shù)組中存放的都是指針元素
插播:指針常量和常量的指針...
常量指針: const char* ptr ="hello"; char const* ptr="hello";內(nèi)容不能改,指針可改
指針常量: char* const ptr="hello"; 指針不能改件炉,內(nèi)容可改
指向常量的常指針:const int* const p;指針和內(nèi)容都不能改
帶兩個const 的好區(qū)分勘究,就是都不能改。怎么區(qū)分指針常量和常量指針呢斟冕?
1. 看const 和*的排列順序
int const* p; const * 即常量指針
const int* p; //const * 即常量指針
int* const p; //* const 即指針常量
2. 看const離誰近口糕,即從右向左看
int const* p; //const修飾的是*p,即*p的內(nèi)容不可通過p改變磕蛇,但p不是const景描,p可以修改,*p不可修改孤里;
const int* p; //同上
int* const p; //const修飾的是p伏伯,p是指針,p指向的地址不能修改捌袜,p不能修改说搅,但*p可以修改;
以上只是關(guān)于C語言指針的一些皮毛虏等,剩下的東西后續(xù)再補充弄唧。通過今天的學(xué)習(xí),對C語言底層的地位有了新的認識霍衫,大概是他因為跟硬件層息息相關(guān)候引。指針的存在讓程序員可以自由地對內(nèi)存進行操作,C語言賦予了程序員極大地自由的同時也帶來了極大的隱患敦跌。