精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳解C語言指針底層基本原理

嵌入式開發愛好者 ? 來源:嵌入式開發愛好者 ? 2023-04-06 10:43 ? 次閱讀

說到指針,估計還是有很多小伙伴都還是云里霧里的,有點“知其然,而不知其所以然”。但是,不得不說,學了指針,C語言才能算是入門了。指針是C語言的「精華」,可以說,對對指針的掌握程度,「直接決定」了你C語言的編程能力。

在講指針之前,我們先來了解下變量在「內存」中是如何存放的。

在程序中定義一個變量,那么在程序編譯的過程中,系統會根據你定義變量的類型來分配「相應尺寸」的內存空間。那么如果要使用這個變量,只需要用變量名去訪問即可。

通過變量名來訪問變量,是一種「相對安全」的方式。因為只有你定義了它,你才能夠訪問相應的變量。這就是對內存的基本認知。但是,如果光知道這一點的話,其實你還是不知道內存是如何存放變量的,因為底層是如何工作的,你依舊不清楚。

那么如果要繼續深究的話,你就需要把變量在內存中真正的樣子是什么搞清楚。內存的最小索引單元是1字節,那么你其實可以把內存比作一個超級大的「字符型數組」。在上一節我們講過,數組是有下標的,我們是通過數組名和下標來訪問數組中的元素。那么內存也是一樣,只不過我們給它起了個新名字:地址。每個地址可以存放「1字節」的數據,所以如果我們需要定義一個整型變量,就需要占據4個內存單元。

那么,看到這里你可能就明白了:其實在程序運行的過程中,完全不需要變量名的參與。變量名只是方便我們進行代碼的編寫和閱讀,只有程序員和編譯器知道這個東西的存在。而編譯器還知道具體的變量名對應的「內存地址」,這個是我們不知道的,因此編譯器就像一個橋梁。當讀取某一個變量的時候,編譯器就會找到變量名所對應的地址,讀取對應的值。

初識指針和指針變量

那么我們現在就來切入正題,指針是個什么東西呢?

所謂指針,就是內存地址(下文簡稱地址)。C語言中設立了專門的「指針變量」來存儲指針,和「普通變量」不一樣的是,指針變量存儲的是「地址」

定義指針

指針變量也有類型,實際上取決于地址指向的值的類型。那么如何定義指針變量呢:

很簡單:類型名* 指針變量名

char*pa;//定義一個字符變量的指針,名稱為pa
int*pb;//定義一個整型變量的指針,名稱為pb
float*pc;//定義一個浮點型變量的指針,名稱為pc

注意,指針變量一定要和指向的變量的類型一樣,不然類型不同可能在內存中所占的位置不同,如果定義錯了就可能導致出錯。

取地址運算符和取值運算符

獲取某個變量的地址,使用取地址運算符&,如:

char*pa=&a;
int*pb=&f;

如果反過來,你要訪問指針變量指向的數據,那么你就要使用取值運算符*,如:

printf("%c,%d ",*pa,*pb);

這里你可能發現,定義指針的時候也使用了*,這里屬于符號的「重用」,也就是說這種符號在不同的地方就有不同的用意:在定義的時候表示「定義一個指針變量」,在其他的時候則用來「獲取指針變量指向的變量的值」

直接通過變量名來訪問變量的值稱之為直接訪問,通過指針這樣的形式訪問稱之為間接訪問,因此取值運算符有時候也成為「間接運算符」。

比如:

//Example01
//代碼來源于網絡,非個人原創
#include
intmain(void)
{
chara='f';
intf=123;
char*pa=&a;
int*pf=&f;

printf("a=%c ",*pa);
printf("f=%d ",*pf);

*pa='c';
*pf+=1;

printf("now,a=%c ",*pa);
printf("now,f=%d ",*pf);

printf("sizeofpa=%d ",sizeof(pa));
printf("sizeofpf=%d ",sizeof(pf));

printf("theaddrofais:%p ",pa);
printf("theaddroffis:%p ",pf);

return0;
}

程序實現如下:

//Consequence 01
a = f
f = 123
now, a = c
now, f = 124
sizeof pa = 4
sizeof pf = 4
the addr of a is: 00EFF97F
the addr of f is: 00EFF970

避免訪問未初始化的指針

voidf()
{
int*a;
*a=10;
}

