<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
下面看一段程式碼:
#include <stdio.h> int main() { int a[5] = {0}; int* p = NULL; printf("a = 0x%Xn", (unsigned int)(a)); printf("a + 1 = 0x%Xn", (unsigned int)(a + 1)); printf("p = 0x%Xn", (unsigned int)(p)); printf("p + 1 = 0x%Xn", (unsigned int)(p + 1)); return 0; }
輸出結果如下:
通過這段程式碼說明指標運算是合法的。
指標是一種特殊的變數,與整數的運算規則為
p + n; <-->(unsigned int)p + n*sizeof(*p);
結論∶
當指標 p 指向一個同型別的陣列的元素時:p+1 將指向當前元素的下一個元素;p-1 將指向當前元素的上一個元素。
p1- p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);
注意:
下面看一段簡單的指標運算程式碼:
#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("%dn", p0 - p1); //printf("%dn", p0 + p2); //ERROR printf("%dn", p0 - p2); //printf("%dn", p0 - p); //ERROR //printf("%dn", p0 * p2); //ERROR //printf("%dn", p0 / p2); //ERROR return 0; }
輸出結果如下:
注意兩個指標指向不同的陣列,雖然它們兩相減符合語法,但是最後的結果肯定沒有意義。
再來看一段指標運算的應用程式碼:
#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 = %pn", pBegin); printf("pEnd = %pn", pEnd); printf("Size: %dn", pEnd - pBegin); for(p=pBegin; p<pEnd; p++) { printf("%c", *p); } printf("n"); return 0; }
輸出結果如下:
注意以下幾點:
#define DIM(a) (sizeof(a) / sizeof(*a))
char* pEnd = s + DIM(s); // Key point ==> pEnd 指向 'o' 後面的地址 ==>
這在 C 語言中是一個擦邊球的邊界位置,也是一個技巧,在這個邊界位置可以認為該指標是合法的,可以和其他指標進行比較運算和減法運算等,在 C++ 標準庫裡面也合法以下標的形式存取陣列中的元素
以指標的形式存取陣列中的元素
a[n] <--> *(a +n) <--> *(n + a) <--> n[a]
注意:現代編譯器的生成程式碼優化率已大大提高,在固定增量時,下標形式的效率已經和指標形式相當;但從可讀性和程式碼維護的角度來看,下標形式更優。
下面看一個陣列的存取方式程式碼:
#include <stdio.h> int main() { int a[5] = {0}; int* p = a; int i = 0; for(i=0; i<5; i++) { p[i] = i + 1; } for(i=0; i<5; i++) { printf("a[%d] = %dn", i, *(a + i)); } printf("n"); for(i=0; i<5; i++) { i[a] = i + 10; } for(i=0; i<5; i++) { printf("p[%d] = %dn", i, p[i]); } return 0; }
輸出結果如下:
注意這個奇怪的寫法:i[a] = i + 10; ==> a[i] = i + 10;
下面通過一個範例,說明陣列和指標的不同:
ext.c:
int a[] = {1, 2, 3, 4, 5};
test.c:
#include <stdio.h> int main() { extern int a[]; printf("&a = %pn", &a); printf("a = %pn", a); printf("*a = %dn", *a); return 0; }
輸出結果如下:
下面來驗證一下陣列名究竟是不是指標,將 test.c 改成:
#include <stdio.h> int main() { extern int* a; printf("&a = %pn", &a); printf("a = %pn", a); printf("*a = %dn", *a); return 0; }
輸出結果如下:
ext.c 中 a[ ] 的地址為 0x804a014,test.c 中的extern int* a; 只是申明識別符號 a,編譯器會認為在這之前就已經給了地址值,就是 0x804a014,所以printf("a = %pn", a); 就是列印0x804a014 地址中的 4 個位元組的數,也就是 a[ ] 陣列中的第一個元素 1,所以列印 0x1,*a 就是取 0x1 地址中的數,但是這個地址值是留給作業系統的,不可存取,存取就會產生段錯誤。
這個就能看出 a + 1 和 &a + 1 的不同,a + 1 增加的步長是一個元素的大小,&a + 1 則是增加的步長是整個陣列的大小。
下面看一個指標運算的經典問題:
#include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; int* p1 = (int*)(&a + 1); int* p2 = (int*)((int)a + 1); int* p3 = (int*)(a + 1); printf("%d, %d, %dn", p1[-1], p2[0], p3[1]); return 0; }
輸出結果如下:
p1[-1] 就是 *(p1 - 1),由於 p1 指向的元素是 5 後面的位置,減 1 之後就指向了 5;p2 的地址是 0x804a015(注意 linux 系統為小端系統),*p2 就是 0x02000000,對應十進位制的值就是 33554432;p3 的地址為 &a[1],所以 p3[1] 就是 3 了。
陣列作為函數引數時,編譯器將其編譯成對應的指標
結論:一般情況下,當定義的函數中有陣列引數時,需要定義另一個引數來標示陣列的大小。
下面看一段程式碼:
#include <stdio.h> void func1(char a[5]) { printf("In func1: sizeof(a) = %dn", sizeof(a)); *a = 'a'; a = NULL; } void func2(char b[]) { printf("In func2: sizeof(b) = %dn", sizeof(b)); *b = 'b'; b = NULL; } int main() { char array[10] = {0}; func1(array); printf("array[0] = %cn", array[0]); func2(array); printf("array[0] = %cn", array[0]); return 0; }
輸出結果如下:
這段程式碼就說明陣列引數退化成指標,因為 sizeof(a) 為 4 個位元組,而不是 5 個位元組。
陣列名和指標僅使用方式相同
陣列名並不是陣列的地址,而是陣列首元素的地址
函數的陣列引數退化為指標
到此這篇關於C語言零基礎講解指標和陣列的文章就介紹到這了,更多相關C語言 指標和陣列內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45