C語言的數組名和對數組名取地址

***************************************************

更多精彩,歡迎進入:http://shop115376623.taobao.com

***************************************************


相信不少的C語言初學者都知道,數組名相當于指針,指向數組的首地址,而函數名相當于函數指針,指向函數的入口地址。

現在有這樣一個問題,如果對數組名取地址,那得到的會是什么呢?很多人立刻會想到:給指針取地址,就是指針的指針,

即二級指針嘛!當然這樣的結論是錯誤的,不然這篇筆記也就沒有意義了。


下面我們來逐步分析,下面是一段驗證這個問題的代碼

Code:
  1. #include<stdio.h>???
  2. int?main() ??
  3. { ??
  4. ????int?a[10]; ??
  5. ??
  6. ????printf("a:/t%p/n",?a);????????? ??
  7. ????printf("&a:/t%p/n",?&a);??????? ??
  8. ????printf("a+1:/t%p/n",?a+1);????? ??
  9. ????printf("&a+1:/t%p/n",?&a+1);?? ??
  10. ??
  11. ????return?0; ??
  12. }??

?

大家可以編譯運行一下,我的輸出的結果是:

Code:
  1. /*???
  2. a:??????????0012FF20??
  3. &a:?????????0012FF20??
  4. a+1:????????0012FF24??
  5. &a+1:?????? 0012FF48??
  6. */??

a和&a指向的是同一塊地址,但他們+1后的效果不同,a+1是一個元素的內存大小(增加4),而&a+1增加的是整個數組的內存

大小(增加40)。既a和&a的指向和&a[0]是相同的,但性質不同!

讀到這里,有很多朋友已經明白其中的機制了,如果還是有些模糊,請繼續往下看

Code:
  1. int?main() ??
  2. { ??
  3. ????int?a[10]; ??
  4. ????printf("%d/n",sizeof(a)); ??
  5. ????return?0; ??
  6. }??

這段代碼會輸出整個數組的內存大小,而不是首元素的大小,由此我們是否聯系到,sizeof(a)這里的a和
&a有些相同之處呢?!? 是的,沒錯,&a取都得是整個數組的地址!既數組名取地址等價于對數組取地址。


好了,讓我們總結一下,如果你還是不太理解,不用擔心,下面的概念很清晰


其實a和 &a結果都是數組的首地址,但他們的類型是不一樣。
a表示&a[0],也即對數組首元素取地址,a+1表示首地址+sizeof(元素類型)。
&a雖然值為數組首元素地址,但類型為:類型 (*)[數組元素個數],所以&a+1大小為:首地址+sizeof(a)。


還有這篇文章最初提到的指針的指針的那個錯誤結論,其實即使不懂上述內容,也應該判斷出結論是錯誤的,大家應該在了解數組名

即是數組的首地址的同時,也要知道,數組名僅僅是“相當”于指針,而并非真的是指針,數組名是只是個常量(一個值為數組首元素

地址的常量),所以不能進行++或者--運算。而常量更是無法取地址的,而之所以有&a,其實這里的a的意義早已經不是當初那個數組

名了,它此時代表了整個數組。





C語言數組首地址和數組名取地址區別
2010年11月24日 11:51

申明:本文系原創,轉載時請注明出處,本人保留追究責任的權利。

原文地址:http://hi.baidu.com/surfmygod/blog/item/53d44914cdb8a5d6a7ef3f13.html


本文適用于機器為32位,編譯器為VC6.0

先來看下面一個例子:
main()
{
int a[5]={0x11121314,0x21222324,0x31323334,0x41424344,0x51525354};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)(a+1);
printf("%x,%x",ptr1[-1],*ptr2);
getch();
}
打印輸出的結果是多少?第4行&a是不是寫錯了?數組名怎么還取地址呢?
你可以試著在軟件中編譯運行一下,結果是51525354,21222324,沒錯,就是它了。你可以試著寫以下程序
再在計算機中編譯運行下:

main()

{

int a[5]={0x11121314,0x21222324,0x31323334,0x41424344,0x51525354};

printf("%p\n%p\n",a,&a);

printf("%d\n%d\n",sizeof(a),sizeof(&a));

printf("%p\n%p",&a+1,a+1);

getch();

}

你可以看到前兩行a和&a打印的結果是一樣的(比如0012FF6C),后兩行的結果是都是20,而&a+1的結果是0012FF6C,

即a的起始地址后移20字節。看到這里對于a和&a的區別是不是有些眉目了?不錯,a和&a的值雖然一樣,但是前者表示

