什么是指針?
在C語言中,操作系統屏蔽掉所有的硬件存儲器,為程序員提供了一個類似數組的內存空間;
這個內存空間的基本單位是字節,也是程序員能夠操作的基本單位。
指針就是每塊基本單位大小的內存的地址,通常被叫做地址或者地址編號。將字節大小的內存
分別進行編號,有助于我們對于內存的使用。
用來存放指針的變量就是指針變量,這也是程序員通常所說的指針。以下所有的指針變量統稱
為指針。
聲明指針的格式:
存儲類型指針類型*指針名;
eg:char*p;
int*p;等
存儲類型:
不單獨聲明時,有兩種情況
情況1:局部定義指針時,默認為auto類型。表示當進入代碼塊時,系統為自動變量分配內存.
在塊內,這些變量被定義,并被認為他是局部于本塊的.當退出塊時,系統釋放分配給自動變量的
內存,因此,變量值就丟失了.重新進入塊,系統會為自動變量再次分配內存,原先的值已經沒有
了。
情況2:全局定義指針時,默認為extern類型。表示為該變量永久的分配存儲,直到當前進程
運行結束。全局變量在整個程序執行期間都是存在的。
指針類型:
由于指針保存的是地址,所以地址相關的變量或者結構,都可以作為指針的類型;
如:char、short、int、long等基本類型所定義的指針類型就是char*、short*、int*、
long*等
指針也可以保存數組的地址,該指針就變成了數組指針;指針也可以保存結構體變量的地址,
該指針就變成了結構體指針;指針也可以保存函數的地址,該指針就變成了函數指針;
*號:
*號有兩個作用:
作用1:在定義時,和普通變量做區分,如果沒有*號,那就和普通變量的定義格式一致,沒
有任何的區別了;
作用2:在使用時,*變量名這個形式表示拿到指針保存的地址上的數據;后面詳細說;
指針名:
指針名是一個標識符,要符合標識符的命名規范;
注:標識符的命名規范:
1、由數字、字母、下劃線組成
2、不能以數字開頭
3、不能和關鍵字沖突,嚴格區分大小寫
指針的大小?
指針的大小和類型沒有關系,和CPU的運行時的尋址位數有關系;
在32位操作系統中,32位CPU一次最大能夠訪問32位數據,所以指針的大小就是32位,即4
字節;
在64位操作系統中,64位CPU一次最大能夠訪問64位數據,所以指針的大小就是64位,即8
字節;
驗證:
使用64位編譯器:
linux@ubuntu:~$gcc01test.c
linux@ubuntu:~$./a.out
sizeof(char*)=8
sizeof(short*)=8
sizeof(int*)=8
sizeof(long*)=8
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
printf("sizeof(char*)=%ld\n",sizeof(char*));
printf("sizeof(short*)=%ld\n",sizeof(short*));
printf("sizeof(int*)=%ld\n",sizeof(int*));
printf("sizeof(long*)=%ld\n",sizeof(long*));
return0;
}
使用32位編譯器:
linux@ubuntu:~$gcc01test.c-m32
linux@ubuntu:~$./a.out
sizeof(char*)=4
sizeof(short*)=4
sizeof(int*)=4
sizeof(long*)=4
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
printf("sizeof(char*)=%d\n",sizeof(char*));
printf("sizeof(short*)=%d\n",sizeof(short*));
printf("sizeof(int*)=%d\n",sizeof(int*));
printf("sizeof(long*)=%d\n",sizeof(long*));
return0;
}
指針類型有什么作用?
由于一個指針只能保存一個地址,一個地址僅僅代表一個字節內存,而通常情況下,程序員定
義變量都不不止使用一個字節;所以如何讓指針訪問到占有多個字節內存的變量的其他數據,
就是通過指針類型;
指針類型決定著指針一次能夠訪問的最大內存空間;
舉例:
linux@ubuntu:~$./a.out
a=0x12345678
p=0x7fff5eec899c
*p=0x12345678//當指針類型和指針所保存變量的類型相同時,能夠正常獲取到變
量的數據
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
inta=0x12345678;//定義一個變量a,保存16進制數0x1234567,總共占4字節
int*p=&a;//定義一個指針,保存變量a的地址
printf("a=%#x\n",a);//#號表示數字前導符,16進制的前導符,是0x,%x表示打印
16進制數
printf("p=%p\n",p);//由于指針p中保存的是地址,打印地址用%p
printf("*p=%#x\n",*p);//*p表示取到指針保存的地址上的數據,*p<==>a
return0;
}
這是我們正常使用指針,保證使用的指針類型和保存的數據類型一致,防止數據丟失;以上示
例中,指針能夠正常取到變量a的4個字節內存上的所有數據;
如果將上述示例修改:
linux@ubuntu:~$./a.out
a=0x12345678
p=0x7ffe4b4f344c
*p=0x78//當指針類型和指針所保存變量的類型不同時,不能夠正常獲取變量的數據
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
inta=0x12345678;//定義一個變量a,保存16進制數0x1234567,總共占4字節
char*p=(char*)&a;//定義一個char*類型的指針,保存int類型的變量a的地址,
由于類型不一致,編譯器會報警告,所以將&a的類型強制轉換為char*類型。消除警告;
printf("a=%#x\n",a);
printf("p=%p\n",p);
printf("*p=%#x\n",*p);
return0;
}
由上述示例得知,當指針類型和指針所保存變量的類型不同時,不能夠正常獲取變量的數據,
指針所獲取到的數據大小由指針決定;
0x78總共占1個字節,和char*類型的指針,所能訪問的數據長度一致;
如何使用指針?
指針的使用只需要記住兩點
1、指針保存的是已定義的變量地址,不能保存未經定義的常量和地址;
2、指針提供另一種操作變量數據的方法,主要和*號有關;
指針是怎么進行偏移的?
指針的偏移,就是指針的運算,指針和普通變量一樣,也是可以進行運算的,但是和普通變量
不一樣的是,普通變量的運算是對普通變量中保存的數據繼續寧運算,而指針的運算和指針類
型有關。
最常使用的指針偏移操作為:p++或者p--等
示例:
linux@ubuntu:~$./a.out
p=0x7ffddc670170//這是指針p中保存的地址
*p=10//這是指針p中保存的地址上的數據,發現為*p==str[0]
p=0x7ffddc670174//這是指針p進行偏移,即p++之后,指針p中保存的地址
*p=20//這是指針p中保存的地址上的數據,發現為*p==str[1]
p=0x7ffddc670178//這是指針p再次進行偏移,即p++之后,指針p中保存的地址
*p=30//這是指針p中保存的地址上的數據,發現為*p==str[2]
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
intstr[5]={10,20,30,40,50};//定義一個數組,有5位元素,每位元素都是int類型
的
int*p=str;//定義一個int*類型的指針,當前保存的是數組的首地址,也是數字首位
元素的地址,str作為數組名,也表示數組的首地址
printf("p=%p\n",p);//打印當前首元素的地址
printf("*p=%d\n",*p);//打印首位元素
p++;//指針進行偏移,等價于p=p+1;表示指針p像后偏移1次,并不是表示p中的
地址加1,地址怎么變化取決于指針類型
printf("p=%p\n",p);
printf("*p=%d\n",*p);
p++;
printf("p=%p\n",p);
printf("*p=%d\n",*p);
return0;
}
由示例可以發現,對于int*類型的指針,雖然只是進行p++操作,但是真正的地址的運算卻是
+4;和指針類型有關;
綜上所述:
1、指針保存的是地址,地址是內存中每一個字節大小空間的編號
2、指針的*號可以幫助指針獲得指針保存地址上的數據內容
3、指針的類型決定指針所能夠訪問的內存大小,指針類型還和指針偏移有關
4、指針大小固定,32位系統中占4字節,64位系統中占8字節
5、指針不能使用常量和未使用的地址進行初始化,會出現野指針