今天就不講新知識了恋技,記得復習前面的內(nèi)容哦奸焙,在微信上看到一篇文章挺好的,直接轉(zhuǎn)了過來哀澈,和大家分享一下原文鏈接:嵌入式Linux
前言
在C語言中,數(shù)組和指針似乎總是“曖昧不清”度气,有時候很容易把它們混淆割按。本文就來理一理數(shù)組和指針之間到底有哪些異同。
數(shù)組回顧
在分析之前磷籍,我們不妨回顧一下數(shù)組的知識适荣。數(shù)組是可以存儲一個固定大小的相同類型元素的順序集合。為了便于我們說明院领,假設(shè)有以下數(shù)組聲明:
int a[5];
char b[] = "hello";
數(shù)組大小必須在編譯期就作為一個常數(shù)確定下來弛矛。
但C99中引入了變長數(shù)組,允許數(shù)組的維度是表達式 比然,但在數(shù)組分配內(nèi)存時丈氓,其表達式的值可以被求出。
數(shù)組下標運算實際上都是通過指針進行的,也就是說a[4]與*(a+4)是等價的万俗,甚至你會發(fā)現(xiàn)和4[a]也是一樣的鱼鼓。
數(shù)組名一般代表了指向該數(shù)組下標為0的元素的指針,并且printf("%s\n",hello)與printf("%s\n",&hello[0])等效该编。
數(shù)組和指針不相等
考慮下面的聲明:
int c[4];//假設(shè)int占4字節(jié)
int *d;
對于上面的聲明硕淑,編譯器會給c預(yù)留內(nèi)存空間4*4字節(jié)课竣,并且數(shù)組名代表著指向數(shù)組第一個元素的指針。但對于d置媳,卻只為指針本身保留了內(nèi)存空間于樟。
所以此時有下面的操作:
c[3]; //合法
*(c+3); //合法
*d; //不合法,d指向了內(nèi)存中不確定位置
c++拇囊; //不合法迂曲,一維數(shù)組名是指針常量,常量不能被修改掉
d++寥袭; //可通過編譯.
另外路捧,下面的兩種情況也是不一樣的:
char c[] = "hello";
char *d = "hello";
前者對字符數(shù)組c進行了初始化,后者將d指向了字符串常量传黄。字符串常量存儲在只讀區(qū)杰扫,因此有下面的操作:
c[0] = 'H'; //合法,可修改數(shù)組內(nèi)容
*d = 'H'; //不合法膘掰,字符串常量內(nèi)容不可更改
d[0] = 'H' //不合法
數(shù)組名的含義
絕大多數(shù)情況章姓,數(shù)組名都代表著指向該數(shù)組中下標為0的元素的指針,但是有例外:
int e[4];//假設(shè)int為4字節(jié)
sizeof(e);
上面的sizeof(e)的值并非4或8(指針占用空間)识埋,而是4*4 = 16凡伊。也就是說,當數(shù)組名被用作運算符sizeof的參數(shù)時窒舟,它的計算結(jié)果是整個數(shù)組的大小系忙,而非第一個元素的指針大小。
再來看下面這種情況:
int temp[5];
char *p = &temp;
char *q = temp;
在這里辜纲,p和q的值是一樣的笨觅,含義卻不一樣,前者是指向數(shù)組的指針耕腾,而后者是指向該數(shù)組中下標為0的元素的指針见剩。因此p+1指向了temp的末尾,而q+1指向了temp的第2個元素扫俺。
數(shù)組長度計算
如何計算數(shù)組長度苍苞?考慮下面的代碼:
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的值相等嗎?顯然并不相等。事實上羹呵,只有l(wèi)en_f得到了數(shù)組f的長度骂际,而len_g的值并沒有任何實際意義。
不能作為參數(shù)的數(shù)組
所謂的數(shù)組不能作為參數(shù)冈欢,并不是指聲明的數(shù)組不能作為參數(shù)傳遞歉铝,而是指當數(shù)組名作為參數(shù)時,數(shù)組名會被轉(zhuǎn)換為指向該數(shù)組下標為0的元素的指針凑耻。
而下面的兩種聲明太示,其實也是等效的:
size_t arrayLen(const int *arr);
size_t arrayLen(const int arr[]);
我們來看一個例子,說明數(shù)組作為參數(shù)的情況:
#include <stdio.h>
int arraySum(const int arr[])
{
unsigned int loop = 0;
/*循環(huán)前計算好長度香浩,提高性能*/
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;
}
我們運行上面的程序类缤,發(fā)現(xiàn)最終結(jié)果并不是我們預(yù)期的21,而是3邻吭。問題在于餐弱,a作為參數(shù)傳入到arraySum中時,它是作為指針的囱晴,那么在函數(shù)內(nèi)部計算sizeof(arr)自然只是得到了指針占用的內(nèi)存大小膏蚓。對于64位程序,這個大小是8速缆,那么len的值為2降允,最終只計算了兩個元素的和。
思考:該如何修改上面的程序才能得到正確的結(jié)果艺糜?
其實我們在使用數(shù)組名作為參數(shù)時剧董,傳遞過去的僅僅是數(shù)組第一個元素的首地址,上面例子算出來的len為1破停,我們算不出來sum的值翅楼。想要求出sum的值,必須把數(shù)組的長度傳遞過去真慢,下面給出一個答案示例:
#include <stdio.h>
int arraySum(const int arr[],int len)
{
unsigned int loop = 0;
/*循環(huán)前計算好長度毅臊,提高性能*/
// 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},len;
len=sizeof(a)/sizeof(int);
int sum = arraySum(a,len);
printf("arr sum is %d",sum);
return 0;
}
總結(jié)
我們來總結(jié)一下前面的核心內(nèi)容:
數(shù)組下標運算實際上都是通過指針進行的。
數(shù)組名代表著指向該數(shù)組中下標為0的元素的指針黑界,但有例外:sizeof(數(shù)組名)返回整個數(shù)組的大小管嬉,而非指針大小朗鸠;&數(shù)組名返回一個指向數(shù)組的指針蚯撩,而不是指向該數(shù)組中下標為0的元素的指針的指針。
數(shù)組名作為參數(shù)時烛占,數(shù)組名會被轉(zhuǎn)換成指向該數(shù)組下標為0的元素的指針胎挎。
指針操作可能比下標操作效率高沟启,但可維護性卻不一定有下標操作好。
數(shù)組和指針不相等犹菇。
思考
下面的代碼輸出結(jié)果是什么德迹?
#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;
}
//輸出2 5
本文章僅供學習交流用禁止用作商業(yè)用途,文中內(nèi)容來水枂編輯揭芍,如有侵權(quán)請聯(lián)系刪除胳搞,謝謝合作
微信公眾號:zhjj0729
微博:文藝to青年