国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

解讀C指針

發布時間:2020-4-30 15:40    發布者:嵌入式人生17
解讀C指針
         我想對很多學習C語言的新手來說,指針無疑是一個難點。但是,我覺得指針也是C語言特別重要的一個特性。也許,你在除了C和C++以外的編程語言中,很少看到指針。而C++中,也多用引用,而非指針。指針,作為一種高效的工具,可謂是一把雙刃劍——用得好,可以大大提高程序效率,但用的不好,就是很多bug的滋生地。
這或許也是人們對指針褒貶不一的原因吧。就我個人而言,我還是很喜歡這個特性,因為我需要經常和硬件以及一些底層的軟件打交道。這個時候,指針便體現出它獨特的魅力。指針的知識很多,有一本經典的書叫《C和指針》,如果有興趣可以讀一讀。這里,我主要總結一些如何去解讀指針(說實話這個東西實在是很容易讓人困惑)的方法,一方面給自己做查詢用,另一方面,希望可以給別人一些幫助。
一,基本概念
關于指針的基本概念,我就不詳細介紹了,因為有許多書都介紹的很詳細。這里我只介紹一部分。指針指向一個地址,而指針本身在大多數系統上都是一個無符號整數(在32bit機上是4byte,在64bit機上是8byte)。下面用一個例子來說明其機制:
在上面的例子中,先定義了一個指針p,它的類型是int,也就是說它只能指向一個int型的變量,而不能指向其他類型的變量。最后我們將a變量的地址賦給p。在這個過程中,涉及到兩個內存塊,一個是存放指針p的內存(用&p可得到內存地址),一個是存放a的值的內存塊(用&a可以得到內存地址)。而第一個內存存的p的值經過賦值語句后也就是&a的值了。另外一個注意點是, *(星號)和變量類型以及變量名之間可以有任意個空格,也可以沒有。比如下面三種方式都是一樣的:
int a= 10;
int *p;    //聲明一個指針,但未初始化,此時為野指針
p = &a;    //a變量的地址賦給指針p
在上面的例子中,先定義了一個指針p,它的類型是int,也就是說它只能指向一個int型的變量,而不能指向其他類型的變量。最后我們將a變量的地址賦給p。在這個過程中,涉及到兩個內存塊,一個是存放指針p的內存(用&p可得到內存地址),一個是存放a的值的內存塊(用&a可以得到內存地址)。而第一個內存存的p的值經過賦值語句后也就是&a的值了。另外一個注意點是, *(星號)和變量類型以及變量名之間可以有任意個空格,也可以沒有。比如下面三種方式都是一樣的:
int* a;
int * a;
int *a;
解讀方法:
首先從標示符開始閱讀,然后往右讀,每遇到圓括號的右半邊就調轉閱讀方向。重復這個過程直到整個聲明解析完畢。需要注意的是,已經讀過的部分在后續作為一個整體來看。
看下面一個例子:
int *a[3];
//首先a右邊是[],說明a是一個具有3個元素的數組
//右邊讀完,則讀左邊。a左邊是int*,說明a的元素是int類型的指針
int (*a)[3]
//首先,a右邊是圓括號的右半邊,轉向,左邊是一個*,說明a是一個指針
//遇到括號,再轉向,是一個[],說明a是一個指向3個元素的數組的指針
//左邊是int,說明元素類型是int
//所以,a是一個指向具有3個整型元素的數組的指針
int (*func)(int p);
//相同的方法,func首先是一個指針
//然后右邊是一個括號,說明(func)是個函數,而func是指向這個函數的指針
//這個函數具有int類型的參數,返回值類型為int
int (*func[3])(int p);
//同理,func首先是一個具有3個元素的數組
//其次,func左邊是一個*,說明func數組的元素是指針。要注意修飾的是func[3],而不是func。因為已經讀過的部分在后面都作為一個整體來對待
//跳出第一個圓括號,右邊又是一個圓括號,說明func數組的元素是函數類型的指針。這個函數具有int類型的參數和int型返回值
二,數組首地址a&a&a[0]
注:a,&a,&a[0]的含義雖然不同,但是他們三個的值是相等的!
以int a[3]為例說明:
1.  a作為右值時,代表數組首元素的首地址,而非數組地址。 也就是a[0]的地址。int i = (a+1),這里a是右值,所以代表首元素的首地址,a+1代表下一個元素的首地址,即&a[1]。
2.  a是整個數組的名字。所以sizeof(a)的值為sizeof(int) * 3 = 40,代表整個數組的大小。
3.  &a即為取a的首地址,也即整個數組的首地址。所以sizeof(&a) = 4。 int p = (int)(&a+1)中的&a+1代表下一個數組的首地址,顯然是越界的。
4.  &a[0]代表首元素的首地址。 所以sizeof(&a[0]) = 4。
5.  &a[3],很顯然數組越界了,但它的sizeof是多少呢? 也是4,因為關鍵字sizeof求值是在編譯的時候,雖然并不存在a[3]這個元素,但是這里并沒有真正訪問a[3],而是根據數組元素類型來確定其值的。所以sizeof(a[3])不會出錯。
6.  a[-1]代表什么意思?首先要明白下標的形式被編譯器解析成指針的形式,即a[1]被解析成(a+1)。那么,a[-1]被解析成*(a-1)。
關于數組首元素的首地址和數組的首地址的區別:其實,數組首元素的首地址和數組首地址的值是相同的,即&a[0]和a(以及&a)是相等的,但是而這含義不一樣。首元素的首地址加1后,是第二個元素的首地址(之所以一直說首地址,是因為有的類型存儲時會占多個地址),但數組的首地址加1后是“下一個數組的地址”,這里的下一個數組只是為了說明加1時加了整個數組的大小,而不是一個元素的大小。
有一點比較容易混淆:a雖然代表整個數組,但(a+1)卻代表下一個元素的首地址,即和(&a[0]+1)一樣,下一個數組的形式為:(&a+1)。 下面以一個程序來說明:
#include
int main()
{
    int a[3]= {1, 2,3};
    printf("%ld\n",sizeof(long unsigned int));
    printf("*(a+1)=%d\n",*(a+1));
    printf("sizeof(a)=%ld\n",sizeof(a));
    printf("sizeof(&a[3])=%ld\n",sizeof(&a[3]));
    printf("a[-1]=%d\t*(a-1)=%d\n",a[-1],*(a-1));
    printf("a=%p\t&a=%p\t&a[0]=%p\n",a,&a,&a[0]);
    printf("a=%p\t(a+1)=%p\t(&a+1)=%p\n",a,(a+1),(&a+1));
    return 0;
}
輸出結果:
8
*(a+1)=2
sizeof(a)=12
sizeof(&a[3])=8
a[-1]=0 *(a-1)=0
a=0x7fffcb4cb980        &a=0x7fffcb4cb980      &a[0]=0x7fffcb4cb980
a=0x7fffcb4cb980        (a+1)=0x7fffcb4cb984    (&a+1)=0x7fffcb4cb98c
說明(下面的行數只計算main函數內有代碼的行):
1.  程序第1行定義了一個具有3個元素的整型數組。
2.  第2行打印了long型的大小。因為我是64bit的,所以一個long是8byte。
3.  第3行打印了*(a+1)的值,結果和a[1]的值相等。說明a雖然代表整個數組,但作為右值時,的確代表首元素的首地址。
4.  第4行輸出值為12,是整個數組的大小。
5.  第5行打印了一個出界元素的大小,沒有報錯,驗證了上面第5條。
6.  第6行打印了a[-1]和*(a-1),輸出值相等。驗證了上面第6條。
7.  第7行打印了a和&a[0],值相等。說明數組的首地址和首元素的首地址是相等的。
8.  第8行打印了a,(a+1),(&a+1),由結果就可以看出首元素的首地址加1是加了一個數組元素的大小,而數組首地址加1是加了一個數組的大小。
三,指針數組和數組指針
指針數組: 首先它是一個數組,數組的元素是指針,也成為“存儲指針的數組”。
數組指針: 首先它是一個指針,它指向一個數組,也可以理解為“數組的指針”。 也可以利用前面的“解讀方法”去分析。
四,函數指針和指針函數
函數指針: 指向函數的指針變量。
指針函數: 帶指針的函數,也就是返回指針的函數。
char* fun(char*a, char*b)  //定義為指針函數
{
...
...
}
int main()
{
    char* (*p)(char* p1,char*p2);//定義函數指針
    p= &fun;//把函數地址賦給它
    //p = fun; //這樣寫也行
    (*p)("aa", "bb");//使用函數指針
  return 0;
}
五,指針常量和常量指針
const char*p1;    //常量指針,指向常量的指針
char const* p2;    //同上
char* const p3;    //指針常量,指針是常量
怎么記?
1.  可以先把類型名去掉,然后看const離誰近,就修飾誰。
2.  也可以const在*左邊的為常量指針,const在*右邊的為指針常量。
三~五的萬能鑰匙
其實,關于“指針數組與數組指針、函數指針與指針函數、指針常量與常量指針”的判斷,有一個萬能鑰匙。那就是根據我們強大的中文語法:前邊是修飾詞,后邊才是主語。比如“指針數組”,前面的指針只是修飾詞,后面的數組才是主語,所以它是一個數組。
六,野指針
野指針指沒有確定指向的指針。造成野指針的情況有:
1. 指針變量創建但沒有初始化。
2. 指針p被free或者delete之后,沒有置為NULL。

