C語言指針數組和數組指針

一、指針數組和數組指針的內存布局

初學者總是分不出指針數組與數組指針的區別。其實很好理解:
指針數組:首先它是一個數組,數組的元素都是指針,數組占多少個字節由數組本身決定。它是“儲存指針的數組”的簡稱。
數組指針:首先它是一個指針,它指向一個數組。在32 位系統下永遠是占4 個字節,至于它指向的數組占多少字節,不知道。它是“指向數組的指針”的簡稱。


下面到底哪個是數組指針,哪個是指針數組呢:
A)
int *p1[10];
B)
int (*p2)[10];
每次上課問這個問題,總有弄不清楚的。這里需要明白一個符號之間的優先級問題。

“[]”的優先級比“*”要高。p1 先與“[]”結合,構成一個數組的定義,數組名為p1,int *修飾的是數組的內容,即數組的每個元素。那現在我們清楚,這是一個數組,其包含10 個指向int 類型數據的指針,即指針數組。至于p2 就更好理解了,在這里“()”的優先級比“[]”高,“*”號和p2 構成一個指針的定義,指針變量名為p2,int 修飾的是數組的內容,即數組的每個元素。數組在這里并沒有名字,是個匿名數組。那現在我們清楚p2 是一個指針,它指向一個包含10 個int 類型數據的數組,即數組指針。我們可以借助下面的圖加深理解:

二、int (*)[10] p2-----也許應該這么定義數組指針

這里有個有意思的話題值得探討一下:平時我們定義指針不都是在數據類型后面加上指針變量名么?這個指針p2 的定義怎么不是按照這個語法來定義的呢?也許我們應該這樣來定義p2:
? ?int (*)[10] p2;
int (*)[10]是指針類型,p2 是指針變量。這樣看起來的確不錯,不過就是樣子有些別扭。其實數組指針的原型確實就是這樣子的,只不過為了方便與好看把指針變量p2 前移了而已。你私下完全可以這么理解這點。雖然編譯器不這么想。^_^

三、再論a 和&a 之間的區別

既然這樣,那問題就來了。前面我們講過a 和&a 之間的區別,現在再來看看下面的代碼:
int main()
{
? ?char a[5]={'A','B','C','D'};
? ?char (*p3)[5] = &a;
? ?char (*p4)[5] = a;
? ?return 0;
}
上面對p3 和p4 的使用,哪個正確呢?p3+1 的值會是什么?p4+1 的值又會是什么?毫無疑問,p3 和p4 都是數組指針,指向的是整個數組。&a 是整個數組的首地址,a是數組首元素的首地址,其值相同但意義不同。在C 語言里,賦值符號“=”號兩邊的數據類型必須是相同的,如果不同需要顯示或隱式的類型轉換。p3 這個定義的“=”號兩邊的數據類型完全一致,而p4 這個定義的“=”號兩邊的數據類型就不一致了。左邊的類型是指向整個數組的指針,右邊的數據類型是指向單個字符的指針。在Visual C++6.0 上給出如下警告:
? ?warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。
還好,這里雖然給出了警告,但由于&a 和a 的值一樣,而變量作為右值時編譯器只是取變量的值,所以運行并沒有什么問題。不過我仍然警告你別這么用。

既然現在清楚了p3 和p4 都是指向整個數組的,那p3+1 和p4+1 的值就很好理解了。

但是如果修改一下代碼,會有什么問題?p3+1 和p4+1 的值又是多少呢?
int main()
{
? ?char a[5]={'A','B','C','D'};
? ?char (*p3)[3] = &a;
? ?char (*p4)[3] = a;
? ?return 0;
}

甚至還可以把代碼再修改:
int main()
{
? ?char a[5]={'A','B','C','D'};
? ?char (*p3)[10] = &a;
? ?char (*p4)[10] = a;
? ?return 0;
}
這個時候又會有什么樣的問題?p3+1 和p4+1 的值又是多少?

上述幾個問題,希望讀者能仔細考慮考慮。

四、地址的強制轉換

先看下面這個例子:
struct Test
{
? ?int Num;
? ?char *pcName;
? ?short sDate;
? ?char cha[2];
? ?short sBa[4];
}*p;

假設p 的值為0x100000。如下表表達式的值分別為多少?
? ?p + 0x1 = 0x___ ?
? ?(unsigned long)p + 0x1 = 0x___?
? ?(unsigned int*)p + 0x1 = 0x___?
我相信會有很多人一開始沒看明白這個問題是什么意思。其實我們再仔細看看,這個知識點似曾相識。一個指針變量與一個整數相加減,到底該怎么解析呢?

