常量指針與指針常量的區別(轉帖)

轉載:http://www.cnblogs.com/witty/archive/2012/04/06/2435311.html

三個名詞雖然非常繞嘴,不過說的非常準確。用中國話的語義分析就可以很方便地把三個概念區分開。

一) 常量指針。

常量是形容詞,指針是名詞,以指針為中心的一個偏正結構短語。這樣看,常量指針本質是指針,常量修飾它,表示這個指針乃是一個指向常量的指針(變量)。

指針指向的對象是常量,那么這個對象不能被更改。

在C/C++中,常量指針是這樣聲明的:

1)const int *p;

2)int const *p;

常量指針的使用要注意,指針指向的對象不能通過這個指針來修改,可是仍然可以通過原來的聲明修改,也就是說常量指針可以被賦值為變量的地址,之所以叫做常量指針,是限制了通過這個指針修改變量的值。例如:

int a = 5;

const int b = 8;

? const int *c = &a; // 這是合法的,非法的是對c的使用

*c = 6; // 非法,但可以這樣修改c指向的對象的值:a = 6;

const int *d = &b; // b是常量,d可以指向b,d被賦值為b的地址是合法的

? 細心的朋友在使用字符串處理函數的時候,應該會注意到這些函數的聲明。它們的參數一般聲明為常量指針。例如,字符串比較函數的聲明是這樣的:

int strcmp(const char *str1, const char *str2);

可是這個函數卻可以接收非常量字符串。例如這段程序:

char *str1, *str2;

str1 = "abcde1234";

str2 = "bcde";

if(strcmp(str1, str2) == 0)

{

printf("str1 equals str2.");

}

str1和str2的內容顯然是可以更改的,例如可以使用“str1[0] = x;”這樣的語句把str1的內容由“abcde1234”變為“xbcde1234”。因為函數的參數聲明用了常量指針的形式,就保證了在函數內部,那 個常量不被更改。也就是說,對str1和str2的內容更改的操作在函數內部是不被允許的。(就目前的應用來看,我覺得設置常量指針就是為函數參數聲明準 備的,不然還真不知道用在什么地方呢,呵呵!)

雖然常量指針指向的對象不能變化,可是因為常量指針是一個變量,因此,常量指針可以不被賦初始值,且可以被重新賦值。例如:

const int a = 12;

const int b = 15;

const int *c = &a; // 為了簡化代碼,很多人習慣賦初始值

const int *d;

d = &a; // 這樣當然是可以的

c = &b; // 雖然c已經被賦予初始值,可是仍然可以指向另一個變量

特點是,const的位置在指針聲明運算符*的左側。只要const位于*的左側,無論它在類型名的左邊或右邊,都聲明了一個指向常量的指針,叫做常量指針。

可以這么想,*左側是常量,指針指向的對象是常量。

二) 指針常量

指針是形容詞,常量是名詞。這回是以常量為中心的一個偏正結構短語。那么,指針常量的本質是一個常量,而用指針修飾它,那么說明這個常量的值應該是一個指針。

指針常量的值是指針,這個值因為是常量,所以不能被賦值。

在C/C++中,指針常量這樣聲明:

int a;

int *const b = &a; //const放在指針聲明操作符的右側

只要const位于指針聲明操作符右側,就表明聲明的對象是一個常量,且它的內容是一個指針,也就是一個地址。上面的聲明可以這么讀,聲明了一個常量b,它的值是變量a的地址(變量a的地址,不就是指向變量a的指針嗎)。

因為指針常量是一個常量,在聲明的時候一定要給它賦初始值。一旦賦值,以后這個常量再也不能指向別的地址。

雖然指針常量的值不能變,可是它指向的對象是可變的,因為我們并沒有限制它指向的對象是常量。

因此,有這么段程序:

char *a = "abcde1234";

char *b = "bcde";

char *const c = &a;

? 下面的操作是可以的。

? a[0] = 'x'; // 我們并沒有限制a為常量指針(指向常量的指針)

或者

*c[0] = 'x' // 與上面的操作一致

三)指向常量的指針常量

顧名思議,指向常量的指針常量就是一個常量,且它指向的對象也是一個常量。

因為是一個指針常量,那么它指向的對象當然是一個指針對象,而它又指向常量,說明它指向的對象不能變化。

在C/C++中,這么聲明:

? const int a = 25;

const int * const b = &a;

