C语言入坑指南-数组之谜
前言
在C語言中,數組和指針似乎總是“曖昧不清”,有時候很容易把它們混淆。本文就來理一理數組和指針之間到底有哪些異同。
數組回顧
在分析之前,我們不妨回顧一下數組的知識。數組是可以存儲一個固定大小的相同類型元素的順序集合。為了便于我們說明,假設有以下數組聲明:
int?a[5]; char?b[]?=?"hello";數組大小必須在編譯期就作為一個常數確定下來。
但C99中引入了變長數組,允許數組的維度是表達式 ,但在數組分配內存時,其表達式的值可以被求出。
數組下標運算實際上都是通過指針進行的,也就是說a[4]與*(a+4)是等價的,甚至你會發現和4[a]也是一樣的。
數組名一般代表了指向該數組下標為0的元素的指針,并且printf("%s\n",hello)與printf("%s\n",&hello[0])等效。
數組和指針不相等
考慮下面的聲明:
int?c[4];//假設int占4字節 int?*d;對于上面的聲明,編譯器會給c預留內存空間4*4字節,并且數組名代表著指向數組第一個元素的指針。但對于d,卻只為指針本身保留了內存空間。
c[3];????????//合法 *(c+3);??????//合法 *d;??????????//不合法,d指向了內存中不確定位置 c++;????????//不合法,一維數組名是指針常量,常量不能被修改掉 d++;????????//可通過編譯另外,下面的兩種情況也是不一樣的:
char?c[]?=?"hello"; char?*d?=?"hello";前者對字符數組a進行了初始化,后者將d指向了字符串常量。字符串常量存儲在只讀區,因此有下面的操作:
?c[0]?=?'H';??//合法,可修改數組內容*d?=?'H';????//不合法,字符串常量內容不可更改d[0]?=?'H'???//不合法數組名的含義
絕大多數情況,數組名都代表著指向該數組中下標為0的元素的指針,但是有例外:
int?e[4];//假設int為4字節 sizeof(e);上面的sizeof(e)的值并非4或8(指針占用空間),而是4*4 = 16。也就是說,當數組名被用作運算符sizeof的參數時,它的計算結果是整個數組的大小,而非第一個元素的指針大小。
int?temp[5]; char?*p?=?&temp; char?*q?=?temp;在這里,p和q的值是一樣的,含義卻不一樣,前者是指向數組的指針,而后者是指向該數組中下標為0的元素的指針。因此p+1指向了temp的末尾,而q+1指向了temp的第2個元素。
數組長度計算
如何計算數組長度?考慮下面的代碼:
int?f[]?=?{1,2,3,4,5,6}; int?*g?=?f; size_t?len_f?=?sizeof(f)/sizeof(int)//正確計算方法 size_t?len_g?=?sizeof(g)/sizeof(int)上面的len_f和len_g的值相等嗎?顯然并不相等。事實上,只有len_f得到了數組f的長度,而len_g的值并沒有任何實際意義。
不能作為參數的數組
所謂的數組不能作為參數,并不是指聲明的數組不能作為參數傳遞,而是指當數組名作為參數時,數組名會被轉換為指向該數組下標為0的元素的指針。
size_t?arrayLen(const?int?*arr); size_t?arrayLen(const?int?arr[]);我們來看一個例子,說明數組作為參數的情況:
#include?<stdio.h> int?arraySum(const?int?arr[]) {unsigned?int?loop?=?0;/*循環前計算好長度,提高性能*/unsigned?int?len?=?sizeof(arr)/sizeof(int);int?sum?=?0;if(NULL?==?arr){return?0;}for(loop?=?0;?loop?<?len;?loop++){sum+=arr[loop];}return?sum;??? } int?main(void) {int?a[]?=?{1,2,3,4,5,6};int?sum?=?arraySum(a);printf("arr?sum?is?%d",sum);return?0; }我們運行上面的程序,發現最終結果并不是我們預期的21,而是3。問題在于,a作為參數傳入到arraySum中時,它是作為指針的,那么在函數內部計算sizeof(arr)自然只是得到了指針占用的內存大小。對于64位程序,這個大小是8,那么len的值為2,最終只計算了兩個元素的和。
思考:該如何修改上面的程序才能得到正確的結果?
總結
我們來總結一下前面的核心內容:
數組下標運算實際上都是通過指針進行的。
數組名代表著指向該數組中下標為0的元素的指針,但有例外:sizeof(數組名)返回整個數組的大小,而非指針大小;&數組名返回一個指向數組的指針,而不是指向該數組中下標為0的元素的指針的指針。
數組名作為參數時,數組名會被轉換成指向該數組下標為0的元素的指針。
指針操作可能比下標操作效率高,但可維護性卻不一定有下標操作好。
數組和指針不相等。
思考
下面的代碼輸出結果是什么?
#include<stdio.h> int?main(void) {int?a[5]?=?{1,2,3,4,5};int?*p?=?(int*)(&a+1);printf("%d,%d",*(a+1),*(p-1));return?0; }掃碼或長按關注
回復「?加群?」進入技術群聊
總結
以上是生活随笔為你收集整理的C语言入坑指南-数组之谜的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全球与中国ARM开发套件市场现状及未来发
- 下一篇: AD9371、AD9361、ADRV90