像這樣的代碼是十分危險的。因為指針a到底指向哪里,我們不知道。就和訪問未初始化的普通變量一樣,會返回一個「隨機值」。

但是如果是在指針里面,那么就有可能覆蓋到「其他的內存區域」,甚至可能是系統正在使用的「關鍵區域」,十分危險。不過這種情況,系統一般會駁回程序的運行,此時程序會被「中止」「報錯」

要是萬一中獎的話,覆蓋到一個合法的地址,那么接下來的賦值就會導致一些有用的數據被「莫名其妙地修改」,這樣的bug是十分不好排查的,因此使用指針的時候一定要注意初始化。

指針和數組

有些讀者可能會有些奇怪,指針和數組又有什么關系?這倆貨明明八竿子打不著井水不犯河水。別著急,接著往下看,你的觀點有可能會改變。

數組的地址

我們剛剛說了,指針實際上就是變量在「內存中的地址」,那么如果有細心的小伙伴就可能會想到,像數組這樣的一大摞變量的集合,它的地址是啥呢?

我們知道,從標準輸入流中讀取一個值到變量中,用的是scanf函數,一般貌似在后面都要加上&,這個其實就是我們剛剛說的「取地址運算符」。如果你存儲的位置是指針變量的話,那就不需要。

//Example02
intmain(void)
{
inta;
int*p=&a;

printf("請輸入一個整數:");
scanf("%d",&a);//此處需要&
printf("a=%d ",a);

printf("請再輸入一個整數:");
scanf("%d",p);//此處不需要&
printf("a=%d ",a);

return0;
}

程序運行如下:

//Consequence 02
請輸入一個整數:1
a = 1
請再輸入一個整數:2
a = 2

在普通變量讀取的時候,程序需要知道這個變量在內存中的地址,因此需要&來取地址完成這個任務。而對于指針變量來說,本身就是「另外一個」普通變量的「地址信息,因此直接給出指針的值就可以了。

試想一下,我們在使用scanf函數的時候,是不是也有不需要使用&的時候?就是在讀取「字符串」的時候:

//Example03
#include
intmain(void)
{
charurl[100];
url[99]='?';
printf("請輸入TechZone的域名:");
scanf("%s",url);//此處也不用&
printf("你輸入的域名是:%s ",url);
return0;
}

程序執行如下:

//Consequence 03
請輸入TechZone的域名:www.techzone.ltd
你輸入的域名是:www.techzone.ltd

因此很好推理:數組名其實就是一個「地址信息」,實際上就是數組「第一個元素的地址」

咱們試試把第一個元素的地址和數組的地址做個對比就知道了:

//Example03V2
#include
intmain(void)
{
charurl[100];
printf("請輸入TechZone的域名:");
url[99]='?';
scanf("%s",url);
printf("你輸入的域名是:%s ",url);

printf("url的地址為:%p ",url);
printf("url[0]的地址為:%p ",&url[0]);

if(url==&url[0])
{
printf("兩者一致!");
}
else
{
printf("兩者不一致!");
}
return0;
}

程序運行結果為:

//Comsequense 03 V2
請輸入TechZone的域名:www.techzone.ltd
你輸入的域名是:www.techzone.ltd
url的地址為:0063F804
url[0]的地址為:0063F804
兩者一致!

這么看,應該是實錘了。那么數組后面的元素也就是依次往后放置,有興趣的也可以自己寫代碼嘗試把它們輸出看看。

指向數組的指針

剛剛我們驗證了數組的地址就是數組第一個元素的地址。那么指向數組的指針自然也就有兩種定義的方法:

...
char*p;
//方法1
p=a;
//方法2
p=&a[0];

指針的運算

當指針指向數組元素的時候,可以對指針變量進行「加減」運算,+n表示指向p指針所指向的元素的「下n個元素」,-n表示指向p指針所指向的元素的「上n個元素」。并不是將地址加1。

如:

//Example04
#include
intmain(void)
{
inta[]={1,2,3,4,5};
int*p=a;
printf("*p=%d,*(p+1)=%d,*(p+2)=%d ",*p,*(p+1),*(p+2));
printf("*p->%p,*(p+1)->%p,*(p+2)->%p ",p,p+1,p+2);
return0;
}

執行結果如下:

