指標是c / c++
中重要的構造型別,指標賦予了
c / c++
程式直接訪問和修改記憶體的能力。
c / c++
的許多重要應用,如編譯、
os、嵌入式開發都依賴於這種能力。
馮諾依曼體系的計算機記憶體儲存指令和資料,我們可以將其抽象為指令區和資料區(當然實際情況要複雜得多)。資料區中包含棧(stack)
和堆(heap)
區,棧區的資料由編譯器管理而堆區資料則由程式設計師管理。
由於指令同樣存在於記憶體中,那麼函式在記憶體中也會擁有位址(指標)。 函式指標相對於函式名來說 可以在執行期動態地選擇呼叫的函式,這一特性是c++
實現動態多型性的重要基礎。
指標是一種構造型別,所有的基本型別和struct
等都有自己的指標。指標包含首位址(即指標的值)和指向物件的型別兩部分資訊,所以指標並不嚴格等價於位址。
不要使用未初始化的指標否則將導致嚴重的執行時錯誤,所幸作業系統的記憶體管理可以保證作業系統自身和其它程序的穩定,但你的程式肯定會異常退出了。指標的型別是重要的,指向struct
的指標初始化後可以使用
ptr -> member
表示式來訪問某乙個成員,但是未經初始化或
void
指標將導致錯誤或警告。
在《c程式設計基礎》中提到,方括號()
,指標(*)
這些符號在宣告語句和執行語句中的含義有所不同,但依舊具有運算子的一些特性。
即指標(*)
,方括號
()以及函式呼叫的
(參數列
)在宣告語句中 可以認為是將乙個識別符號標記為特殊型別的標誌,當同乙個宣告語句中存在多個標誌時,它們按照表示式求解的順序決定宣告的型別:
(1)基本宣告:
int *p; 宣告指標p
(注意不是
*p),
*p表示其指向的資料。
int p[m]; 宣告長為m
的一維陣列p。
int p[m][m]; 宣告m×m
二維陣列p。
(2)復合宣告:
int **p 宣告p
為二重指標(不是
**p),則
*p為一重指標,
**p為資料物件。
int *p[m] 宣告指標陣列,初等運算子從右向左結合首先宣告乙個陣列,然後宣告陣列元素型別為指標。
int *fun(...) 宣告返回指標的函式,從右向左首先宣告fun
為函式,然後宣告返回值型別為指標。
int (*ptr) (...)
宣告ptr
為函式指標,從右向左首先宣告這是乙個函式,
(*ptr)
宣告這是乙個函式指標。使用函式指標時只需以
(*ptr)
代替函式名即可,例:
qsort庫函式使用函式指標作謂詞函式
#include#includeint tell(const
void *a,const
void *b)
int main(void
) ;
int (*tp) (const
void *a, void *b);
tp =tell;
scanf("%d
", &m);
for (i = 0; i < m; i++)
qsort (a, m,
sizeof(int
),tp);
for (i=0;i)
printf("\n
");return0;
}
指標作為函式引數則可以實現傳址呼叫,下面給出乙個最簡單的交換兩個數的程式:
#includeint swap(int *pa, int *pb)int main(void
)
const
int * ptr;
intconst * ptr;
指向常物件的指標
int * const ptr = &a;
指向不能改變的指標,必須初始化
const
int * const ptr = &a;
intconst * const ptr;
指向與物件均不能改變的指標;
以*為標誌,靠近基本型別的為指向常物件,靠近指標名為指向不變。
1.一維陣列
上文已經說明陣列的宣告方式:
(1)宣告乙個長度為8的
int陣列
arr int arr[8];
(2)陣列的長度必須為常正整數
,不能是
const
物件【const int n = 8;int arr[n];
】;可以是列舉元素但不能是列舉物件,通常使用字面值或巨集來作為長度 #define n 10;
(3)陣列下標從
0開始(不是1);
(4)方括號(
)可以訪問陣列的某個成員, arr[i];arr[0];。
在函式內定義的陣列不會自動初始化,在函式外定義的陣列將自動初始化為0
(或等價值)。在函式內定義陣列同時初始化時,未初始化變數將自動初始為
0值 int arr[8] = ;
常用這個特性將陣列全部初始化為
0值, int arr[8] = ;
。將所有元素初始化時不需要指定陣列長度,即 int arr = ;
與 int arr[2] =
等價。
2.高維陣列
我們可以將高維陣列理解為陣列的陣列,即高維陣列的元素是低一維的陣列。因為陣列就名就是其首位址,那麼,高維陣列的元素是低維陣列的首位址。以二維陣列為例,利用a[i]<=>*(a+i)
逐級展開
a[i][j] <=> *(a[i]+j) <=> *(*(a+i)+j)
i的單位為一維陣列的長度,
j的單位為基本型別的長度。推導時,將
展開即可,加乙個
&就是少乙個*。
*(a+i)+j <=> a[i]+j <=> &a[i][j]
高維陣列的初始化有兩種形式。首先將其元素理解為陣列,每乙個陣列的初值用乙個花括號括起,把它們當做乙個元素用另乙個大括號括起。高維陣列在記憶體中是線性儲存的,可以根據它在記憶體中的儲存順序當做一維陣列進行初始化。這兩種方式下,沒有被賦值的元素均被自動賦0
。在對所有元素賦值時,第一維的長度可以省略由編譯系統求出,其它維數不可省略。
3.陣列是一段連續的記憶體空間,陣列名可以認為是常指標(不允許更改指向)。從陣列實現來看,下標從0開始是非常自然的。
c對下標的處理方法的處理方法就是將它轉化為位址,a[i]與*(a+i)無條件等價。
void *malloc(unsigned int size); (常用)
(1) 在記憶體中分配乙個大小為size
的連續空間,引數
size
為無符號整型(不允許為負數)。函式的返回值是所分配區域第乙個位元組的位址。如果函式不能成功地執行(如記憶體空間不足)則返回空指標
(null)。
(2) void指標型別不能理解為指向任何型別,而應理解為指向不確定型別的資料的指標。應用指派運算子
(強制轉換)
將void
指標變為具體的型別指標,
size
引數應用
sizeof()
運算子求得以避免錯誤,如
結構體的大小不嚴格等於所有成員大小之和並提高程式可移植性。例如:
int * ptr = (int *)malloc( sizeof(int)* n );
宣告ptr
指向一段長度為n連續
int型空間(實際上是乙個長度為n的
int陣列)。
void *calloc(unsigned n,unsigned size);
在動態儲存區分配n
個長度為
size
的連續空間,可以用來儲存乙個陣列。
void
free(void *p);
釋放指標變數p
所指向的動態空間,無返回值。例如: free(ptr);
void *realloc(void *p,unsigned int size);
將p指向的動態空間大小改變為
size
。
C 記憶體與指標
1 int year year 1000 記憶體位址在0028ff44 23 int ptr year int 即宣告了乙個指標型變數,指標是乙個變數,儲存的是乙個變數的位址。45 在宣告語句中,可以把 看作是指標的型別 67 ptr year year 取變數的位址,即ptr year 0028f...
指標與記憶體
char 乙個位元組 double 8個位元組 int 4個位元組 short 2 個位元組 fioat 4個位元組 將記憶體條抽象成乙個很大的一維字元陣列,對記憶體條中的每乙個位元組分配乙個32位或64位的編號 與32位或64位處理器相關 這個編號我們稱之為記憶體位址。定義乙個變數,用來儲存記憶體...
記憶體與指標 陣列與指標
陣列指標 行指標 型別識別符號 變數名 個數 陣列指標指向乙個提取的陣列,本質為指標 定義 int p n p是乙個指標,指向乙個整型的一維陣列,這個一維陣列的長度是n,也可以說是p的步長。也就是說執行p 1時,p要跨過n個整型資料的長度。陣列指標的步長必須和它指向的二維陣列的列長相同!p 2 相當...