的是數組a的首地址,進階為數組元素長度,而后者也是表示數組a的首地址(或許有些人不同意我這個觀點,對地址

取地址應該是指向指針的指針呀。不過你注意了沒有,a和&a值是一樣的,試想如果這里表示的是指向指針的指針,

那么a的地址和指向a的指針的地址可能一樣么?

兩個指針都指向數組首地址,怎么會是指向指針的指針?還有一點需要強調,對一個指針進行sizeof運算,32位系統

下應該得到4,而對數組名進行sizeof運算得到的結果卻是20,這說明了什么?很顯然,數組名雖然能夠拿出來代表

一個地址,但是它和指針還是有區別的,對它進行sizeof運算也不會得到指針的大小。不信?你可以試試sizeof(&a[0])

和sizeof(a),看看結果是不是相同),

但是是將整個數組作為一個對象來看待的,進階為整個數組長度。也就是說,a和&a雖然值相同,但是a是將所有數組

元素看成一個個不同的個體來對待的,而&a是將整個數組作為一個整體來對待的。這里要強調的是,a+1和&a[1]其實

是一樣的,都是代表a數組向后偏移一個元素的地址,你可以再用sizeof關鍵字打印一下兩個的值。但是a和&a[0]的

意義相同么?若打印地址的話,兩者確實是一樣的,但是你也用sizeof打印下兩者,一樣么?再試試a+0呢?很顯然,

a和a+0是有區別的,但是a+0和&a[0]是含義相同的。所以,你可以說a+i和&a[i]含義相同,但是絕不能說a和&a[0]

或a+0含義相同。所以&a+1后移20位為&a+sizeof(&a),而a+1卻是a+sizeof(a[i])。

(《C語言深度解剖》認為在32為系統下sizeof(&a)的值仍為4,我覺得是不對的。他覺得是VC6.0錯了,其實不止VC,

其他很多編譯器得到的結果也不會是4,這說明a和&a在C中本來就不是作為指針來用的,只是具有指針的部分性質而已。)



ptr1是將&a+1強轉為int類型指針,此時打印ptr1[-1]即將ptr指針前移sizeof(int)個字節,故打印結果是5。

這樣一來后面的也明了了,a+1的值為在數組a的首地址上后移sizeof(int)個字節,然后強轉為int類型指針

(其實強轉并沒有改變什么,原來類型即為整型指針,可以去掉強轉),最后輸出結果為21222324。


再想一下,如果將第一例第五行改為int *ptr2=(int *)((int)a+1);打印結果會是什么?

這里要考慮數據在計算機中的存儲模式:大端模式和小端模式。解釋一下:

大端模式(Big_endian):字數據的高字節存儲在低地址中,而字數據的低字節則存放在高地址中。
小端模式(Little_endian):字數據的高字節存儲在高地址中,而字數據的低字節則存放在低地址中。

在大端模式下,a在計算機中存儲如下(從低地址到高地址,一個十六進制數代表內存的一個字節,下同):
0x11 0x12 0x13 0x14 0x21 0x22 0x23 0x24 0x31 0x32 0x33 0x34 0x41 0x42 0x43 0x44 0x51 0x52 0x53 0x54

在小端模式下,a在計算機中存儲如下:
0x14 0x13 0x12 0x11 0x24 0x23 0x22 0x21 0x34 0x33 0x32 0x31 0x44 0x43 0x42 0x41 0x54 0x53 0x52 0x51

(int)a表示將a的首地址強轉為整型數據(若原來是0012FF6C,轉換后仍為0012FF6C,但是這時已經不是表示地址而是一個
十六進制整型數了),這時+1代表整型數(int)a加1(變為0012FF6D),再把結果強轉為整形指針,故指向的數據地址為0012FF6D,
即上述存儲去的第二個字節開始處。此時輸出*ptr2,即輸出a數組存儲區中第二到第五字節組成的一個整型數,若為大端模式則輸出
12131421,若為小端模式則輸出24111213。



補充說明下,在vc6.0上,上面sizeof(&a)才是20,而在GCC ,以及之后的vc版本(如vs2005及之后版本)則是將&a完全視作一個指針,sizeof(&a)為4 (32位機器)



二維數組名問題?
轉自: ?http://zhidao.baidu.com/question/386658092.html

int  *p1[3],     (*p2)[2], ** p,    a[3][2];a) p1=a;是否語法正確?  b)  p2=a;呢? ?  為什么?請詳述原因。        c)  p=a;  是否正確???可不可以認為二維數組名是一個指向指針的指針變量?  
 
 
 
