深入理解C指標之四 指標和陣列

2021-09-22 20:35:33 字數 4444 閱讀 4946

原文:

深入理解c指標之四:指標和陣列

陣列是c內建的基本資料結構,陣列表示法和指標表示法緊密關聯。一種常見的錯誤認識是陣列和指標完全可以互換,儘管陣列名字有時可以當做指標來用,但陣列的名字不是指標。陣列和指標的區別之一就是,儘管陣列的名字可以返回陣列位址,但是名字不能作為賦值操作的目標。

陣列是能用索引訪問的同質元素連續集合。陣列的元素在記憶體中是相鄰的,而且元素都是同一型別的。陣列的長度是固定的,realloc函式和變長陣列提供了應對長度需要變化的陣列的技術。

一維陣列是線性結構,用乙個索引訪問成員。取決於不同的記憶體模型,陣列的長度可能會有不同。

int vector[5];

陣列的名字只是引用了一塊記憶體,對陣列使用sizeof操作符會得到為該陣列分配的位元組數。要知道陣列的元素數,只要對其除以元素長度即可。

int vector[5];

printf("vector is %p\nsize is %d\n", &vector, sizeof(vector));

//vector is 0xbffb8c08

//size is 20

可以用乙個塊語句初始化一維陣列。

int vector[5] = ;

宣告乙個二維陣列。可以將二維陣列當做陣列的陣列,只使用乙個下標訪問二維陣列得到的是對應行的指標。

int matrix[2][3] = ,};

printf("0 is %p\n1 is %p\n", &matrix[0], &matrix[1]);

//0 is 0xbf984044

//1 is 0xbf984050

可以看到,兩個位址剛好差12個位元組,也就是matrix陣列一行的長度。

把陣列位址賦給指標。

int* pv = vector;

注意這種寫法和&vector[0]是等價的,不同於&vector是返回的整個陣列的指標。乙個是陣列指標,乙個是整數指標,指標型別不同。pv實際代表的是乙個位址,*(pv+i)的寫法等價於pv[i],前者稱作指標表示法,後者稱作陣列表示法

printf("pv[0] is %d\n*(pv+1) is %d\n ",pv[0],*pv);

//pv[0] is 1

//*(pv+1) is 1

pv指標包含乙個記憶體塊的位址,方括號表示法會取出pv中包含的位址,用指標算數運算子把索引i加上,然後接引新位址返回其內容。給指標加上乙個整數實際是給它加了整數與資料型別長度的乘積,這一點對陣列名字也同樣適用,*(pv+1)和*(vector+1)是等價的。因此陣列表示法可以理解為「偏移並解引」操作。vector[i]和*(vector+i)兩種方法結果相同,僅僅在實現上略有差別,可以忽略。注意指標可以作為左值,但是陣列名字不可以作為左值使用,vector=vector+1是錯誤的寫法。

如果從堆上分配記憶體並把位址賦給乙個指標,那就肯定可以對指標使用下標並把這塊記憶體當做乙個陣列。用malloc建立的已有陣列的長度可以通過realloc函式來調整。c99支援變長陣列,但是變長陣列只能在函式內部宣告。所以如果陣列的生命週期需要比函式長,或者你沒有使用c99,那就只能使用realloc。

下面這個函式接受使用者的輸入,並且使用realloc函式動態的申請所需的記憶體,按回車結束輸入。

char* getline(void)

while(1)

if(++length >= maximumlength)

currentposition = newbuffer + (currentposition - buffer);

buffer = newbuffer;

}*currentposition++ = character;

}*currentposition = '\0';

printf("buffer is %s\n", buffer);

return buffer;

}getline();

將一維陣列作為引數傳遞給函式實際是通過值來傳遞陣列的位址,我們需要告訴函式陣列的長度,否則函式只有乙個位址,不知道陣列到底有多長。對於字串來說,可以依靠nul字元來判斷其長度。對於有些陣列則無法判斷。

宣告乙個指向陣列的指標和指標陣列、陣列指標是不同的。指向陣列的指標是乙個指標指向陣列下標為0的元素,指標陣列是乙個元素為指標的陣列,陣列指標是陣列型別的指標。

int vector[2] = ;

int* pv1 = vector;//指向陣列的指標

int* pv2[2];//指標陣列,可以用乙個迴圈來為每個指標分配記憶體

int (*pv3)[2];//陣列型別的指標

現在再來區分一下陣列表示法和指標表示法在指標陣列的應用。

int* array[5];