//Consequence 04
*p = 1, *(p+1) = 2, *(p+2) = 3
*p -> 00AFF838, *(p+1) -> 00AFF83C, *(p+2) -> 00AFF840

有的小伙伴可能會想,編譯器是怎么知道訪問下一個元素而不是地址直接加1呢?

其實就在我們定義指針變量的時候,就已經告訴編譯器了。如果我們定義的是整型數組的指針,那么指針加1,實際上就是加上一個sizeof(int)的距離。相對于標準的下標訪問,使用指針來間接訪問數組元素的方法叫做指針法。

其實使用指針法來訪問數組的元素,不一定需要定義一個指向數組的單獨的指針變量,因為數組名自身就是指向數組「第一個元素」的指針,因此指針法可以直接作用于數組名:

...
printf("p->%p,p+1->%p,p+2->%p ",a,a+1,a+2);
printf("a=%d,a+1=%d,a+2=%d",*a,*(a+1),*(a+2));
...

執行結果如下:

p->00AFF838,p+1->00AFF83C,p+2->00AFF840
b=1,b+1=2,b+2=3

現在你是不是感覺,數組和指針有點像了呢?不過筆者先提醒,數組和指針雖然非常像,但是絕對「不是」一種東西。

甚至你還可以直接用指針來定義字符串,然后用下標法來讀取每一個元素:

