-
指針重要性:
表示一些復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
快速的傳遞數(shù)據(jù)
使函數(shù)返回一個以上的值
能直接訪問硬件
能方便的處理字符串
是理解面向?qū)ο笳Z言中引用的基礎(chǔ)
c語言的靈魂
-
指針的定義
-
地址:
-
內(nèi)存單元的編號
-
從零開始的非負(fù)整數(shù)
-
范圍:
-
-
指針:
-
指針就是地址,地址就是指針
-
指針變量就是存放內(nèi)存單元編號的地址,活著說指針變量就是存放地址的變量
-
指針和指針變量是兩個不同的概念
-
但是要注意的是:通常我們敘述會把指針變量簡稱為指針
-
指針的本質(zhì)就是操作受限的非負(fù)整數(shù)(為什么這么說,因為非負(fù)整數(shù)可以加減乘除,而指針不能加乘除,只能相減)
-
指針的分類:
1基本類型的指針
int * p;//p是變量名字, int* 表示存放的存放的是int類型的數(shù)據(jù)
int i =3;
p=&i;//p是指針變量,并且p存放了普通變量i的地址,所以說p指向了普通變量i ,所以*p=i;或者說所有出現(xiàn)*p的地方都可以替代成i,所有出現(xiàn)i的地方都可以替代成 *p,*p就是以p的內(nèi)容為地址的變量
常見的錯誤寫法
錯誤寫法1:
int * p;
int i =5;
*p=i;//錯誤:因為*p就是以p的內(nèi)容為地址的變量,但是p沒有賦值,就是垃圾值,所以這里*p就是以這個垃圾值為地址的這個一個單元,這個地址我們并不知道,那么你要把i的值給這個我們不知道的單元,那么就會奔潰
錯誤寫法2:
int i =5;
int*p;
int *q;
p=&i;
*q=p;//同上的一個原因是q是沒有賦值,*q是垃圾值,原因二是*q和p的數(shù)據(jù)類型不一致
錯誤寫法2:
int i =5;
int*p;
int *q;
p=&i;
q=q;//這個沒錯,q是垃圾值,q賦值給p,p也變成垃圾值
printf(@"%d",*q);//這個就是錯的,q的空間數(shù)據(jù)本程序,所以本程序可以讀寫,但是如果q內(nèi)部是垃圾值,則本程序不能讀寫*q的內(nèi)容,因此此時 *q所代表的內(nèi)存單元的控制權(quán)限并沒有分配給本程序,所以本程序運行到此行就會出錯
附注:* 的含義
1 乘法
2 定義指針變量: int * p;//定義了一個名字叫p的變量,int表示p只能存放數(shù)據(jù)類型為int類型的地址
3 指針運算符,該運算符放在已經(jīng)定義好的指針變量前面,如果p是一個定義定義好的指針變量,則*p表示以p的內(nèi)容為地址的變量
2.指針和數(shù)組
1.指針和一維數(shù)組
#####數(shù)組名:
一維數(shù)組名是個指針常量,存放的是數(shù)組首個元素的地址,因為它是常量,所以不能被改變
#####下標(biāo)和指針的關(guān)系
如果p是個指針變量,則p[i] 永遠(yuǎn)等價于 *(p+i)
確定一個一維數(shù)組需要幾個參數(shù)[如果一個函數(shù)要處理一個一維數(shù)組,則需要接受該數(shù)組的哪些信息],答案是需要兩個參數(shù):第一個是數(shù)組第一個元素的地址,第二個是數(shù)組的長度
#####指針變量的運算
指針變量不能相加不能相乘也不能相除,只能減
如果兩個指針變量指向的是同一塊連續(xù)空間中的不同儲存單元,則這兩個指針變量才可以相減,一般只能是數(shù)組
int i =5;
int j=10;
int a[5];
p=&a[1];
q=&a[4];
printf("相差幾個單元:%d",q-p);//3
#####一個指針到底占幾個字節(jié)
假設(shè)p指向char類型變量(char占一個字節(jié))
假設(shè)q指向int類型變量(int占四個字節(jié))
假設(shè)r指向doubel類型變量(doubel占八個字節(jié))
那么p q r本身所占的字節(jié)數(shù)是否一樣
答案是:q p r本身所占字節(jié)數(shù)都是一樣的,四個字節(jié)
總結(jié):
1.一個指針變量,無論他指向的變量占幾個字節(jié),該指針本身只占四個字節(jié),
2.一個變量的地址使用該變量的首字節(jié)的地址表示
原理是這樣,比如q指向int類型變量,其他p只保存了int所在四個字節(jié)內(nèi)存的第一個字節(jié),至于只保存了第一個字節(jié)但是卻能儲存四個字節(jié)的數(shù)據(jù),這是由數(shù)據(jù)類型int決定,就是從p保存的第一個字節(jié)開始往后計算四個字節(jié),對于doubel float也是一樣的,但是為什么p本身占四個字節(jié),這是因為,機器是32位的,也就說地址總線有32跟,那么最大地址的表示為2的32次方,也就是4個字節(jié)的表示方式,p表示其實都是內(nèi)存單元,既然內(nèi)存的最大單元為2的32次方法,那么它本身的最大值也應(yīng)該為2的32次方
2.指針和二維數(shù)組
3.指針和函數(shù)
4.指針和結(jié)構(gòu)體
-
結(jié)構(gòu)體定義
為什么需要結(jié)構(gòu)體:為了表示一些復(fù)雜的事物,而普通的基本類型無法滿足實際需求
什么叫結(jié)構(gòu)體:就是把一些基本類型組合在一起的形成的新的數(shù)據(jù)類型叫做結(jié)構(gòu)體
```
//定義一個結(jié)構(gòu)體的數(shù)據(jù)類型
struct Student{
int age;
float score;
char sex;
};
struct student stu={12,"edison"};
NSLog(@"age =%d name=%s",stu.age,stu.name);
定義結(jié)構(gòu)體的方式
方式1:
struct Student{
int age;
float score;
char sex;
};
方式2:
struct Student{
int age;
float score;
char sex;
}stu;//在定義的同時直接定義變量名,這樣不好,因為只能定義一次
方法3:
struct{
int age;
float score;
char sex;
}stu;//也不好
* ######結(jié)構(gòu)體的初始化
初始化方法
方法1
struct student st ={12,"edison"};
方法2;
struct student st ;
st.age=12;
st.name="edison";
如何取出結(jié)構(gòu)體的每個成員
/*
結(jié)構(gòu)體變量名.成員名
指針變量名->成員名
/
struct student st={12,"edison"};
st.age=12;
st.name="name";
struct student * pst=&st;
pst->age=34;
pst->name="edison"http://pst->age 在計算機內(nèi)部會轉(zhuǎn)化成(pst).age,
//所以 pst->age 等價于st.age,也等價于(*pst).age
* ######結(jié)構(gòu)體運算
結(jié)構(gòu)體變量可以相互賦值
struct student st={12,"edison"};
st.age=12;
st.name="name";
struct student st2=st;//是可以的
#####5.多級指針
* ####專題
#####1.動態(tài)內(nèi)存分配
* ######傳統(tǒng)數(shù)組的缺點:
1.數(shù)組長度必須事先指定,且只能是常整數(shù),不能是變量
2.傳統(tǒng)形勢定義的數(shù)組,該數(shù)組的內(nèi)存程序員無法手動釋放,只能等本函數(shù)運行完畢由系統(tǒng)釋放
3.數(shù)組的長度一旦定義,其長度就不能更改,數(shù)組的長度不能在函數(shù)運行的過程中動態(tài)的擴充或者縮小
4.a函數(shù)定好的數(shù)組,在a函數(shù)運行期間可以被其他函數(shù)調(diào)用,但是a函數(shù)運行完畢之后,a函數(shù)中數(shù)組將無法給其他函數(shù)使用
* ######為什么需要動態(tài)分配內(nèi)存
就是因為動態(tài)數(shù)組很好的解決了傳統(tǒng)數(shù)組的四個缺陷
int * p =(int )malloc(100);
/
malloc函數(shù)只有一個形參,就是需要分配的字節(jié)數(shù)
malloc函數(shù)其實只能返回分配好的內(nèi)存的第一個字節(jié)的地址,所以在malloc前加入(int *)強制轉(zhuǎn)化,就是為了表示把第一個字節(jié)的地址強制轉(zhuǎn)化成整形變量的地址,那么就說明這100個字節(jié)得按照4個字節(jié)一一劃分,
p本身所占的內(nèi)存是靜態(tài)分配的,p所指向的內(nèi)存是動態(tài)分配的
free(p);//把p指向的內(nèi)存給釋放掉,p本身的內(nèi)存是靜態(tài)的,不能由程序員手動釋放,把p指向的內(nèi)存釋放掉后就不能讀寫這塊內(nèi)存上的值了
*/
######1