還記得前面我們的表達式“a+1”與“&a+1”之間的區別嗎?其實這里也一樣。指針變量與一個整數相加減并不是用指針變量里的地址直接加減這個整數。這個整數的單位不是byte 而是元素的個數。所以:p + 0x1 的值為0x100000+sizof(Test)*0x1。至于此結構體的大小為20byte,前面的章節已經詳細講解過。所以p +0x1 的值為:0x100014。

(unsigned long)p + 0x1 的值呢?這里涉及到強制轉換,將指針變量p 保存的值強制轉換成無符號的長整型數。任何數值一旦被強制轉換,其類型就改變了。所以這個表達式其實就是一個無符號的長整型數加上另一個整數。所以其值為:0x100001。

(unsigned int*)p + 0x1 的值呢?這里的p 被強制轉換成一個指向無符號整型的指針。所以其值為:0x100000+sizof(unsigned int)*0x1,等于0x100004。

上面這個問題似乎還沒啥技術含量,下面就來個有技術含量的:在x86 系統下,其值為多少?
intmain()
{
? ?int a[4]={1,2,3,4};
? ?int *ptr1=(int *)(&a+1);
? ?int *ptr2=(int *)((int)a+1);
? ?printf("%x,%x",ptr1[-1],*ptr2);
? ?return 0;
}
這是我講課時一個學生問我的題,他在網上看到的,據說難倒了n 個人。我看題之后告訴他,這些人肯定不懂匯編,一個懂匯編的人,這種題實在是小case。下面就來分析分析這個問題:

根據上面的講解,&a+1 與a+1 的區別已經清楚。

ptr1:將&a+1 的值強制轉換成int*類型,賦值給int* 類型的變量ptr,ptr1 肯定指到數組a 的下一個int 類型數據了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 個byte。所以其值為0x4。
ptr2:按照上面的講解,(int)a+1 的值是元素a[0]的第二個字節的地址。然后把這個地址強制轉換成int*類型的值賦給ptr2,也就是說*ptr2 的值應該為元素a[0]的第二個字節開始的連續4 個byte 的內容。

其內存布局如下圖:
好,問題就來了,這連續4 個byte 里到底存了什么東西呢?也就是說元素a[0],a[1]里面的值到底怎么存儲的。這就涉及到系統的大小端模式了,如果懂匯編的話,這根本就不是問題。既然不知道當前系統是什么模式,那就得想辦法測試。大小端模式與測試的方法在第一章講解union 關鍵字時已經詳細討論過了,請翻到彼處參看,這里就不再詳述。我們可以用下面這個函數來測試當前系統的模式。
int checkSystem( )
{
? ?union check
? ?{
? ? ? int i;
? ? ?char ch;
? ?} c;
? ?c.i = 1;
? ?return (c.ch ==1);
}
如果當前系統為大端模式這個函數返回0;如果為小端模式,函數返回1。也就是說如果此函數的返回值為1 的話,*ptr2 的值為0x2000000。如果此函數的返回值為0 的話,*ptr2 的值為0x100。

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

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

相關文章

求二叉樹的高度