看,指針聲明操作符左邊有一個const,說明聲明的是一個指向常量的指針。再看,指針聲明操作符右邊有一個const,說明聲明的是一個指針常量。前后都鎖死了,那么指向的對象不能變,指針常量本身也不能變。細細體味,相信能得其道,下面就不贅述了。

用一個例子作為總結。雖然字符指針與其它指針的本質是一樣的,可是因為字符指針常用來表示字符串,常不好理解。下面就用字符指針來舉例。

char *a = "abcde1234";

const char *b = "bcde"; // b是指向常量字符串的指針變量

char *const c = &a;? // c是指向字符指針變量的常量

const char *const d = &b; // d是指向字符常量的指針常量

問題來了。

1)問:因為a是變量,a可以賦值為其它值,如"12345abc"。那么c指向a,當a變化了,c指向什么呢?

答:仍然指向"abcde1234"。雖然a可以指向別的字符串,可是c仍然指向"abcde1234",也就是a開始指向的對象。

2)問:a是變量,可以改變a的內容。那么當執行了“a[0] = 'x';”后,c會怎樣呢?

答:c當然還指向a初始指向的字符。不過,這個字符已經變成了'x'。

3)問:b是指向常量的指針變量,當b指向別的字符串,d怎么樣?

答:d仍然指向b初始的字符串。

4)問:b可以變化,b指向的字符不能變化,也就是說b[0]不能被重新賦值,可是b[1]可以被重新賦值嗎?

答:原則上b指向的字符是常量,并沒有限制下一個字符,應該可以被賦值。可是因為你使用字符串進行了初始賦值,而且編譯器是靜態編譯的,C/C++程序就把b當作字符串指針來處理了,因此,當對下一個字符進行賦值時,編譯不能通過。

其他問題,歡迎補充。

我編了這樣的口訣,記住,應該不難:

const(*號)左邊放,我是指針變量指向常量;

const(*號)右邊放,我是指針常量指向變量;

const(*號)兩邊放,我是指針常量指向常量;

指針變量能改指向,指針常量不能轉向!

要是全都變成常量,鎖死了,我不能轉向,你也甭想變樣!


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

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

相關文章

c/c++錯題總結

1.類名 對象名 默認調用“對象名()”這個構造函數,在棧內存中存在對象名,在堆內存中存在實際對象; 2.類名 對象名(一個或以上個參數) 默認調用相應的構造函數,在棧內存中存在對象名,在堆內存中也是存在實際對象的&a…

智能指針學習筆記

轉載:http://www.cnblogs.com/wuchanming/p/4411878.html 1. 介紹 本文介紹智能指針的使用。智能指針是c 中管理資源的一種方式,用智能指針管理資源,不必擔心資源泄露,將c 程序員 從指針和內存管理中解脫出來,再者&…

c++程序編譯過程

c程序編譯分成四個過程:編譯預處理,編譯,匯編,鏈接 編譯預處理:處理以#為開頭 編譯:將.cpp文件翻譯成.s匯編文件 匯編:將.s匯編文件翻譯成機器指令.o文件 鏈接:匯編生產的目標文件.o…

仿函數(函數對象)

轉載:http://www.cnblogs.com/wuchanming/p/4411867.html 本文乃作者學習《C標準程序庫》的學習筆記,首先介紹了仿函數(函數對象)和函數適配器(配接器)的概念,然后列出STL中所有的仿函數&#x…

C++ template —— 動多態與靜多態(六)

轉載:http://www.cnblogs.com/yyxt/p/5157517.html 前面的幾篇博文介紹了模板的基礎知識,并且也深入的講解了模板的特性。接下來的博文中,將會針對模板與設計進行相關的介紹。 ------------------------------------------------------------…

變量之間的區別

全局變量、局部變量、靜態全局變量、靜態局部變量的區別 c變量根據定義具有不同的生命周期,會有不同的作用域,主要有六個作用域:全局作用域,局部作用域,文件作用域,類作用域,語句作用域&#xf…

計算機的網絡體系以及參考模型

