久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 3869|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

關(guān)于C語言的關(guān)鍵字—const的理解和用法詳解

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:306491 發(fā)表于 2018-4-12 19:28 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
const在C語言中算是一個(gè)比較新的描述符,我們稱之為常量修飾符,意即其所修的對(duì)象為常量(immutable)。C中,const關(guān)鍵字的用途就是使函數(shù)操作時(shí)不改變其修飾的變量的值。
我們來分情況看語法上它該如何被使用。

1、函數(shù)體內(nèi)修飾局部變量。
例:
void func(){
const int a=0;}
    首先,我們先把const這個(gè)單詞忽略不看,那么a是一個(gè)int類型的局部自動(dòng)變量,我們給它賦予初始值0。然后再看const,const作為一個(gè)類型限定詞,和int有相同的地位。
const int a;
int const a;
是等價(jià)的。于是此處我們一定要清晰的明白,const修飾的對(duì)象是誰,是a,和int沒有關(guān)系。const 要求他所修飾的對(duì)象為常量,不可被改變,不可被賦值,不可作為左值(l-value)。
這樣的寫法也是錯(cuò)誤的。
const int a;
a=0;
這是一個(gè)很常見的使用方式:
const double pi=3.14;
在程序的后面如果企圖對(duì)pi再次賦值或者修改就會(huì)出錯(cuò)。
然后看一個(gè)稍微復(fù)雜的例子。
const int* p;
還是先去掉const 修飾符號(hào)。
注意,下面兩個(gè)是等價(jià)的。
int* p;
int *p;
其實(shí)我們想要說的是,*p是int類型。那么顯然,p就是指向int的指針。
同理
const int* p;
其實(shí)等價(jià)于
const int (*p);
int const (*p);
即,*p是常量。也就是說,p指向的數(shù)據(jù)是常量。
于是
p+=8; //合法
*p=3; //非法,p指向的數(shù)據(jù)是常量。

那么如何聲明一個(gè)自身是常量指針呢?方法是讓const盡可能的靠近p;
int* const p;
const右面只有p,顯然,它修飾的是p,說明p不可被更改。然后把const去掉,可以
看出p是一個(gè)指向 int形式變量的指針。
于是
p+=8; //非法
*p=3; //合法

再看一個(gè)更復(fù)雜的例子,它是上面二者的綜合
const int* const p;
說明p自己是常量,且p指向的變量也是常量。
于是
p+=8; //非法
*p=3; //非法

const 還有一個(gè)作用就是用于修飾常量靜態(tài)字符串。
例如:
const char* name="David";
如果沒有const,我們可能會(huì)在后面有意無意的寫name[4]='x'這樣的語句,這樣會(huì)導(dǎo)致對(duì)只讀內(nèi)存區(qū)域的賦值,然后程序會(huì)立刻異常終止。有了 const,這個(gè)錯(cuò)誤就能在程序被編譯的時(shí)候就立即檢查出來,這就是const的好處。讓邏輯錯(cuò)誤在編譯期被發(fā)現(xiàn)。

const 還可以用來修飾數(shù)組
const char s[]="David";
與上面有類似的作用。
2、在函數(shù)聲明時(shí)修飾參數(shù)
來看實(shí)際中的一個(gè)例子。
NAME
memmove -- copy byte string

LIBRARY
Standard C Library (libc, -lc)

SYNOPSIS
#include <string.h>

void *
memmove(void *dst, const void *src, size_t len);

這是標(biāo)準(zhǔn)庫中的一個(gè)函數(shù),用于按字節(jié)方式復(fù)制字符串(內(nèi)存)。
它的第一個(gè)參數(shù),是將字符串復(fù)制到哪里去(dest),是目的地,這段內(nèi)存區(qū)域必須是可寫。
它的第二個(gè)參數(shù),是要將什么樣的字符串復(fù)制出去,我們對(duì)這段內(nèi)存區(qū)域只做讀取,不寫。
于是,我們站在這個(gè)函數(shù)自己的角度來看,src 這個(gè)指針,它所指向的內(nèi)存內(nèi)所存儲(chǔ)的數(shù)據(jù)在整個(gè)函數(shù)執(zhí)行的過程中是不變。于是src所指向的內(nèi)容是常量。于是就需要用const修飾。
例如,我們這里這樣使用它。
const char* s="hello";
char buf[100];
memmove(buf,s,6); //這里其實(shí)應(yīng)該用strcpy或memcpy更好

如果我們反過來寫,
memmove(s,buf,6);
那么編譯器一定會(huì)報(bào)錯(cuò)。事實(shí)是我們經(jīng)常會(huì)把各種函數(shù)的參數(shù)順序?qū)懛。事?shí)是編譯器在此時(shí)幫了我們大忙。如果編譯器靜悄悄的不報(bào)錯(cuò),(在函數(shù)聲明處去掉const即可),那么這個(gè)程序在運(yùn)行的時(shí)候一定會(huì)崩潰。

