1.2指標的型別
指標的型別:去掉變數名,剩下的的就是指標型別
int* p ; //int* 整形指標
int* arr[3]; //int*[3] 整形陣列指標
int (*p)(int a,int b); // int (*)(int a,int b);返回值為整形的函式指標
int (*arr)[4] ; // int (*)[4]; 指標陣列,指向陣列的指標
指標所指向的型別:去掉*和變數名
int* p ;// int
int *arr[3];// int
int (*p)(int a,int b);// int p(int a,int b);
int (*arr)[4] ;// int a[4];
指標之間不要相加. int *p,*pp... p+pp;
指標和指標之間可以相減: 得到記憶體相差幾個位元組
指標和常量可以加減:p+3; p-3
指標和常量相加,實際上加的是n個所指向的型別大小的和
p++; p--; p+=1
指標之間的相減:指標和指標之間可以相減,得到是記憶體相差幾個位元組
指標和常量相減:指標和常量可以相減
int main()
**指標操作
第乙個區域:**段–>放**
第二個區域:資料段–>如全域性變數,靜態的…,常量 除了區域性變數 本段最重要
第三個區域:棧區 -->放區域性變數(棧區記憶體空間比較小),記憶體自動釋放
第四個區域:堆區 -->動態申請記憶體;從大位址到小位址分配,其他都是從小到大(為什麼從大到小分配)
堆區的記憶體都是手動釋放
堆和棧的區別可以用如下的比喻來看出:
使用棧就象我們去飯館裡吃飯,
只管點菜(發出申請)、付錢、和吃(使用),
吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,
他的好處是快捷,但是自由度小。
使用堆就象是自己動手做喜歡吃的菜餚,
比較麻煩,但是比較符合自己的口味,而且自由度大。
malloc 申請記憶體
格式 p=(型別) malloc(申請記憶體大小)
realloc 釋放記憶體
格式 p=(型別)realloc(p,改變記憶體大小)
const指標
const int* p; cosnt修飾的是指標所指向的記憶體空間,指標指向可以發生改變
int const *p; 和第一種一樣.第一種方式多.
int * const p; 指標指向不可以發生改變,但指標所指向的記憶體空間可以修改.
const int * const p; //指標和指標所指向的記憶體空間都不可以改變
二級指標.指標變數中存放的是一級指標變數的位址
格式: 型別** 指標名 = 初始化位址
修改一級指標指向
int** pp = & p; *pp = &y;
修改一級指標所指向的記憶體空間值
int** pp = & p; **pp = 123;
動態分配
動態的在記憶體中申請一塊區域.
函式: malloc void * malloc(需要申請的記憶體空間大小);
格式: 型別* 指標= (型別*)malloc(記憶體大小);
申請的記憶體空間沒有初始化.
重新申請記憶體
void * realloc( void * _memory, size_t _newsize);
在原有指標的基礎上繼續申請記憶體空間.
野指標:沒有給指標賦值,指標不知道指向**,有可能指向任意乙個記憶體空間,通過指標操作記憶體空間就會出錯,所以要避免野指標出現.
空指標:指向null的指標,指向乙個特殊的位置,同樣的不可以通過指標操作記憶體空間.
void*指標:通用型指標,可以指向任何型別.在使用之前進行強制型別轉換.
記憶體洩露:申請記憶體空間找不到了?
記憶體釋放: freee(指標);
先看下面這個例子
struct test
*p;
假設p 的值為0x100000。如下表表示式的值分別為多少?
p + 0x1 = 0x___ ?
(unsigned long)p + 0x1 = 0x___?
(unsigned int*)p + 0x1 = 0x___?
我相信會有很多人一開始沒看明白這個問題是什麼意思。其實我們再仔細看看,這個知識點似曾相識。乙個指標變數與乙個整數相加減,到底該怎麼解析呢?
還記得前面我們的表示式「a+1」與「&a+1」之間的區別嗎?其實這裡也一樣。指標變數與乙個整數相加減並不是用指標變數裡的位址直接加減這個整數。這個整數的單位不是byte 而是元素的個數。所以:p + 0x1 的值為0x100000+sizof(test)*0x1。至於此結構體的大小為20byte,前面的章節已經詳細講解過。所以p +0x1 的值為:0x100014。
(unsigned long)p + 0x1 的值呢?這裡涉及到強制轉換,將指標變數p 儲存的值強制轉換成無符號的長整型數。任何數值一旦被強制轉換,其型別就改變了。所以這個表示式其實就是乙個無符號的長整型數加上另乙個整數。所以其值為:0x100001。
(unsigned int*)p + 0x1 的值呢?這裡的p 被強制轉換成乙個指向無符號整型的指標。所以其值為:0x100000+sizof(unsigned int)*0x1,等於0x100004。
上面這個問題似乎還沒啥技術含量,下面就來個有技術含量的:在x86 系統下,其值為多少?
intmain()
; int *ptr1=(int *)(&a+1);//指向a陣列後面的記憶體單元,&a+1表示向後移16個儲存單元
int *ptr2=(int *)((int)a+1);//表示a的儲存單元的位址增加乙個位元組
printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1]其實指向的是a陣列的最後乙個單元,*ptr1則表示a陣列的位址後移乙個位元組之後的4個連續儲存單元所儲存的值
return 0;
}
這是我講課時乙個學生問我的題,他在網上看到的,據說難倒了n 個人。我看題之後告訴他,這些人肯定不懂彙編,乙個懂彙編的人,這種題實在是小case。下面就來分析分析這個問題:
根據上面的講解,&a+1 與a+1 的區別已經清楚。
ptr1:將&a+1 的值強制轉換成int型別,賦值給int 型別的變數ptr,ptr1 肯定指到陣列a 的下乙個int 型別資料了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往後退4 個byte。所以其值為0x4。
ptr2:按照上面的講解,(int)a+1 的值是元素a[0]的第二個位元組的位址。然後把這個位址強制轉換成int型別的值賦給ptr2,也就是說ptr2 的值應該為元素a[0]的第二個位元組開始的連續4 個byte 的內容。
其記憶體布局如下圖:
好,問題就來了,這連續4 個byte 裡到底存了什麼東西呢?也就是說元素a[0],a[1]裡面的值到底怎麼儲存的。這就涉及到系統的大小端模式了,如果懂彙編的話,這根本就不是問題。既然不知道當前系統是什麼模式,那就得想辦法測試。大小端模式與測試的方法在第一章講解union 關鍵字時已經詳細討論過了,請翻到彼處參看,這裡就不再詳述。我們可以用下面這個函式來測試當前系統的模式。
int checksystem()
c; c.i = 1;
return (c.ch ==1);//如果當前系統為大端模式這個函式返回0;如果為小端模式,函式返回1。
}
如果當前系統為大端模式這個函式返回0;如果為小端模式,函式返回1。也就是說如果此函式的返回值為1 的話,*ptr2 的值為0x2000000。如果此函式的返回值為0 的話,*ptr2 的值為0x100。 C語言的靈魂 指標基礎
一 什麼是指標 1 指標的定義 位址形象化為指標,通過指標能夠找到記憶體單元。指標變數就是位址變數,變數的值為指標。指標其實是我們將變數名和位址的關係顯化 獨立 出來的一種形式,是為了我們更加方便的讀取資料和進行操作而設計的,是c語言的靈魂。解釋 int a printf d,a 如上,我們通常是通...
C語言之靈魂 指標學習
指標是c語言的難點 稱之為c語言的靈魂一點也不為過,不過指標用好了能事半功倍,用不好bug滿天飛。一 指標的概念 指標也是變數只不過是特殊的變數,指標的值是另乙個變數的地 也就是變數所在的記憶體位址 指標的定義 在變數名之前加 號即可。如 char point 二 指標的應用 1.指標與普通變數 指...
C語言的靈魂 指標基本用法
指標 pointer 是乙個值為記憶體位址的變數 或資料物件 記憶體位址一般使用16進製制來表示。通俗的理解為,變數就是乙個記憶體,記憶體肯定有記憶體位址,而我們的指標就是來儲存這個記憶體位址的變數。資料型別 指標變數名 例如int ptr num char ptr name float money...