array[0] = (int*) malloc (sizeof(int));

*array[0] = 100;

*(array+1) = (int*) malloc (sizeof(int));

**(array+1) = 200;

在這裡array[1]和*(array+1)是等價的,實際都是指標型別,使用malloc函式為指標在堆上分配記憶體,解引指標來為資料賦值,因此**(array+1)其實不難理解,乙個*解引得到乙個指標,對指標再解引才得到資料,而括號前面已經 解釋過,就是相當於乙個取位址和加索引的操作。當然,還可以使用array[0][0]來代替*array[0]。

可以將多維陣列的一部分看做子陣列,比如二維陣列的每一行當做乙個一維陣列。陣列按行-列順序儲存,第二行的第乙個元素的記憶體位址緊跟在第一行最後乙個元素後面。

int matrix[2][3] = ,};

int (*pmat)[3] = matrix;//3是二維陣列的列數

printf("size of pmat[0] is %d\n", sizeof(pmat[0]));

//size of pmat[0] is 12

可以看到,該陣列指標的第乙個元素的長度是12個位元組,也就是說是第一行的長度。如果要訪問第一行第乙個元素,需要用pmat[0][0]來訪問。array[i][j]等於 array+i*sizeof(row) + j* sizeof(element)。sizeof(row)是一行的總大小,sizeof(element)是單個元素的大小,array是array[0][0]的位址。

給函式傳遞陣列引數時,要考慮如何傳遞陣列的維數以及每一維度的大小。下面是兩種傳遞二維陣列的方法:

void display2darray(int arr[3], int rows){}

void display2darray(int (*arr)[3], int rows){}

兩種方法都指定了行數。如果傳遞的陣列維度超過了二維,除了一維的部分,需要指定其它維度的長度。如果傳遞乙個array3d[3][2][4]的陣列:

void display3darray(int (*arr)[2][4], int rows){}

當使用malloc分別為二維陣列的不同子陣列分配記憶體時,可能導致記憶體分配不連續的問題。使用塊語句一次性初始化不會有這個問題。使用malloc來為二維陣列分配連續的記憶體有兩種策略。假設二維陣列有三行四列。第一種一次性分配所有記憶體3*4*sizeof(element),然後使用的時候通過前面提到的如何訪問array[i][j]的方法手動計算要訪問的記憶體位址。第二種方法分為兩步。第一步先使用malloc分配一塊記憶體用來存放指向二維陣列每一行的指標的指標。第二步為array[0][0]的指標分配所有記憶體,然後計算array[1][0]和array[2][0]的位置,分別給這兩個關鍵指標賦值,這樣就可以根據每一行的指標來使用下標訪問了。

int rows = 3;

int columns = 5;

//第一種方法

int* matrixx = (int*) malloc (rows * columns * sizeof(int));

//第二種方法

int **matrixy = (int**) malloc (rows * sizeof(int*));

matrixy[0] = (int*) malloc (rows * columns * sizeof(int));

int i = 1;

while(i不規則陣列是每一行的列數不一樣的二維陣列。可以使用復合字面量來初始化不規則陣列。

(const int)

(int [3])

不規則陣列的訪問和維護都比較麻煩,使用前應慎重考慮。

c指標之四 指標和陣列

陣列是c內建的基本資料結構 一 陣列概述 獲取元素數量的方式 陣列長度除以元素長度 int icount sizeof vector sizeof int 1 一維陣列 2 二維陣列 3 多維陣列 二 指標表示法和陣列 單獨使用陣列名字時候會返回陣列位址,可以把陣列賦值給指標 如 int vecto...

深入理解指標和陣列 指標和函式

指向函式指標陣列的指標 在了解了指標之後,可以得出,指標就是乙個變數,用來存放位址的變數。位址就相當於門牌號,而指標就是存放它的變數,對指標進行解引用 則相當於拿一把鑰匙去開對應的門牌號的門,開啟門,訪問其中的變數。指標的大小在32位平台上是4個位元組,在64位平台上是8個位元組。如有以下 先看下面...

深入理解C指標之三 指標和函式

原文 深入理解c指標之三 指標和函式 理解函式和指標的結合使用,需要理解程式棧。大部分現代的塊結構語言,比如c,都用到了程式棧來支援函式的執行。呼叫函式時,會建立函式的棧幀並將其推到程式棧上。函式返回時,其棧幀從程式棧上彈出。在使用函式時,有兩種情況指標很有用。一種是將指標作為引數傳遞給函式,函式可...