//Example05
//代碼來源于網絡
#include
#include
intmain(void)
{
char*str="IloveTechZone!";
inti,length;

length=strlen(str);

for(i=0;i {
printf("%c",str[i]);
}
printf(" ");

return0;
}

程序運行如下:

//Consequence 05
I love TechZone!

在剛剛的代碼里面,我們定義了一個「字符指針」變量,并且初始化成指向一個字符串。后來的操作,不僅在它身上可以使用「字符串處理函數」,還可以用「下標法」訪問字符串中的每一個字符。

當然,循環部分這樣寫也是沒毛病的:

...
for(i=0,i {
printf("%c",*(str+i));
}

這就相當于利用了指針法來讀取。

指針和數組的區別

剛剛說了許多指針和數組相互替換的例子,可能有的小伙伴又開始說:“這倆貨不就是一個東西嗎?”

隨著你對指針和數組越來越了解,你會發現,C語言的創始人不會這么無聊去創建兩種一樣的東西,還叫上不同的名字。指針和數組終究是「不一樣」的。

比如筆者之前看過的一個例子:

//Example06
//代碼來源于網絡
#include
intmain(void)
{
charstr[]="IloveTechZone!";
intcount=0;

while(*str++!='?')
{
count++;
}
printf("總共有%d個字符。 ",count);

return0;
}

當編譯器報錯的時候,你可能會開始懷疑你學了假的C語言語法:

//Error in Example 06
錯誤(活動)E0137表達式必須是可修改的左值
錯誤C2105“++”需要左值

我們知道,*str++ != ‘?’是一個復合表達式,那么就要遵循「運算符優先級」來看。具體可以回顧《C語言運算符優先級及ASCII對照表》。

str++比*str的優先級「更高」,但是自增運算符要在「下一條語句」的時候才能生效。所以這個語句的理解就是,先取出str所指向的值,判斷是否為?,若是,則跳出循環,然后str指向下一個字符的位置。

看上去貌似沒啥毛病,但是,看看編譯器告訴我們的東西:表達式必須是可修改的左值

++的操作對象是str,那么str到底是不是「左值」呢?

如果是左值的話,那么就必須滿足左值的條件。

?

擁有用于識別和定位一個存儲位置的標識符

存儲值可修改

?

第一點,數組名str是可以滿足的,因為數組名實際上就是定位數組第一個元素的位置。但是第二點就不滿足了,數組名實際上是一個地址,地址是「不可以」修改的,它是一個常量。如果非要利用上面的思路來實現的話,可以將代碼改成這樣:

//Example06V2
//代碼來源于網絡
#include
intmain(void)
{
charstr[]="IloveTechZone!";
char*target=str;
intcount=0;

while(*target++!='?')
{
count++;
}
printf("總共有%d個字符。 ",count);

return0;
}

這樣就可以正常執行了:

//Consequence 06 V2
總共有16個字符。

這樣我們就可以得出:數組名只是一個「地址」,而指針是一個「左值」。

指針數組?數組指針?

看下面的例子,你能分辨出哪個是指針數組,哪個是數組指針嗎?

int*p1[5];
int(*p2)[5];

單個的我們都可以判斷,但是組合起來就有些難度了。

答案:

int*p1[5];//指針數組
int(*p2)[5];//數組指針

我們挨個來分析。

指針數組

數組下標[]的優先級是最高的,因此p1是一個有5個元素的「數組」。那么這個數組的類型是什么呢?答案就是int*,是「指向整型變量的指針」。因此這是一個「指針數組」。

那么這樣的數組應該怎么樣去初始化呢?

你可以定義5個變量,然后挨個取地址來初始化。

不過這樣太繁瑣了,但是,并不是說指針數組就沒什么用。

比如:

//Example07
#include
intmain(void)
{
char*p1[5]={
"人生苦短,我用Python。",
"PHP是世界上最好的語言!",
"Onemorething...",
"一個好的程序員應該是那種過單行線都要往兩邊看的人。",
"C語言很容易讓你犯錯誤;C++看起來好一些,但當你用它時,你會發現會死的更慘。"
};
inti;
for(i=0;i {
printf("%s ",p1[i]);
}
return0;
}

結果如下:

//Consequence 07
人生苦短,我用Python。
PHP是世界上最好的語言!
One more thing...
一個好的程序員應該是那種過單行線都要往兩邊看的人。
C語言很容易讓你犯錯誤;C++看起來好一些,但當你用它時,你會發現會死的更慘。

這樣是不是比二維數組來的更加直接更加通俗呢?

數組指針

()和[]在優先級里面屬于「同級」,那么就按照「先后順序」進行。

int(*p2)將p2定義為「指針」, 后面跟隨著一個5個元素的「數組」,p2就指向這個數組。因此,數組指針是一個「指針」,它指向的是一個數組。

但是,如果想對數組指針初始化的時候,千萬要小心,比如:

//Example08
#include
intmain(void)
{
int(*p2)[5]={1,2,3,4,5};
inti;
for(i=0;i {
printf("%d ",*(p2+i));
}
return0;
}

Visual Studio 2019報出以下的錯誤:

//Error and Warning in Example 08
錯誤(活動)E0146初始值設定項值太多
錯誤C2440“初始化”: 無法從“initializer list”轉換為“int (*)[5]”
警告C4477“printf”: 格式字符串“%d”需要類型“int”的參數,但可變參數 1 擁有了類型“int *”

這其實是一個非常典型的錯誤使用指針的案例,編譯器提示說這里有一個「整數」賦值給「指針變量」的問題,因為p2歸根結底還是指針,所以應該給它傳遞一個「地址」才行,更改一下:

//Example08V2
#include
intmain(void)
{
inttemp[5]={1,2,3,4,5};
int(*p2)[5]=temp;
inti;
for(i=0;i {
printf("%d ",*(p2+i));
}
return0;
} //Error and Warning in Example 08 V2
錯誤(活動)E0144"int *" 類型的值不能用于初始化 "int (*)[5]" 類型的實體
錯誤C2440“初始化”: 無法從“int [5]”轉換為“int (*)[5]”
警告C4477“printf”: 格式字符串“%d”需要類型“int”的參數,但可變參數 1 擁有了類型“int *”

可是怎么還是有問題呢?

我們回顧一下,指針是如何指向數組的。

inttemp[5]={1,2,3,4,5};
int*p=temp;

我們原本以為,指針p是指向數組的指針,但是實際上「并不是」。仔細想想就會發現,這個指針實際上是指向的數組的「第一個元素」,而不是指向數組。因為數組里面的元素在內存中都是挨著個兒存放的,因此只需要知道第一個元素的地址,就可以訪問到后面的所有元素。

但是,這么來看的話,指針p指向的就是一個「整型變量」的指針,并不是指向「數組」的指針。而剛剛我們用的數組指針,才是指向數組的指針。因此,應該將「數組的地址」傳遞給數組指針,而不是將第一個元素的地址傳入,盡管它們值相同,但是「含義」確實不一樣:

//Example08V3
//Example08V2
#include
intmain(void)
{
inttemp[5]={1,2,3,4,5};
int(*p2)[5]=&temp;//此處取地址
inti;
for(i=0;i {
printf("%d ",*(*p2+i));
}
return0;
}

程序運行如下:

//Consequence 08
1
2
3
4
5

指針和二維數組

在上一節《C語言之數組》我們講過「二維數組」的概念,并且我們也知道,C語言的二維數組其實在內存中也是「線性存放」的。

假設我們定義了:int array[4][5]

array

array作為數組的名稱,顯然應該表示的是數組的「首地址」。由于二維數組實際上就是一維數組的「線性拓展」,因此array應該就是指的指向包含5個元素的數組的指針。

如果你用sizeof()去測試array和array+1的話,就可以測試出來這樣的結論。

*(array+1)

首先從剛剛的問題我們可以得出,array+1同樣也是指的指向包含5個元素的數組的指針,因此*(array+1)就是相當于array[1],而這剛好相當于array[1][0]的數組名。因此*(array+1)就是指第二行子數組的第一個元素的地址。

*(*(array+1)+2)

有了剛剛的結論,我們就不難推理出,這個實際上就是array[1][2]。是不是感覺非常簡單呢?

總結一下,就是下面的這些結論,記住就好,理解那當然更好:

*(array+i)==array[i]
*(*(array+i)+j)==array[i][j]
*(*(*(array+i)+j)+k)==array[i][j][k]
...

數組指針和二維數組

我們在上一節里面講過,在初始化二維數組的時候是可以偷懶的:

intarray[][3]={
{1,2,3},
{4,5,6}
};

剛剛我們又說過,定義一個數組指針是這樣的:

int(*p)[3];

那么組合起來是什么意思呢?

int(*p)[3]=array;

通過剛剛的說明,我們可以知道,array是指向一個3個元素的數組的「指針」,所以這里完全可以將array的值賦值給p。

其實C語言的指針非常靈活,同樣的代碼用不同的角度去解讀,就可以有不同的應用。

那么如何使用指針來訪問二維數組呢?沒錯,就是使用「數組指針」

//Example09
#include
intmain(void)
{
intarray[3][4]={
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
int(*p)[4];
inti,j;
p=array;
for(i=0,i {
for(j=0,j {
printf("%2d",*(*(p+i)+j));
}
printf(" ");
}
return0;
}

運行結果:

//Consequence 09
0 1 2 3
4 5 6 7
8 9 10 11

void指針

void實際上是無類型的意思。如果你嘗試用它來定義一個變量,編譯器肯定會「報錯」,因為不同類型所占用的內存有可能「不一樣」。但是如果定義的是一個指針,那就沒問題。void類型中指針可以指向「任何一個類型」的數據,也就是說,任何類型的指針都可以賦值給void指針。

將任何類型的指針轉換為void是沒有問題的。但是如果你要反過來,那就需要「強制類型轉換」。此外,不要對void指針「直接解引用」,因為編譯器其實并不知道void指針會存放什么樣的類型。

//Example10
#include
intmain(void)
{
intnum=1024;
int*pi=#
char*ps="TechZone";
void*pv;

pv=pi;
printf("pi:%p,pv:%p ",pi,pv);
printf("*pv:%d ",*pv);

pv=ps;
printf("ps:%p,pv:%p ",ps,pv);
printf("*pv:%s ",*pv);
}

這樣會報錯:

//Error in Example 10
錯誤C2100非法的間接尋址
錯誤C2100非法的間接尋址

如果一定要這么做,那么可以用「強制類型轉換」

//Example10V2
#include
intmain(void)
{
intnum=1024;
int*pi=#
char*ps="TechZone";
void*pv;

pv=pi;
printf("pi:%p,pv:%p ",pi,pv);
printf("*pv:%d ",*(int*)pv);

pv=ps;
printf("ps:%p,pv:%p ",ps,pv);
printf("*pv:%s ",pv);
}

當然,使用void指針一定要小心,由于void指針幾乎可以「通吃」所有類型,所以間接使得不同類型的指針轉換變得合法,如果代碼中存在不合理的轉換,編譯器也不會報錯。

因此,void指針能不用則不用,后面講函數的時候,還可以解鎖更多新的玩法。

NULL指針

在C語言中,如果一個指針不指向任何數據,那么就稱之為「空指針」,用「NULL」來表示。NULL其實是一個宏定義:

#defineNULL((void*)0)

在大部分的操作系統中,地址0通常是一個「不被使用」的地址,所以如果一個指針指向NULL,就意味著不指向任何東西。為什么一個指針要指向NULL呢?

其實這反而是一種比較指的推薦「編程風格」——當你暫時還不知道該指向哪兒的時候,就讓它指向NULL,以后不會有太多的麻煩,比如:

//Example11
#include
intmain(void)
{
int*p1;
int*p2=NULL;
printf("%d ",*p1);
printf("%d ",*p2);
return0;
}

第一個指針未被初始化。在有的編譯器里面,這樣未初始化的變量就會被賦予「隨機值」。這樣指針被稱為「迷途指針」,「野指針」或者「懸空指針」。如果后面的代碼對這類指針解引用,而這個地址又剛好是合法的話,那么就會產生莫名其妙的結果,甚至導致程序的崩潰。因此養成良好的習慣,在暫時不清楚的情況下使用NULL,可以節省大量的后期調試的時間。

指向指針的指針

開始套娃了。其實只要你理解了指針的概念,也就沒什么大不了的。

//Example12
#include
intmain(void)
{
intnum=1;
int*p=#
int**pp=&p;

printf("num:%d ",num);
printf("*p:%d ",*p);
printf("**p:%d ",**pp);
printf("&p:%p,pp:%p ",&p,pp);
printf("&num:%p,p:%p,*pp:%p ",&num,p,*pp);
return0;
}

程序結果如下:

//Consequence 12
num: 1
*p: 1
**p: 1
&p: 004FF960, pp: 004FF960
&num: 004FF96C, p: 004FF96C, *pp: 004FF96C

當然你也可以無限地套娃,一直指下去。不過這樣會讓代碼可讀性變得「很差」,過段時間可能你自己都看不懂你寫的代碼了。

指針數組和指向指針的指針

那么,指向指針的指針有什么用呢?

它可不是為了去創造混亂代碼,在一個經典的實例里面,就可以體會到它的用處:

char*Books[]={
"《C專家編程》",
"《C和指針》",
"《C的陷阱與缺陷》",
"《CPrimerPlus》",
"《Python基礎教程(第三版)》"
};

然后我們需要將這些書進行分類。我們發現,其中有一本是寫Python的,其他都是C語言的。這時候指向指針的指針就派上用場了。首先,我們剛剛定義了一個指針數組,也就是說,里面的所有元素的類型「都是指針」,而數組名卻又可以用指針的形式來「訪問」,因此就可以使用「指向指針的指針」來指向指針數組:

...
char**Python;
char**CLang[4];

Python=&Books[5];
CLang[0]=&Books[0];
CLang[1]=&Books[1];
CLang[2]=&Books[2];
CLang[3]=&Books[3];
...

因為字符串的取地址值實際上就是其「首地址」,也就是一個「指向字符指針的指針」,所以可以這樣賦值。

這樣,我們就利用指向指針的指針完成了對書籍的分類,這樣既避免了浪費多余的內存,而且當其中的書名要修改,只需要改一次即可,代碼的靈活性和安全性都得到了提升。

常量和指針

常量,在我們目前的認知里面,應該是這樣的:

520, 'a'

或者是這樣的:

#defineMAX1000
#defineB'b'

常量和變量最大的區別,就是前者「不能夠被修改」,后者可以。那么在C語言中,可以將變量變成像具有常量一樣的特性,利用const即可。

constintmax=1000;
constchara='a';

在const關鍵字的作用下,變量就會「失去」本來具有的可修改的特性,變成“只讀”的屬性。

指向常量的指針

強大的指針當然也是可以指向被const修飾過的變量,但這就意味著「不能通過」指針來修改它所引用的值??偨Y一下,就是以下4點:

指針可以修改為指向不同的變量

指針可以修改為指向不同的常量

可以通過解引用來讀取指針指向的數據

不可以通過解引用來修改指針指向的數據

常量指針

指向非常量的常量指針

指針本身作為一種「變量」,也是可以修改的。因此,指針也是可以被const修飾的,只不過位置稍稍「發生了點變化」

...
int*constp=#
...

這樣的指針有如下的特性:

指針自身不能夠被修改

指針指向的值可以被修改

指向常量的常量指針

在定義普通變量的時候也用const修飾,就得到了這樣的指針。不過由于限制太多,一般很少用到:

...
intnum=100;
constintcnum=200;
constint*constp=&cnum;
...

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    2902

    瀏覽量

    73533
  • C語言
    +關注

    關注

    180

    文章

    7576

    瀏覽量

    133998
  • 數組
    +關注

    關注

    1

    文章

    411

    瀏覽量

    25821
  • 運算符
    +關注

    關注

    0

    文章

    166

    瀏覽量

    11013
  • 指針變量
    +關注

    關注

    0

    文章

    17

    瀏覽量

    7217

原文標題:詳解 C 語言指針底層基本原理

文章出處:【微信號:嵌入式開發愛好者,微信公眾號:嵌入式開發愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    擴頻通信的基本原理

    附件非常詳解的介紹了擴頻通信的基本原理,本人做通信快3年了,是我見過的介紹擴頻通信最好的資料,分享一下!
    發表于 11-15 10:57

    C語言指針詳解

    ];//指針的類型是 int(*)[3] (5)int*(*ptr)[4];//指針的類型是int*(*)[4] 怎么樣?找出指針的類型的方法是不是很簡單? 完整的C
    發表于 07-04 03:34

    C指針詳解

    我想對很多學習C語言的新手來說,指針無疑是一個難點。但是,我覺得指針也是C語言特別重要的一個特性
    發表于 12-29 07:20

    c語言指針詳解

    1.指針簡介 指針C語言中廣泛使用的一種數據類型。 運用指針編程是C
    發表于 03-26 09:51

    C語言指針電子教程

    本資料是一份不錯的關于C語言指針的電子教程,希望對大家有所幫助... 指針簡介 指針C
    發表于 07-30 16:00 ?77次下載

    C語言指針函數和函數指針詳細介紹

    C語言指針函數和函數指針詳細介紹。。。。。。。
    發表于 03-04 15:27 ?5次下載

    徹底搞定C語言指針詳解完整版

    徹底搞定C語言指針詳解完整版。
    發表于 05-10 17:04 ?0次下載

    C指針詳解-經典-非常詳細

    C指針詳解-經典-非常詳細
    發表于 10-23 17:39 ?79次下載
    <b class='flag-5'>C</b><b class='flag-5'>指針</b><b class='flag-5'>詳解</b>-經典-非常詳細

    c語言函數指針定義,指針函數和函數指針的區別

     往往,我們一提到指針函數和函數指針的時候,就有很多人弄不懂。下面就由小編詳細為大家介紹C語言中函數指針,
    發表于 11-16 15:18 ?3551次閱讀

    C語言的精髓——指針詳解

    C語言的精髓——指針詳解
    發表于 11-30 14:43 ?17次下載

    為什么C語言要引入指針_引入指針的好處是什么

    讓你知道什么是 C語言 指針,為什么用指針,從此不在害怕指針。
    的頭像 發表于 07-28 10:12 ?2.2w次閱讀

    從最底層的內存存儲空間開始帶你了解C語言指針

    一、前言 二、變量與指針的本質 三、指針的幾個相關概念 四、指向不同數據類型的指針 五、總結 一、前言 如果問C語言中最重要、威力最大的概念
    的頭像 發表于 02-02 10:40 ?2349次閱讀
    從最<b class='flag-5'>底層</b>的內存存儲空間開始帶你了解<b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>指針</b>

    C語言進階】C語言指針的高階用法

    C語言進階】C語言指針的高階用法
    的頭像 發表于 08-31 13:24 ?2146次閱讀

    底層解析C指針(一)

    指針C語言中的精髓部分,同樣也是C語言的難點所在,下面從最底層來分析
    的頭像 發表于 02-15 14:47 ?728次閱讀
    <b class='flag-5'>底層</b>解析<b class='flag-5'>C</b><b class='flag-5'>指針</b>(一)

    c語言指針用法詳解:如何使用指針變量做函數參數

    指針C語言中一個比較重要的東西,有人說指針C語言的靈魂這句話說的一點也沒錯。 正確靈活地運用
    發表于 09-21 12:32 ?977次閱讀
    <b class='flag-5'>c</b><b class='flag-5'>語言</b><b class='flag-5'>指針</b>用法<b class='flag-5'>詳解</b>:如何使用<b class='flag-5'>指針</b>變量做函數參數