a)不正確!p1是指針數組,他的元素是指針,但是他是數組,數組名不可以寫在賦值號左邊。b)正確!p2是數組指針,他可以指向一個數組。在這里他可以指向一個包含2個元素的數組。而二維數組的本質是指針數組,每個元素是一個 數組指針(這點是核心)。a[3][2] 的實質是:一個有3個元素的數組,每個元素是數組指針,該指針指向一個含有2個元素的數組(因為內存是個大的1維數組,所有東西在內存里都是1維數組)。#include <stdio.h>int main(void){    int (*p1)[2];    int a[3][2];    p1=a;    printf("%p, %p\n",p1+2,a+2);    while(1);    return 0;}以上程序可以說明b是正確的。c:不正確!如果你做p++那么p的值只增加了4(一個指針大小),而不是增加8(一個 p[2] 大小) 
 
 
其他網址:?http://topic.csdn.net/u/20100106/15/e5fa8fa6-555e-4729-a435-d1f8fdac5612.html



示例程序:

?#if 1

#include <stdio.h>
#include <stdlib.h>



int main()
{
int a[] = {1,2,3,4,5};
int *p1 = (int *)(a+1);
int *p2 = (int *)(&a+1);?
int *p3 = (int *)((int)a + 1);
int *p4 = a;?
printf("a is %p \n",a);
printf("&a is %p \n",&a);
printf("sizeof(a) = %d\n",sizeof(a));
printf("sizeof(&a) = %d\n",sizeof(&a));
printf("sizeof(p4) = %d \n",sizeof(p4));?
printf("p1 = %p \n",p1);
printf("p2 = %p \n",p2);
printf("*p1 = %d\n",*p1);
printf("p2[-1] = %d\n",p2[-1]);
printf("*p3 = %d \n",*p3);
printf("*(p2-1) = %d \n",*(p2-1));
?? ? ? ?
? ? system("PAUSE");
? ? return 0;
}

#endif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458843.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458843.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458843.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小米 android 8,小米華為們誰最良心?10大手機廠商安卓8.0升級情況盤點

3月8日&#xff0c;谷歌放出了首個安卓9.0開發者預覽版的固件包&#xff0c;不出意外的話&#xff0c;它的正式版會在今年正式亮相。但對廣大安卓用戶來說&#xff0c;想要立刻用上最新系統并非易事。目前來說&#xff0c;安卓碎片化問題依然嚴重&#xff0c;我們不妨現實點&am…

窺探Swift之數組安全索引與數組切片

在Swift中的數組和字典中下標是非常常見的&#xff0c;數組可以通過索引下標進行元素的查詢&#xff0c;字典可以通過鍵下標來獲取相應的值。在使用數組時&#xff0c;一個常見的致命錯誤就是數組越界。如果在你的應用程序中數組越界了&#xff0c;那么對不起&#xff0c;如果由…

大小端模式的快速判斷方法

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 大小端的問題剖析&#xff1a; 嵌 入式系統開發者應該對Little-endian和Big-endian模…

【RAC】How to Proceed from Failed 11gR2 CRS Installation

Applies to: [ID 942166.1] Oracle Server – Enterprise Edition – Version: 11.2.0.1 to 11.2.0.2 – Release: 11.2 to 11.2 Generic UNIX Generic Linux Goal This goal of this note is to provide steps to proceed from failed 11gR2 Grid Infrastructure installat…

WinForm支持拖拽效果

有一個MSDN客戶提問在WinForm中如何實現拖拽效果——比如在WinForm中有一個Button&#xff0c;我要實現的效果是拖拽這個Button到目標位置后生成一個該控件的副本。 其實這個操作主要分成三步走&#xff1a; 1&#xff09;確定被拖拽的對象&#xff1a; 這里是Button&#xff0…

win7 64位出現桌面右鍵鼠標顯示忙碌

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 將下面綠色內容復制到txt文本中&#xff0c;然后另存為1.bat 雙擊運行即可 【針對64位…

android tee,Android 9.0的新增安全特性與TEE

Android P&#xff0c;預計將于 2018 年第三季度發布最終版本。特別是Android8.0以來&#xff0c;安全性是Android版本變更的一個重要因素。從安全性增強方面來看&#xff0c;本次Android9.0版本主要有以下幾個方面&#xff1a;統一的指紋身份驗證對話框Android P 中&#xff0…

哪些要素會讓咱們呈現抑郁癥的病癥

依據最新研討標明&#xff0c;一自個的性情怎樣&#xff0c;本來是天然生成的&#xff0c;后天的日子&#xff0c;僅僅對咱們的性情進行批改&#xff0c;但在咱們潛意識中&#xff0c;違反自個性情的行動&#xff0c;會讓咱們感到格外累&#xff0c;所以&#xff0c;不少人即是…