這里還要說明的一點(diǎn)是在函數(shù)參數(shù)聲明中const一般用來聲明指針而不是變量本身。
例如,上面的size_t len,在函數(shù)實(shí)現(xiàn)的時(shí)候可以完全不用更改len的值,那么是否應(yīng)該把len也聲明為常量呢?可以,可以這么做。我們來分析這么做有什么優(yōu)劣。如果加了const,那么對(duì)于這個(gè)函數(shù)的實(shí)現(xiàn)者,可以防止他在實(shí)現(xiàn)這個(gè)函數(shù)的時(shí)候修改不需要修改的值(len),這樣很好。但是對(duì)于這個(gè)函數(shù)的使用者,
1、這個(gè)修飾符號(hào)毫無意義,我們可以傳遞一個(gè)常量整數(shù)或者一個(gè)非常量整數(shù)過去,反正對(duì)方獲得的只是我們傳遞的一個(gè)copy。
2。暴露了實(shí)現(xiàn)。我不需要知道你在實(shí)現(xiàn)這個(gè)函數(shù)的時(shí)候是否修改過len的值。
所以,const一般只用來修飾指針。

再看一個(gè)復(fù)雜的例子
int execv(const char *path, char *const argv[]);
著重看后面這個(gè),argv.它代表什么。如果去掉const,我們可以看出
char * argv[];
argv是一個(gè)數(shù)組,它的每個(gè)元素都是char *類型的指針。
如果加上const.那么const修飾的是誰呢?他修飾的是一個(gè)數(shù)組,argv[],意思就是說這個(gè)數(shù)組的元素是只讀的。那么數(shù)組的元素的是什么類型呢?是char *類型的指針。也就是說指針是常量,而它指向的數(shù)據(jù)不是。于是
argv[1]=NULL; //非法
argv[0][0]='a'; //合法

    3、全局變量。
我們的原則依然是,盡可能少的使用全局變量。
我們的第二條規(guī)則則是,盡可能多的使用const。
如果一個(gè)全局變量只在本文件中使用,那么用法和前面所說的函數(shù)局部變量沒有什么區(qū)別。
如果它要在多個(gè)文件間共享,那么就牽扯到一個(gè)存儲(chǔ)類型的問題。

有兩種方式。
1.使用extern
例如
/* file1.h */
extern const double pi;
/* file1.c */
const double pi=3.14;
然后其他需要使用pi這個(gè)變量的,包含file1.h
#include "file1.h"
或者,自己把那句聲明復(fù)制一遍就好。
這樣做的結(jié)果是,整個(gè)程序鏈接完后,所有需要使用pi這個(gè)變量的共享一個(gè)存儲(chǔ)區(qū)域。

2.使用static,靜態(tài)外部存儲(chǔ)類
/* constant.h */
static const pi=3.14;
需要使用這個(gè)變量的*.c文件中,必須包含這個(gè)頭文件。前面的static一定不能少。否則鏈接的時(shí)候會(huì)報(bào)告說該變量被多次定義。這樣做的結(jié)果是,每個(gè)包含了constant.h的*.c文件,都有一份該變量自己的copy,該變量實(shí)際上還是被定義了多次,占用了多個(gè)存儲(chǔ)空間,不過在加了static關(guān)鍵字后,解決了文件間重定義的沖突。壞處是浪費(fèi)了存儲(chǔ)空間,導(dǎo)致鏈接完后的可執(zhí)行文件變大。但是通常,這個(gè),小小幾字節(jié)的變化,不是問題。好處是,你不用關(guān)心這個(gè)變量是在哪個(gè)文件中被初始化的。

最后,說說const的作用。
const 的好處,是引入了常量的概念,讓我們不要去修改不該修改的內(nèi)存。直接的作用就是讓更多的邏輯錯(cuò)誤在編譯期被發(fā)現(xiàn)。所以我們要盡可能的多使用const。但是很多人并不習(xí)慣使用它,更有甚者,是在整個(gè)程序 編寫/調(diào)試 完后才補(bǔ)const。如果是給函數(shù)的聲明補(bǔ)const,尚好。如果是給 全局/局部變量補(bǔ)const,那么……那么,為時(shí)已晚,無非是讓代碼看起來更漂亮了。

