陣列的本質
- 陣列是一段連續的記憶體空間
- 陣列的空間大小為 sizeof(array_type) * array_size【array_size:陣列的元素個數】
- 陣列名可看作指向陣列第一個元素的常量指標
問題:
1. a + 1 的意義是什麼?結果是什麼
2. 指標運算的意義是什麼?結果又是什麼?
程式設計實驗: a + 1 的結果是什麼?
#include <stdio.h>
int main()
{
int a[5] = {0};
int* p = NULL;
printf("a = 0x%X
", (unsigned int)(a));
printf("a + 1 = 0x%X
", (unsigned int)(a + 1));
printf("p = 0x%X
", (unsigned int)(p));
printf("p + 1 = 0x%X
", (unsigned int)(p + 1));
return 0;
}
輸出:
a = 0xBFD627C8
a + 1 = 0xBFD627CC
p = 0x0
p + 1 = 0x4
分析:
p + 1 ==> 0 + 1 * sizeof(*p) ==> 0 + 1 * sizeof(int) ==> 0 + 4 ==> 4
a + 1 ==> 0xBFD627C8 + 1 * sizeof(*a) ==> 0xBFD627C8 + 1 * sizeof(a[0]) ==> 0xBFD627C8 + 1 * sizeof(int) ==> 0xBFD627C8 + 1 * 4 ==> 0xBFD627C8 + 4 ==> 0xBFD627CC
指標的運算
- 指標是一種特殊的變數,與整數的運算規則為
p+n; <--> (unsigned int)p + n * sizeof(*p)
結論:當指標指向一個同型別的陣列的元素時, p+1 將指向當前元素的下一個元素; p-1 將指向當前元素的上一個元素。
- 指標之間只支援減法運算
- 參與減法運算的指標型別必須相同
p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);
注意:
1. 只有當兩個指標指向同一個陣列中的元素時,指標相減才有意義,其意義為指標所指元素的**下標差**。
2. 當兩個指標指向的元素不在同一個陣列中時,結果未定義。
以上兩條注意事項面對絕大部分的使用情況。
指標的運算是很靈活的,在特殊情況下,可以通過強制型別的轉換,實現不同型別指標間的運算,而得到巧妙的結果。
已知一個結構體裡面的成員地址,可以反推出該結構體的首地址 :
struct _tag
{
int aa;
int bb;
unsigned int* node;
};
指標的比較
- 指標也可以進行關係運算( <, <=, >, >= )
- 任意關係運算的前提是同時指向同一個陣列中的元素
- 任意兩個指標之間的比較運算( ==, != ) 無限制
- 參與比較運算的指標型別必須相同
例項分析: 指標運算初探
#include <stdio.h>
int main()
{
char s1[] = {`H`, `e`, `l`, `l`, `o`};
int i = 0;
char s2[] = {`W`, `o`, `r`, `l`, `d`};
char* p0 = s1;
char* p1 = &s1[3];
char* p2 = s2;
int* p = &i;
printf("%d
", p0 - p1);
// printf("%d
", p0 + p1);
// printf("%d
", p0 - p2);
// printf("%d
", p0 - p);
// printf("%d
", p0 * p1);
// printf("%d
", p0 / p1);
return 0;
}
輸出:
-3
分析:
p0 - p2; 編譯無警告,無錯誤,但大部分情況下,這樣操作是沒有實際意義的
p0 + p1; error: invalid operands to binary + (have ‘char *’ and ‘char *’) // 操作符不支援
p0 - p; error: invalid operands to binary - (have ‘char *’ and ‘int *’) // 指標型別不同
p0 * p1; error: invalid operands to binary * (have ‘char *’ and ‘char *’) // 操作符不支援
p0 / p1; error: invalid operands to binary / (have ‘char *’ and ‘char *’) // 操作符不支援
例項分析: 指標運算的應用
#include <stdio.h>
#define DIM(a) (sizeof(a) / sizeof(*a))
int main()
{
char s[] = {`H`, `e`, `l`, `l`, `o`};
char* pBegin = s;
char* pEnd = s + DIM(s); // key point
char* p = NULL;
printf("pBegin = %p
", pBegin);
printf("pEnd = %p
", pEnd);
printf("Size: %d
", pEnd - pBegin);
for(p=pBegin; p<pEnd; p++)
{
printf("%c
", *p);
}
printf("
");
return 0;
}
輸出:
pBegin = 0xbf9c17af
pEnd = 0xbf9c17b4
Size: 5
H
e
l
l
o
分析:
pEnd = s + DIM(s) ==>
s + 5 ==> 0xbf9c17af + 5 * sizeof(*s) ==> 0xbf9c17af + 5 * sizeof(char) ==> 0xbf9c17af + 5 * 1 ==> 0xbf9c17af + 5 ==> 0xbf9c17b4
小結
- 陣列宣告時編譯器自動分配一片連續的記憶體空間,空間名為陣列名
- 指標宣告是隻分配了用於容納地址值的 4 位元組空間
- 指標和整數可以進行運算,其結果為整數
- 指標之間只支援減法運算,其結果為陣列元素下標差
- 指標之間支援比較運算,其型別必須相同
補充:以上實驗在32位機器中執行。
當指標大小佔用 8 位元組時(64位機器), 使用 (unsigned int) 強制型別轉換將發生資料截斷,導致得到不正常的結果。
以上內容參考狄泰軟體學院系列課程,請大家保護原創!