如何定義一個只能在堆上(棧上)生成對象的類?

在C中&#xff0c;類的對象建立分為兩種&#xff0c;一種是靜態建立&#xff0c;如A a&#xff1b;另一種是動態建立&#xff0c;如A* ptrnew A&#xff1b;這兩種方式是有區別的。 靜態建立一個類對象&#xff0c;是由編譯器為對象在棧空間中分配內存&#xff0c;是通過直接移…

canny算子的理論分析

****************************************************************************************************************************************** 紅&#xff1a;數字圖像處理視頻教程&#xff08;兩部&#xff09; {中科院版36講視頻教程 電子科大版70講視頻教程&#x…

Android為spinner設置適配器,Android Spinner與適配器模式詳解及實例代碼

最近做項目對Android Spinner 使用&#xff0c;這里簡單寫個小例子&#xff0c;來測試如何使用。Spinner是一個下拉列表&#xff0c;往安卓界面中拖拽一個Spinner控件&#xff0c;在屬性中設置Android:entries“array/spinner_data”其中spinner_data為在string中設置的數組。數…

web框架-Struts開始

問題&#xff1a; 為什么有structs 作為一種框架&#xff08;frameset&#xff09;可以與傳統的mvc進行比較&#xff1f; MVC是一種模式數據處理、顯示和數據輸入分開&#xff0c;來規范開發&#xff0c;但是卻又并不規范。可以這樣想&#xff1a;有三家公司&#xff0c;他們對…

加快上架方法

估計最近蘋果app應用上架的比較多&#xff0c;審核比較慢&#xff0c;現在一個app從提交到上架短則7&#xff0c;8天&#xff0c;長則2&#xff0c;3個星期。我在實際上線應用時&#xff0c;總結了一個簡單實用的小技巧&#xff0c;可以加快上架時間&#xff0c;最近使用這種方…

接口自動化測試 返回html,接口自動化測試實戰(更新完畢)

前言自動化沒練習的項目怎么辦&#xff1f;自動化已經成為測試的必備技能之一了&#xff0c;所以&#xff0c;很多想跳槽的測試朋友都在自學&#xff0c;特別是最實用的接口自動化&#xff0c;但是很多人因為沒有可以練手的項目而苦惱&#xff0c;最終導致缺乏實戰經驗&#xf…

Opencv 圖像增強算法 圖像檢測結果及代碼

****************************************************************************************************************************************** 紅&#xff1a;數字圖像處理視頻教程&#xff08;兩部&#xff09; {中科院版36講視頻教程 電子科大版70講視頻教程&#x…

php Hash Table(四) Hash Table添加和更新元素

HashTable添加和更新的函數&#xff1a; 有4個主要的函數用于插入和更新HashTable的數據: int zend_hash_add(HashTable *ht, char *arKey, uint nKeyLen,void **pData, uint nDataSize, void *pDest); int zend_hash_update(HashTable *ht, char *arKey, uint nKeyLen, void …

山寨“餓了么”應用中添加菜品數量按鈕效果

山寨“餓了么”應用中添加菜品數量按鈕效果 本人視頻教程系類 iOS中CALayer的使用 最終效果&#xff1a; 山寨源頭&#xff1a; 源碼&#xff1a;&#xff08;此源碼解決了重用問題&#xff0c;可以放心的放在cell中使用&#xff09; AddAndDeleteButton.h 與 AddAndDeleteBu…

html間數據傳送,Express框架與html之間如何進行數據傳遞(示例代碼)

關于Node.js 的Express框架介紹&#xff0c;推薦看菜鳥教程的Express框架&#xff0c;很適合入門&#xff0c;這里不再贅述&#xff0c;這里主要講一下Express框架與html之間如何進行數據傳遞我采用的是JQuery的Ajax()向后臺傳參方式(url傳參)1、Type屬性為Get時&#xff1a;(1…

數字圖像去噪典型算法及matlab實現

圖像去噪是數字圖像處理中的重要環節和步驟。去噪效果的好壞直接影響到后續的圖像處理工作如圖像分割、邊緣檢測等。圖像信號在產生、傳輸過程中都可能會受到噪聲的污染&#xff0c;一般數字圖像系統中的常見噪聲主要有&#xff1a;高斯噪聲&#xff08;主要由阻性元器件內部產…

pat1100. Mars Numbers (20)

1100. Mars Numbers (20) 時間限制400 ms內存限制65536 kB代碼長度限制16000 B判題程序Standard 作者CHEN, YuePeople on Mars count their numbers with base 13: Zero on Earth is called "tret" on Mars.The numbers 1 to 12 on Earch is called "jan, feb, …