計算機的網絡體系以及參考模型一、OSI七層模型二、TCP/IP參考模型三、TCP/IP 五層參考模型四、OSI 模型和 TCP/IP 模型異同比較五、OSI 和 TCP/IP 協議之間的對應關系六、為什么 TCP/IP 去除了表示層和會話層?七、數據如何在各層之間傳輸(數據的封裝過程…

C++ 模板詳解(二)

轉載:http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html 四、類模板的默認模板類型形參 1、可以為類模板的類型形參提供默認值,但不能為函數模板的類型形參提供默認值。函數模板和類模板都可以為模板的非類型形參提供默認值。 2、類模板的類…

c++類對象的創建方式

對象創建限制在堆或棧 c類對象的創建方式對象創建限制在堆或棧C 中的類的對象的建立模式如何將類限制在堆上呢?C 中的類的對象的建立模式 C 中的類的對象的建立模式分為兩張:靜態建立,動態建立 靜態建立:由編譯器為對象在棧空間…

C++ 模板詳解(一)

轉載:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html C模板 模板是C支持參數化多態的工具,使用模板可以使用戶為類或者函數聲明一種一般模式,使得類中的某些數據成員或者成員函數的參數、返回值取得任意類型。 模板是一種對類…

劍指Offer09. 用兩個棧實現隊列

class CQueue { public:stack<int> stack1,stack2;CQueue() {//初始化棧while(!stack1.empty()){stack1.pop();}while(!stack2.empty()){stack2.pop();}}void appendTail(int value) {stack1.push(value);}int deleteHead() {if(stack2.empty()){while(!stack1.empty()){…

rk3588 之啟動

目錄 uboot版本配置修改編譯 linux版本配置修改編譯 啟動sd卡啟動制作spi 燒錄 參考 uboot 版本 v2024.01-rc2 https://github.com/u-boot/u-boot https://github.com/rockchip-linux/rkbin 配置修改 使用這兩個配置即可&#xff1a; orangepi-5-plus-rk3588_defconfig r…

C++引用詳解

轉載&#xff1a;http://www.cnblogs.com/gw811/archive/2012/10/20/2732687.html 引用的概念 引用&#xff1a;就是某一變量&#xff08;目標&#xff09;的一個別名&#xff0c;對引用的操作與對變量直接操作完全一樣。 引用的聲明方法&#xff1a;類型標識符 &引用名目標…

劍指Offer03.數組中重復的數字

找出數組中重復的數字。 在一個長度為 n 的數組 nums 里的所有數字都在 0&#xff5e;n-1 的范圍內。數組中某些數字是重復的&#xff0c;但不知道有幾個數字重復了&#xff0c;也不知道每個數字重復了幾次。請找出數組中任意一個重復的數字。 示例 1&#xff1a; 輸入&…

C++ 模板全特化中的函數特化

轉載&#xff1a;http://blog.csdn.net/rain_qingtian/article/details/15815251 [cpp] view plaincopy print?#include <iostream> using namespace std; template<typename T> bool isLess(T x, T y) { cout << "general version\n&q…

c++面向對象總結

c面向對象總結什么是面向對象&#xff1f;面向對象的三大特性重寫和重載的區別隱藏和重寫&#xff0c;重載的區別什么是多態&#xff1f;多態如何實現什么是面向對象&#xff1f;面向對象的三大特性 面向對象&#xff1a;對象是指具體的某一個事物&#xff0c;這些事物的抽象就…

類模板static成員的使用

轉載&#xff1a;http://blog.csdn.net/ljq32/article/details/7911390 1. 與普通類的static成員一樣&#xff0c;類內部聲明一次&#xff0c;類外部定義一次&#xff0c;定義時可以設置也可以不設置初始值; 2. 類模板內部聲明與普通類的static成員一致&#xff1a; [html] vi…

Linux網絡編程服務器模型選擇之循環服務器

轉載&#xff1a;http://www.cnblogs.com/lizhenghn/p/3617608.html 在網絡程序里面&#xff0c;通常都是一個服務器處理多個客戶機&#xff0c;為了出個多個客戶機的請求&#xff0c;服務器端的程序有不同的處理方式。本節開始介紹Linux下套接字編程的服務器模型選擇&#xff…

劍指Offer04. 二維數組中的查找

在一個 n * m 的二維數組中&#xff0c;每一行都按照從左到右遞增的順序排序&#xff0c;每一列都按照從上到下遞增的順序排序。請完成一個高效的函數&#xff0c;輸入這樣的一個二維數組和一個整數&#xff0c;判斷數組中是否含有該整數。 相當于二叉搜索樹,左孩子比根節點小&…

Linux網絡編程服務器模型選擇之并發服務器(上)

轉載&#xff1a;http://www.cnblogs.com/lizhenghn/p/3617666.html 與循環服務器的串行處理不同&#xff0c;并發服務器對服務請求并發處理。循環服務器只能夠一個一個的處理客戶端的請求&#xff0c;顯然效率很低。并發服務器通過建立多個子進程來實現對請求的并發處理。并發…