const最經(jīng)常的用法
1.為了防止傳遞的函數(shù)參數(shù)不被修改,在調(diào)用函數(shù)的形參中用const關(guān)鍵字.
               //Example ->
               int FindNum(const int array[], int num, int conut);//聲明函數(shù)
               //code...
               int FindNum(const int array[], int num, int count)
               {
                        int i;
                        int flag = 1;
                        for (i = 0; (i < count) && flag; i++)
                        {
                                   if (array[ i] == num)
                                   {
                                           flag = 0;
                                           break;
                                   }
                         }
                         return flag;
                }
                //code...
               
    上面這例子中,編譯器會(huì)把a(bǔ)rray[]當(dāng)作常量數(shù)據(jù)的數(shù)組看待。所以,假如你不小心給數(shù)組賦值,那么,編譯器就會(huì)報(bào)錯(cuò)了。因此,當(dāng)你不需要也不想修改數(shù)組的數(shù)據(jù)時(shí),最好用const把數(shù)組定義為常量數(shù)組。
[ i]2.const可以用來創(chuàng)建數(shù)組常量、指針常量、指向常量的指針等:
        const char ch = 'a';
        const int a[5] = {1, 2, 3, 4, 5};  
        const int *p = a;          //a是一個(gè)數(shù)組的首地址.p是指向常量的指針
        int * const p = a;        //a是一個(gè)數(shù)組的首地址.p是指針常量;
        const int * const p = a;   //a是一個(gè)數(shù)組的首地址。p是指向常量的指針常量
前兩種情況很簡(jiǎn)單,現(xiàn)在著重分析一下后三種用法,因?yàn)檫@3種情況容易出錯(cuò),偶就有時(shí)候怕用錯(cuò)了剛脆不用const.   
——const int *p = a;  //p是指向常量的指針,因此,不可以通過給指針賦值來改變數(shù)組中的數(shù)據(jù),例如:
*p = 10;   /*錯(cuò)誤*/   
*(p + 2) = 1;  /*錯(cuò)誤*/
——int * const p = a;  //看這表達(dá)式,const的位置和第一個(gè)不同吧!他們的用法和作用就完全不一樣了。這時(shí)候p是指針常量,我們知道,指針是指向了一個(gè)數(shù)組的首地址,那么,它的位置就不可以改變了。但是你現(xiàn)在應(yīng)該和第一個(gè)表達(dá)式比較了,現(xiàn)在的數(shù)組并不是常量數(shù)組,  所以數(shù)組的數(shù)據(jù)是可以改變的,而指針這時(shí)候它是不可以移動(dòng)的  ,指向數(shù)組第一個(gè)數(shù)據(jù),所以它可以而且只可以改變數(shù)組第一個(gè)數(shù)據(jù)的值。
下面舉幾個(gè)例子幫助理解:
*p = 2;          /*可以*/   
*(p+1) = 10;     /*可以*/
     p++;             /*不可以*/
    ——const int * const p = a; //假如前面兩種表達(dá)式的本質(zhì)你理解了,這種表達(dá)式你來理解根本沒有問題,const現(xiàn)在有兩個(gè),而且一個(gè)const的位置是第一種情況的位置,第二個(gè)const是第二種情況的位置,所以這表達(dá)式的功能就是前兩種情況的作用總合。這里不多說!
下面舉幾個(gè)例子幫助理解:
*p = 2;  /*不可以*/
     *(p + 2) = 10; /*不可以*/  
p++; /*不可以*/

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:383374 發(fā)表于 2019-1-23 00:16 來自觸屏版 | 只看該作者
感謝解說,受教了
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 一区二区三区四区不卡 | 美女视频三区 | 色综合久 | 日本午夜视频 | 日韩欧美精品在线 | 国产精品毛片一区二区在线看 | 欧美区在线| sese视频在线观看 | av无遮挡 | 国产一区二区电影 | 91视频在线看 | 久久一区 | 青青草一区二区三区 | 九九精品在线 | 国产在线精品一区二区三区 | 另类专区成人 | 日韩在线观看中文字幕 | av电影手机在线看 | 高清黄色毛片 | 日本精品一区二区三区在线观看视频 | 亚洲一区二区电影在线观看 | 在线视频成人 | 国产精品久久久久久久久久妇女 | 日韩亚洲一区二区 | 久久精品日产第一区二区三区 | 国产精品一区2区 | 日韩精品一区二区三区在线播放 | 亚洲一区二区中文字幕 | 精品久久香蕉国产线看观看亚洲 | 免费成人在线网站 | 日日碰狠狠躁久久躁婷婷 | 一区二区福利视频 | 日日夜夜精品视频 | 国产成人av在线播放 | 日韩成人免费视频 | 99久久99 | 国产精久久久久久久妇剪断 | 自拍偷拍中文字幕 | 亚洲一区二区三区乱码aⅴ 四虎在线视频 | 成人免费视频久久 | 久久av.com|