C語言入坑指南-數(shù)組之謎

今天就不講新知識了恋技,記得復習前面的內(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青年

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市称杨,隨后出現(xiàn)的幾起案子流酬,更是在濱河造成了極大的恐慌涵防,老刑警劉巖峡眶,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揪利,死亡現(xiàn)場離奇詭異,居然都是意外死亡页衙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門阴绢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來店乐,“玉大人,你說我怎么就攤上這事呻袭≌0耍” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵左电,是天一觀的道長廉侧。 經(jīng)常有香客問我,道長篓足,這世上最難降的妖魔是什么段誊? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮栈拖,結(jié)果婚禮上连舍,老公的妹妹穿的比我還像新娘。我一直安慰自己涩哟,他們只是感情好索赏,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贴彼,像睡著了一般潜腻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锻弓,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天砾赔,我揣著相機與錄音,去河邊找鬼。 笑死暴心,一個胖子當著我的面吹牛妓盲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播专普,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼悯衬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了檀夹?” 一聲冷哼從身側(cè)響起筋粗,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炸渡,沒想到半個月后娜亿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蚌堵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年买决,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吼畏。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡督赤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泻蚊,到底是詐尸還是另有隱情躲舌,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布性雄,位于F島的核電站没卸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秒旋。R本人自食惡果不足惜办悟,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滩褥。 院中可真熱鬧病蛉,春花似錦、人聲如沸瑰煎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酒甸。三九已至魄健,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間插勤,已是汗流浹背沽瘦。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工革骨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人析恋。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓良哲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親助隧。 傳聞我的和親對象是個殘疾皇子筑凫,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容