本文地址:http://m.qingdxww.cn/thread-587314-1-1.html     【打印本頁】

本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
您需要登錄后才可以發表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區
  • 利用SAM E54 Xplained Pro評估工具包演示CAN轉USB橋接器以及基于CAN的主機和自舉程序應用程序
  • 使用SAM-IoT Wx v2開發板演示AWS IoT Core應用程序
  • 使用Harmony3加速TCP/IP應用的開發培訓教程
  • 集成高級模擬外設的PIC18F-Q71家族介紹培訓教程
  • 貿澤電子(Mouser)專區
關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日本一区二区在线不卡 | 久久福利免费视频 | 视频一区二区三区在线 | 欧洲成人爽视频在线观看 | 97国产成人精品视频 | 超91在线| 日韩视频在线观看一区 | 久久婷婷久久一区二区三区 | 无人视频免费观看免费视频 | 天天摸天天操天天干 | 日本特交大片免费观看 | 日本免费黄网 | 最近免费观看高清韩国日本大全 | 国产91导航 | 视频麻豆 | 欧美三级不卡在线观线看高清 | 国产麻豆精品一区二区 | 高清欧美一区二区三区 | 精品一区二区三区在线成人 | 精品欧美一区二区三区在线观看 | 欧日韩在线不卡视频 | 日本亚洲高清乱码中文在线观看 | 在线观看国产一区 | 精品久久久久久国产牛牛app | 99精品热 | 四虎www成人影院观看 | 国产一级黄色大片 | 5252av| 欧美夜夜操| 成人国产三级在线播放 | 99精品在线观看视频 | 91视频黄版| 欧美在线视频网站 | 福利国模私拍视频在线观看 | 欧美激情精品久久久久久久 | 国内精品免费麻豆网站91麻豆 | 四虎精品免费永久在线 | 天天爱天天做色综合 | 欧美日韩不卡视频 | 日韩欧美在线免费观看 | ww亚洲ww在线观看国产 |