1 int GetHeight(BinTree BT)2 {3 int HL, HR, MaxH;4 5 if(BT)6 {7 HL GetHeight(BT->Left); //求左子樹的高度8 HR GetHeight(BT->Right); //求右子樹的高度9 MaxH (HL > HR) ? HL : HR; //取左右子樹較大的高…

Json與List的相互轉換

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 問題由來: 最近由于做一個項目,項目的一個功能就是根據Listview的內容生成一個二維碼,然后掃描二維…

機器學習常用模型

(原作:MSRA劉鐵巖著《分布式機器學習:算法、理論與實踐》。這一部分敘述很清晰,適合用于系統整理NN知識) 線性模型 線性模型是最簡單的,也是最基本的機器學習模型。其數學形式如下:g(X;W)WTX。有…

(轉)告別程序員生涯,一點感慨,與諸君共勉

轉自:https://blog.csdn.net/phphot/article/details/2230411 再過幾天,我就正式告別程序員生涯了,這也是我最后一次以職業程序員身份在CSDN發表文章。小弟談談入行幾年來的感受,做一個人生階段的自我總結,同時希望能…

C語言指針與數組之間的恩恩怨怨

很多初學者弄不清指針和數組到底有什么樣的關系。我現在就告訴你:他們之間沒有任何關系!只是他們經常穿著相似的衣服來逗你玩罷了。指針就是指針,指針變量在32 位系統下,永遠占4 個byte,其值為某一個內存的地址。指針可…

CentOS7查看開放端口命令

CentOS7查看開放端口命令CentOS7的開放關閉查看端口都是用防火墻來控制的,具體命令如下:查看已經開放的端口:Linux代碼 firewall-cmd --list-ports 開啟端口Linux代碼 firewall-cmd --zonepublic --add-port80/tcp --permanent 命令含義&…

referer參數和addslashes()函數的騷路子

TIPS: 此函數確實是過濾用戶輸入的,當gpc未開啟的時候使用addslashes()函數進行過濾,當開啟gpc的時候直接返回,那么問題就來了,當php開啟gpc的時候直接返回字符串,但是gpc是只針GET,POST,COOKIE三種超全局變量進行過濾…

MySQL 的各個json 函數說明

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 如果英文的不方便閱讀,請參考個人收錄的另一篇中文解說:MySQL中json函數說明和舉例 只是為了方便 自己用的時候…

訂單編號,遞增且不連續(php版)

1、實現方式&#xff0c;使用while循環&#xff0c;比較low&#xff0c;200w條數據 2s public function getMany ($startNum, $count) {$num $startNum;$codes[] $startNum;for($i1;$i<$count;$i){$num1 random_int(1,9);while($num $num1) {$num1 random_int(1,9);}$…

一文搞懂:詞法作用域、動態作用域、回調函數、閉包

把以前一直只限于知道&#xff0c;卻不清晰理解的這幾個概念完完整整地梳理了一番。內容參考自wiki頁面&#xff0c;然后加上自己一些理解。 詞法作用域和動態作用域 不管什么語言&#xff0c;我們總要學習作用域(或生命周期)的概念&#xff0c;比如常見的稱呼&#xff1a;全局…

C語言函數指針

一、函數指針的定義 顧名思義&#xff0c;函數指針就是函數的指針。它是一個指針&#xff0c;指向一個函數。看例子&#xff1a;A)char * (*fun1)(char * p1,char * p2);B)char * *fun2(char * p1,char * p2);C)char * fun3(char * p1,char * p2);看看上面三個表達式分別是什么…

程序員進階之算法練習:LeetCode專場

歡迎大家前往騰訊云社區&#xff0c;獲取更多騰訊海量技術實踐干貨哦~ 本文由落影發表 前言 LeetCode上的題目是大公司面試常見的算法題&#xff0c;今天的目標是拿下5道算法題&#xff1a; 題目1是基于鏈表的大數加法&#xff0c;既考察基本數據結構的了解&#xff0c;又考察在…

vim 安裝vim-prettier

1、在.vimrc中添加 配置沒有安裝成功的話 git clone https://github.com/prettier/vim-prettier Plug prettier/vim-prettier, { do: yarn install, for: [javascript, typescript, css, less, scss, json, graphql, markdown, vue, yaml, html, php] } let g:prettier#aut…

詳解Mysql中的JSON系列操作函數

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一、方法羅列&#xff1a; 分類 函數 描述創建jsonjson_array 創建json數組json_object 創建json對象 json_quote 將json轉成json字符串…

WEB/H5性能優化總結

我們今天來說說前端圖形渲染優化&#xff0c;因為我接下來的時間可能要開始研究webgl方面的東西&#xff0c;所以就在這里把之前做過的H5做一個總結&#xff0c;現同步發布于GERRY_BLOG&#xff0c;TiMiGerry-知乎&#xff0c;轉載請保留鏈接。靜態資源-圖片 一 、圖片格式JPEG…

C語言數組參數與指針參數

我們都知道參數分為形參和實參。形參是指聲明或定義函數時的參數&#xff0c;而實參是在調用函數時主調函數傳遞過來的實際值。 一、一維數組參數 1、能否向函數傳遞一個數組&#xff1f;看例子&#xff1a;void fun(char a[10]){char c a[3];}intmain(){char b[10] “abcd…

maven文件結構

pom.xml 用于maven的配置文件 /src 源代碼目錄 /src/main 工程源代碼目錄 /src/main/java 工程java源代碼目錄 /src/main/resource 工程的資源目錄 /src/test 單元測試目錄 /src/test/java /target 輸出目錄&#xff0c;所有的輸出都存放在這個目錄下 /target/classes 編譯之…

php如何使用高階函數

1、首先學會數組轉集合的方式 &#xff08;1&#xff09;使用collect函數 $arr [1, 2, 3, 4, 5]; $collect collect($arr); &#xff08;2&#xff09;使用array_map函數 $arr [1, 2, 3, 4, 5]; $collect array_map(function($item){ return $item *…

Git 使用,命令說明

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. D:\ChengXu\git\Git中雙擊Git Bash啟動git窗口。 2. 這條不能放到博客&#xff0c;是我的賬號密碼。 3. 添加&#xff1a; git add …

2017ACM/ICPC亞洲區沈陽站 C Hdu-6219 Empty Convex Polygons 計算幾何 最大空凸包

題面 題意:給你一堆點,求一個最大面積的空凸包,里面沒有點. 題解:紅書板子,照抄完事,因為題目給的都是整點,所以最后答案一定是.5或者.0結尾,不用對答案多做處理 1 #include<bits/stdc.h>2 #define N 553 using namespace std;4 struct rec5 {6 double x,y;7 };8 rec…