聲明
本系列來(lái)至中國(guó)大學(xué)慕課-闞道宏老師的C++系列課程的相關(guān)課堂筆記嵌纲,闞道宏老師講解細(xì)膩、精準(zhǔn)汉匙,由淺入深拱烁,徐徐漸進(jìn),有興趣的可以去中國(guó)大學(xué)慕課上查看闞道宏老師的相關(guān)課程噩翠。
本文僅用于學(xué)習(xí)交流,若有侵權(quán)邦投,請(qǐng)聯(lián)系我
數(shù)據(jù)需要保存再內(nèi)存中才能被計(jì)算機(jī)讀取伤锚,計(jì)算結(jié)果也只能保存在計(jì)算機(jī)內(nèi)存中,如果程序需要處理大量的數(shù)據(jù)志衣,如何定義變量呢屯援?例如要處理100個(gè)同學(xué)的成績(jī)單。
未了處理和保存大規(guī)模的數(shù)據(jù)念脯,C++語(yǔ)言提供了特殊的語(yǔ)言組織形式狞洋,我們稱之為數(shù)組。
數(shù)組的基本概念:
數(shù)組是一組數(shù)據(jù)類型相同绿店,變量某種次序排列的數(shù)據(jù)集合吉懊,其中的每個(gè)數(shù)據(jù)被稱為數(shù)組的一個(gè)元素,數(shù)組元素按排列次序編號(hào)假勿,編號(hào)為整數(shù)借嗽,從0開始,編號(hào)就被稱為數(shù)組元素的下標(biāo)转培。存儲(chǔ)一維方向排列的數(shù)據(jù)恶导,例如數(shù)列,就是用一維數(shù)組浸须,一維數(shù)組有一個(gè)下標(biāo)惨寿;存儲(chǔ)二維方向排列的數(shù)據(jù)邦泄,例如矩陣,就是用二維數(shù)組裂垦,二維數(shù)組有2個(gè)下標(biāo)虎韵,第一個(gè)為行下標(biāo),第二個(gè)為列下標(biāo)缸废;c++語(yǔ)言也可以定義多維數(shù)組包蓝,最常用的就是一維數(shù)組和二維數(shù)組。
文字處理程序處理字符數(shù)據(jù):
文字程序所處理的對(duì)象是字符數(shù)據(jù)企量,計(jì)算機(jī)只能存儲(chǔ)和處理數(shù)值數(shù)據(jù)测萎,而文字是程序所處理的對(duì)象是字符數(shù)據(jù),為了存儲(chǔ)和處理字符數(shù)據(jù)届巩,需要使用某種字符標(biāo)準(zhǔn)硅瞧,將字符轉(zhuǎn)換為字符編碼,字符編碼就是字符的編碼恕汇,例如計(jì)算機(jī)可以處理英文腕唧,ASCII碼就是專門為處理英文設(shè)計(jì)的編碼標(biāo)準(zhǔn),c++語(yǔ)言使用字符類型來(lái)存儲(chǔ)字符的編碼瘾英,該變碼是一個(gè)單字節(jié)整數(shù)枣接,c++語(yǔ)言將字符類型和單字節(jié)整數(shù)類型合二為一,統(tǒng)稱為字符類型缺谴,關(guān)鍵字是char但惶,在計(jì)算機(jī)內(nèi)部,一個(gè)字符就是一個(gè)單字節(jié)整數(shù)湿蛔,一個(gè)字符類型的變量可以保存一個(gè)字符膀曾,而如果需要保存一篇文章,這篇文章其實(shí)是一組字符阳啥,我們就需要使用字符數(shù)組添谊。
一、數(shù)組
1.1 定義數(shù)組
- 定義數(shù)組的一個(gè)限制條件就是這組數(shù)據(jù)的數(shù)據(jù)類型必須相同察迟,該類型稱為數(shù)組變量的數(shù)組類型斩狱。
- 定義數(shù)組變量時(shí)須指定數(shù)組元素的個(gè)數(shù),每個(gè)數(shù)組元素相當(dāng)于一個(gè)普通變量卷拘,可以存放一個(gè)數(shù)據(jù)喊废。
- 訪問某個(gè)數(shù)組元素時(shí)需通過(guò)下標(biāo)來(lái)指明訪問的是哪個(gè)數(shù)組元素
語(yǔ)法:
數(shù)據(jù)類型 數(shù)組變量名[常量表達(dá)式1][常量表達(dá)式2]...[常量表達(dá)式n]
詳解:
- 數(shù)據(jù)類型:指定了數(shù)組變量的數(shù)據(jù)類型
- 數(shù)組變量名:可簡(jiǎn)稱為數(shù)組名,需復(fù)合標(biāo)識(shí)符的命名規(guī)則
- 常量表達(dá)式:指定了多維數(shù)組各下標(biāo)的個(gè)數(shù)栗弟,用中括號(hào)[]括起來(lái)污筷,常量表達(dá)式可以是單個(gè)常量,或是由常量組成的表達(dá)式,其結(jié)果必須為正整數(shù)瓣蛀。
- 定義一維數(shù)組給1個(gè)常量表達(dá)式陆蟆,指定數(shù)組元素的個(gè)數(shù),一維數(shù)組的元素個(gè)數(shù)也稱為該數(shù)組的長(zhǎng)度惋增;定義二維數(shù)組個(gè)2個(gè)常量表達(dá)式叠殷,第一個(gè)指定行數(shù),第二個(gè)指定列數(shù)诈皿,數(shù)組元素個(gè)數(shù)=行數(shù)x列數(shù)林束;數(shù)組元素的個(gè)數(shù)等于各常量表達(dá)式的乘積。
舉例:
int x[5]; //定義一個(gè)一維數(shù)組變量x稽亏,包含5個(gè)元素
double y[2+3]; //定義一個(gè)double類型一維數(shù)組變量y壶冒,包含5個(gè)元素
int z[5][10]; //定義一個(gè)int類型的二維數(shù)組變量z,包含5行截歉,10列胖腾,共50個(gè)元素。
int a,x[5],z[5][10]; //可以將相同類型的數(shù)組變量和普通變量放在一條語(yǔ)句定義
當(dāng)執(zhí)行數(shù)組類型語(yǔ)句時(shí)瘪松,計(jì)算機(jī)為數(shù)組變量中的所有元素同時(shí)分配內(nèi)存空間咸作,各數(shù)組元素的內(nèi)存單元,在內(nèi)存中是按順序連續(xù)排列的宵睦,數(shù)組變量所占字節(jié)數(shù)等于所有元素所占字節(jié)數(shù)的總和记罚,為了方便程序員,c++語(yǔ)言提供了一種sizeof運(yùn)算符状飞,來(lái)求某種數(shù)據(jù)類型或變量所占用的字節(jié)數(shù)毫胜。
sizeof運(yùn)算符:
sizeof(數(shù)據(jù)類型名)
或
sizeof(表達(dá)式)
語(yǔ)法說(shuō)明:
- sizeof(數(shù)據(jù)類型名)的計(jì)算結(jié)果是指定數(shù)據(jù)類型占用的字節(jié)數(shù)
- sizeof(表達(dá)式)的計(jì)算結(jié)果是指定表達(dá)式結(jié)果類型占用的字節(jié)數(shù),表達(dá)式是可以單個(gè)變量诬辈、常量或數(shù)組變量,這時(shí)sizeof的計(jì)算結(jié)果就是該變量荐吉、常量或數(shù)組變量占用的字節(jié)數(shù)焙糟。
舉例:
sizeof(int); //結(jié)果為4,因?yàn)閕nt類型占用4個(gè)字節(jié)
sizeof(5); //結(jié)果為4样屠,因?yàn)?是int型穿撮。
sizeof(2+3); //結(jié)果為4,因?yàn)?是int型痪欲。
int a[5];
sizeof(a); //因?yàn)閍是一個(gè)int型一維數(shù)組變量悦穿,有5個(gè)元素,一個(gè)元素占用4個(gè)字節(jié)业踢,故結(jié)果為20栗柒。
1.2 訪問數(shù)組元素:
遍歷:對(duì)數(shù)據(jù)集合最常規(guī)的處理方法是依次訪問集合中的每個(gè)元素,將所有的元素逐個(gè)處理一遍知举,這種處理方法稱為對(duì)數(shù)據(jù)集合的遍歷**
設(shè)計(jì)遍歷算法瞬沦,需要用到循環(huán)結(jié)構(gòu)太伊。
數(shù)組變量名[下標(biāo)表達(dá)式1][下標(biāo)表達(dá)式2]...[下標(biāo)表達(dá)式n]
語(yǔ)法說(shuō)明:
- 數(shù)組變量名知名要訪問哪個(gè)數(shù)組
- 下標(biāo)表達(dá)式指明所訪問的數(shù)組元素的下標(biāo),多維數(shù)組要指明所有下標(biāo)逛钻,分別用中括號(hào)[]括起來(lái)僚焦,假設(shè)下標(biāo)表達(dá)式n所對(duì)應(yīng)的數(shù)組定義的下標(biāo)個(gè)數(shù)為N,則該表達(dá)式的結(jié)果應(yīng)當(dāng)為0~N-1之間的非負(fù)整數(shù)曙痘,0為該下標(biāo)的下界芳悲,N-1為該下標(biāo)的上界;訪問數(shù)組變量時(shí)边坤,下標(biāo)不能越界名扛,否則會(huì)出現(xiàn)越界錯(cuò)誤,編譯器檢測(cè)不出程序中的越界錯(cuò)誤惩嘉,但執(zhí)行時(shí)可能會(huì)導(dǎo)致不可預(yù)知的后果罢洲,例如死機(jī)等;
- 訪問一維數(shù)組元素給1個(gè)下標(biāo)表達(dá)式文黎;訪問二維數(shù)組給2個(gè)下標(biāo)表達(dá)式惹苗,第1個(gè)是行下標(biāo),第2個(gè)是列下標(biāo)耸峭;......桩蓉。
舉例:定義一個(gè)一維數(shù)組變量:int x[3];
int x[3];
/*訪問x中的元素*/
x[0] = 10; //將數(shù)組變量x的第0個(gè)元素賦值為10
x[1] = 20; //將數(shù)組變量x的第1個(gè)元素賦值為20
x[2] = 30; //將數(shù)組變量x的第2個(gè)元素賦值為30
x[3] = 40; //越界錯(cuò)誤,x的上界為2
實(shí)例:二維數(shù)組的訪問
如果定義了二維數(shù)組y
int y[2][3]; //包含2行3列劳闹,共計(jì)6個(gè)元素
y[0][0] = 10; //將數(shù)組第0行院究,第0列賦值為10
y[0][1] = 20; //將數(shù)組第0行,第1列賦值為20
y[1][2] = 30; //將數(shù)組第1行本涕,第3列賦值為20
//訪問二維數(shù)組時(shí)业汰,行下標(biāo)和列下標(biāo),均不能越界
放位數(shù)組元素時(shí)菩颖,可以使用變量样漆,或表達(dá)式來(lái)指定數(shù)組元素的下標(biāo),舉例:
int n=0,x[3];
x[n] = 10; //n=0,故將x數(shù)組中的第0個(gè)元素賦值為10
x[n+1] = 20; //n+1=1,故將x數(shù)組中的第1個(gè)元素賦值為10
//使用變量和表達(dá)式作為下標(biāo)訪問數(shù)組的元素時(shí)晦闰,同樣不能越界放祟。
1.3 數(shù)組的整體輸入和輸出
可以使用cin語(yǔ)句一次性從鍵盤輸入所有的數(shù)組元素,這種方式稱為數(shù)組的整體輸入呻右,也可以用cout語(yǔ)句將數(shù)組元素輸出到顯示器上跪妥,我們稱之為數(shù)組的整體輸出,數(shù)組的整體輸入輸出声滥,需要遍歷所有的數(shù)組元素眉撵,可以使用循環(huán)結(jié)構(gòu)來(lái)實(shí)現(xiàn)。
#include <iostream>
using namespace std;
int main(){
int m,n;
int x[3];
for(n=0;n<3;n++)// 因當(dāng)注意n的取值范圍,避免越界錯(cuò)誤
cin>>x[n];
for(n=0;n<3;n++)
cout<<"一維數(shù)組y:"<<x[n]<<",";
cout<<endl;
double y[2][3];
/*訪問二維數(shù)組执桌,需要用到2層循環(huán)*/
for(m=0;m<2;m++) //第一層是對(duì)行進(jìn)行循環(huán)
{
for (n=0;n<3;n++) //第二層是對(duì)列進(jìn)行循環(huán)
cin>>y[m][n]; //注意順序鄙皇,不能寫反
}
for(m=0;m<2;m++)
{
for(n=0;n<3;n++)
cout<<"二維數(shù)組y:"<<y[m][n]<<",";
cout<<endl;
}
return 0;
}
1.4 數(shù)組的初始化
定義一個(gè)數(shù)組變量時(shí),各數(shù)組元素都被分配在內(nèi)存單元仰挣,但內(nèi)存單元存放的是以前遺留的數(shù)據(jù)伴逸,這些數(shù)據(jù)是不確定的,在定義數(shù)組變量時(shí)膘壶,可以為全部或部分元素賦初始值错蝴,這就稱為數(shù)組變量的初始化。
初始值用大括號(hào){}括起來(lái)颓芭,二維數(shù)組的初始值的排列順序是按照先行后列的順序中跌。
int x[3] = {2,4,6}; //將3個(gè)元素的初始值依次設(shè)定為2凤价、4、6
/*將第0行的3個(gè)元素依次設(shè)定為1、3萎战、5 將第1行的3個(gè)元素依次設(shè)定為2绣夺、4纽门、6*/
double y[2][3] = {1,3,5,2,4,6};
定義數(shù)組變量時(shí)憨栽,如果列出了全部元素的初始值,那么可以省略第一個(gè)下標(biāo)床玻,計(jì)算機(jī)可以根據(jù)已經(jīng)初始化的元素個(gè)數(shù)自動(dòng)計(jì)算第一個(gè)下標(biāo)的數(shù)量毁涉。
int x[]={2,4,6}; //一維數(shù)組省略下標(biāo)個(gè)數(shù),將根據(jù)初始值數(shù)量把下標(biāo)個(gè)數(shù)設(shè)定為3
double y[][3] = {1,3,5,2,4,6}; //多維數(shù)組只能省略第一個(gè)下標(biāo)個(gè)數(shù)锈死,將根據(jù)初始值數(shù)量將行下標(biāo)個(gè)數(shù)設(shè)定為2贫堰,6/3=2
當(dāng)給出的初始值個(gè)數(shù)少于下標(biāo)數(shù)量時(shí),則會(huì)依次賦值待牵,最后沒有被賦值的元素其屏,自動(dòng)設(shè)定為0,這種只給出部分初始值的方法缨该,稱為部分初始化漫玄,部分初始化時(shí),未被初始化的元素自動(dòng)設(shè)為0.
int x[3]={2,4}; //依次將第0個(gè)元素和第一個(gè)元素賦值為2和4压彭,第三個(gè)元素沒有初始值,設(shè)為0.
double y[2][3]={{1,3},{2,4}};//每一行最后一個(gè)元素沒有初始值渗常,設(shè)定為0
double y[2][3]={{1,3,5}};//第0行的3個(gè)元素設(shè)定為1壮不、3、5皱碘,第1行沒有給出初始值询一,3個(gè)元素設(shè)定為0
1.5 常用的數(shù)組處理方法
數(shù)組變量中存放的是一個(gè)數(shù)據(jù)集合,處理數(shù)據(jù)集合算法,例如求數(shù)組元素的總和健蕊,或平均值菱阵,通常都要遍歷數(shù)組中的所有元素,因此需要使用循環(huán)結(jié)構(gòu)來(lái)實(shí)現(xiàn)缩功。遍歷多維數(shù)組時(shí)需要用到多重循環(huán)晴及。
實(shí)例:求數(shù)組元素總和以及平均值的c++程序
#include <iostream>
using namespace std;
int main(){
float y[2][3] = {{1.0,3.5,5.2},{2.2,4.9,6.5}};
int m,n;
float average,sum=0;
/*
求二維數(shù)組的總和和平均值,需要先遍歷行嫡锌,在遍歷列虑稼。
*/
for(m=0;m<2;m++)
{
for(n=0;n<3;n++)
sum +=y[m][n]; //將數(shù)組y中所有的元素全部累加到sum上
}
average = sum/6;
cout<<"數(shù)列的元素的和為:"<<sum<<"平均值為:"<<average<<endl;
return 0;
}
實(shí)例:求二維數(shù)組元素中的最大值和最小值
#include <iostream>
using namespace std;
int main(){
int x[2][3] = {{1,3,5},{2,4,6}};
int m,n;
int max=x[0][0],min =x[0][0]; //先假定第一個(gè)元素是最大或最小的
/*利用循環(huán)對(duì)所有值進(jìn)行判斷*/
for(m=0;m<2;m++)
for(n=0;n<3;n++)
{
if(x[m][n]>max) max=x[m][n];
if(x[m][n]<min) min=x[m][n];
}
cout<<"最大值是:"<<max<<",最小值是:"<<min<<endl;
return 0;
}
數(shù)組排序:
排序是將原來(lái)無(wú)序的數(shù)據(jù)集合按照某種規(guī)則進(jìn)行排序,這樣可以提高今后查找的速度势木。
假如定義一個(gè)數(shù)組變量x:int x[6] = {1蛛倦,4,6啦桌,2溯壶,5,3}甫男;該集合的數(shù)據(jù)順序是雜亂無(wú)章的且改,如果按照數(shù)據(jù)從小到大排序,即可得到一個(gè)按照1查剖、2钾虐、3、4笋庄、5效扫、6排列的一維數(shù)組。選擇排序:
#include <iostream>
using namespace std;
int main(){
int x[6]={1,3,4,6,5,2};
int a,b,min,temp;
for(a=0;a<6-1;a++) //選取0-4的元素直砂,剩余一個(gè)不選擇
{
min=a; //此時(shí)假設(shè)下標(biāo)為a的元素就是最小的菌仁,將下標(biāo)a賦值給中間變量min
for(b=a+1;b<6;b++) //第二次循環(huán)從1-5,也就抽取是第一次循環(huán)下標(biāo)a后面的數(shù)
{
if(x[b]<x[min]) //通過(guò)下標(biāo)抽取元素静暂,并比較這兩個(gè)數(shù)的大小
min=b; //如果下標(biāo)b所對(duì)應(yīng)的元素更小济丘,將b的值賦值給min
}
temp=x[a];x[a]=x[min];x[min]=temp; //再次通過(guò)一個(gè)中間變量交換下標(biāo)a和下標(biāo)min所對(duì)應(yīng)的元素值
}
for(a=0;a<6;a++)
cout<<x[a]<<",";
return 0;
}
二、指針與數(shù)組
定義數(shù)組變量洽蛀,計(jì)算機(jī)將為數(shù)組變量中的所有元素同時(shí)分配內(nèi)存空間摹迷,各數(shù)組元素的內(nèi)存單元在內(nèi)存中是按順序連續(xù)排列的,本章講述通過(guò)指針變量訪問元素的方法郊供。
- 如果定義一個(gè)指針變量p峡碉,將數(shù)組中第0個(gè)元素的地址(簡(jiǎn)稱為數(shù)組首地址)賦值給p,我們稱指針變量p指向了該數(shù)組的第0個(gè)元素驮审, 這時(shí)我們就可以通過(guò)指針變量p來(lái)間接訪問數(shù)組的第0個(gè)元素鲫寄。
- 修改指針變量p中的地址值吉执,使之指向任意一個(gè)數(shù)組元素,這樣就可以間接訪問數(shù)組中的所有元素
- 利用數(shù)組元素在內(nèi)存中連續(xù)存儲(chǔ)的特點(diǎn)地来,通過(guò)加減運(yùn)算符修改地址值可以讓指針變量指向不同的數(shù)組元素
- 通過(guò)比較地址值的大写撩怠(關(guān)系運(yùn)算),可以確定不同數(shù)組元素之間的位置次序
- 指針變量類型就是地址類型未斑,凡是涉及到地址運(yùn)算統(tǒng)稱為指針運(yùn)算咕宿,例如對(duì)內(nèi)存地址進(jìn)行算法運(yùn)算、關(guān)系運(yùn)算颂碧,以及取地址荠列、取內(nèi)容運(yùn)算等等,通過(guò)指針變量和指針運(yùn)算可以方便的遍歷數(shù)組元素
2.1 通過(guò)指針變量間接訪問數(shù)組元素
定義一個(gè)和數(shù)組相同類型的指針變量载城,就可以將指針變量指向任意一個(gè)數(shù)組元素肌似,然后通過(guò)指針變量間接訪問數(shù)組元素。
實(shí)例:星號(hào)*是取內(nèi)容運(yùn)算符
int x[6] = {1,4,6,2,5,3};
int *p; //定義一個(gè)和數(shù)組x相同類型的指針變量p诉瓦,類型都是int型
p = &x[0]; //將指針變量指向數(shù)組x的第0個(gè)元素川队,第0個(gè)元素的地址是該數(shù)組的首地址
cout<<*p; //通過(guò)指針變量訪問第0個(gè)元素,結(jié)果為1
p = &x[1]; //修改指針變量指向睬澡,將指針變量指向第1個(gè)元素
數(shù)組第0個(gè)位置的地址固额,我們稱之為首地址,可以直接通過(guò)數(shù)組名來(lái)取出數(shù)組的首地址煞聪。
p = &x[0]; //將指針變量p指向數(shù)組的首地址
p = x; //也可以通過(guò)訪問數(shù)組名的方式取得一維數(shù)組的內(nèi)存首地址斗躏。
可以將一維數(shù)組的數(shù)組名理解為是一個(gè)表示該數(shù)組首地址的符號(hào)常量
2.2 指針變量的算術(shù)運(yùn)算
利用數(shù)組元素在內(nèi)存中連續(xù)存儲(chǔ)的特點(diǎn),利用加減運(yùn)算昔脯,修改地址值啄糙,可以讓指針變量指向不同的數(shù)組元素,根據(jù)不同符號(hào)類型的元素存儲(chǔ)寬度云稚,對(duì)指針變量值進(jìn)行加減操作即可隧饼,例如一個(gè)int型的數(shù)組,每個(gè)元素的存儲(chǔ)位數(shù)是4個(gè)字節(jié)静陈,要改變指針變量的指向燕雁, 只需要對(duì)指針變量執(zhí)行加減4即可。例如:
- int型數(shù)組:p+=4;
- double型數(shù)組:p+=8;
也就是說(shuō)程序員使用指針變量鲸拥,遍歷數(shù)組拐格,在將指針變量從一個(gè)元素移到下一個(gè)元素時(shí),要考錄到數(shù)組的類型刑赶,不同的類型增加不同的字節(jié)數(shù)禁荒,這樣是比較麻煩的,為了方便程序員使用指針變量遍歷數(shù)組角撞,減輕程序員的負(fù)擔(dān)呛伴,C++語(yǔ)言規(guī)定,不管數(shù)組是什么類型谒所,將指針變量從一個(gè)元素移動(dòng)到下一個(gè)元素热康,都統(tǒng)一成:p+=1;為了實(shí)現(xiàn)這一點(diǎn)劣领,c++修改了指針變量于整數(shù)加減的規(guī)則姐军。
指針變量與整數(shù)進(jìn)行加減運(yùn)算:
假設(shè)指針變量的數(shù)類型為T,n為整數(shù)尖淘,表達(dá)式的結(jié)果仍為T類型的指針奕锌,其地址值等于p的地址值:,其中sizeof(T)村生,就是T類型所占的字節(jié)數(shù)惊暴,按照這個(gè)運(yùn)算規(guī)則,如果指針變量p指向數(shù)組對(duì)應(yīng)的某個(gè)元素趁桃,那么就是該元素后辽话,第n個(gè)元素的地址,而p-n就是p目前指向的元素前面第n個(gè)元素的地址卫病。
同類型指針變量之間的相減:
假設(shè)兩個(gè)指針變量p1和p2他們的指針類型都為T類型油啤,那么表達(dá)式的結(jié)果為int型,數(shù)值等于:蟀苛,就是兩個(gè)地址的差值除以sizeof(T)益咬,就是T類型的字節(jié)數(shù)。按照這個(gè)運(yùn)算規(guī)則帜平,如果指針變量分別指向同一數(shù)組中的兩個(gè)元素幽告,則p1-p2的結(jié)果,就是這兩個(gè)元素下標(biāo)的差值
void類型指針:
c++規(guī)定不能參與上述運(yùn)算罕模,因?yàn)槠老伲瑂izeof(void)沒有確切的定義
實(shí)例:
#include <iostream>
using namespace std;
int main(){
int x[6]={1,4,6,2,5,3};
int *p, *p1, *p2; //定義3個(gè)int型指針變量p,p1淑掌,p2蒿讥,類型和數(shù)組類型相同
p = &x[0]; //將指針變量p指向第0個(gè)元素
for(int n=0;n<6;n++)
cout<<*(p+n)<<","; //通過(guò)指針變量與整數(shù)的算術(shù)運(yùn)算依次訪問各數(shù)組元素
cout<<endl;
int d; //定義一個(gè)int型變量d
p1 = p+1; //將指針變量p1指向第1個(gè)元素
p2 = p+4; //將指針變量p2指向第4個(gè)元素
d = p2-p1; //指針變量之間的差值等于等于其所指向數(shù)組下標(biāo)之間的差值,及4-1
cout<<d<<endl;//顯示結(jié)果為3
d = &x[4]-&x[1]; //數(shù)組元素地址之間的差值等于其下標(biāo)之間的差值抛腕,及4-1
cout<<d<<endl; //顯示結(jié)果為3
return 0;
}
2.3 指針變量之間的關(guān)系運(yùn)算
使用關(guān)系型運(yùn)算符芋绸,可以比較兩個(gè)地址值的大小,如果兩個(gè)指針變量指向同一數(shù)組中的元素担敌,則可以通過(guò)比較他們的大小摔敛,確定其指向數(shù)組元素之間的位置次序關(guān)系,地址值小的元素在前全封,地址值大的元素在后马昙,如果相等桃犬,則說(shuō)明這兩個(gè)指針變量指向了數(shù)組中的同一個(gè)元素。
實(shí)例:
#include <iostream>
using namespace std;
int main(){
int x[6]={1,4,6,2,5,3};
int *p;
for(p=&x[0]; p<=&x[5]; p++)//確定循環(huán)的終止點(diǎn)行楞,比較指針p和&x[5]的大小攒暇。
cout<<*p<<","; //通過(guò)*p取出內(nèi)存中對(duì)應(yīng)的值,*號(hào)是取內(nèi)容運(yùn)算符
cout<<endl;
return 0;
}
2.4 指針的取內(nèi)容運(yùn)算
指針運(yùn)算符星號(hào)*子房,也被稱為取內(nèi)容運(yùn)算符形用,通過(guò)指針變量保存的內(nèi)存地址,訪問所指向的內(nèi)存單元证杭,
int x[6] = {1,4,6,2,5,3};
*p=x; //定義指針變量p指向數(shù)組x的首地址田度,也就是&x[0]
/*通過(guò)指針運(yùn)算符*訪問數(shù)組元素*/
*p; //訪問第0個(gè)元素
*(p+1); //訪問第1個(gè)元素
*(p+2); //訪問第2個(gè)元素
/*通過(guò)下標(biāo)運(yùn)算符[],來(lái)訪問數(shù)組元素*/
p[0]; //訪問第0個(gè)元素
p[1]; //訪問第1個(gè)元素
p[2]; //訪問第2個(gè)元素
一維數(shù)組的數(shù)組名可以理解為一個(gè)表示該數(shù)組首地址的符號(hào)常量解愤。因此數(shù)組名除了使用下標(biāo)運(yùn)算符[]來(lái)訪問數(shù)組元素外镇饺,也可以用指針運(yùn)算符來(lái)訪問數(shù)組元素。因此數(shù)組名也可以認(rèn)為是一個(gè)指針琢歇,
int x[6] = {1,4,6,2,5,3};
/*通過(guò)下標(biāo)運(yùn)算符[]兰怠,來(lái)訪問數(shù)組元素*/
x[0]; //訪問第0個(gè)元素
x[1]; //訪問第1個(gè)元素
x[2]; //訪問第2個(gè)元素
/*通過(guò)指針運(yùn)算符*訪問數(shù)組元素*/
*x; //訪問第0個(gè)元素
*(x+1); //訪問第1個(gè)元素
*(x+2); //訪問第2個(gè)元素
通過(guò)以上幾種訪問形式魄宏,可以看出,從本質(zhì)上講烁焙,訪問數(shù)組元素册招,是一種通過(guò)指針的間接訪問,訪問時(shí)扔嵌,可以使用下標(biāo)運(yùn)算符[],也可以使用指針運(yùn)算符*寥裂。
2.5 動(dòng)態(tài)內(nèi)存分配
程序定義數(shù)組變量可以保存大量相同類型的數(shù)據(jù)嵌洼,在處理不同數(shù)據(jù)的時(shí)候,數(shù)組的元素個(gè)數(shù)往往不一樣封恰,定義數(shù)組時(shí)麻养,元素個(gè)數(shù)該定義為多少,需要程序員在定義數(shù)組時(shí)先預(yù)估元素的個(gè)數(shù)诺舔,如果程序員在定義數(shù)組時(shí)數(shù)組元素少于實(shí)際的元素?cái)?shù)量鳖昌,就會(huì)造成錯(cuò)誤,多于實(shí)際的元素個(gè)數(shù)時(shí)混萝,就會(huì)造成內(nèi)存的浪費(fèi)遗遵,在c++語(yǔ)言中可以使用動(dòng)態(tài)內(nèi)存分配的方法。
動(dòng)態(tài)內(nèi)存分配:
new和delete運(yùn)算符逸嘀,new分配內(nèi)存车要,delete運(yùn)算符用于釋放內(nèi)存。動(dòng)態(tài)內(nèi)存分配因當(dāng)在使用完以后崭倘,及時(shí)釋放內(nèi)存翼岁,以提高內(nèi)存的利用率类垫,內(nèi)存的動(dòng)態(tài)分配、訪問和釋放都必須通過(guò)指定變量才能實(shí)現(xiàn)琅坡。針對(duì)單個(gè)變量和數(shù)組變量悉患,new和delete運(yùn)算符的語(yǔ)法不一樣。
動(dòng)態(tài)內(nèi)存分配又稱為在堆分配榆俺,生存期由用戶指定售躁,分配靈活,但有內(nèi)存泄露等問題茴晋,是一個(gè)在程序里面隨機(jī)申請(qǐng)的內(nèi)存陪捷。
在C語(yǔ)言中使用函數(shù)來(lái)實(shí)現(xiàn)內(nèi)存的動(dòng)態(tài)分配
- 分配內(nèi)存:malloc函數(shù)
- 釋放內(nèi)存:free函數(shù)
C++語(yǔ)言提供了另外一種新的動(dòng)態(tài)內(nèi)存分配方法
- 分配內(nèi)存:new運(yùn)算符
- 釋放內(nèi)存:delete運(yùn)算符
動(dòng)態(tài)內(nèi)存分配可以提高內(nèi)存的使用率,內(nèi)存的動(dòng)態(tài)分配诺擅、訪問和釋放市袖,都需通過(guò)指針變量來(lái)實(shí)現(xiàn),C++針對(duì)單個(gè)變量和數(shù)組變量烁涌,new運(yùn)算符和delete運(yùn)算符使用語(yǔ)法有區(qū)別
1苍碟、基本的定義和釋放方法
動(dòng)態(tài)內(nèi)存分配時(shí),不需要指定變量名撮执,但是需要指定數(shù)據(jù)類型微峰,分配成功后,講返回分配內(nèi)存單元的首地址二打,需要預(yù)習(xí)定義好一個(gè)同類型的指針變量來(lái)保存這個(gè)地址县忌,后續(xù)訪問該內(nèi)存單元時(shí),需要使用指針變量继效,來(lái)進(jìn)行間接訪問症杏,釋放內(nèi)存單元時(shí)也需要使用這個(gè)指針變量,來(lái)指定釋放哪個(gè)內(nèi)存單元瑞信,
指針變量名 = new 數(shù)據(jù)類型(初始值);
delete指針變量名厉颤;
語(yǔ)法說(shuō)明:
- 數(shù)據(jù)類型指定動(dòng)態(tài)分配變量的數(shù)據(jù)類型;
- (初始值)指定所分配內(nèi)存單元的初始值(用小括號(hào)括起來(lái))凡简,及變量的初始化逼友,如果不需要初始化,“(初始值)”則可以省略秤涩;
- 計(jì)算機(jī)執(zhí)行new運(yùn)算符時(shí)將按照數(shù)據(jù)類型指定的字節(jié)數(shù)分配內(nèi)存空間并初始化帜乞,然后返回所分配內(nèi)存單元的首地址,應(yīng)當(dāng)通過(guò)賦值語(yǔ)句將該首地址保存到一個(gè)預(yù)先定義好的同類型指針變量中筐眷;
- 計(jì)算機(jī)執(zhí)行delete運(yùn)算符時(shí)將按照指針變量中的地址釋放指定的內(nèi)存單元黎烈;
int *p; //為了動(dòng)態(tài)分配一個(gè)int型變量,需預(yù)先定義好一個(gè)int型指針變量
p = new int; //使用new運(yùn)算符動(dòng)態(tài)分配一個(gè)int型變量,將所分配內(nèi)存單元的首地址賦值給指針變量p
*p = 10; //通過(guò)指針變量p間接訪問所分配的內(nèi)存單元照棋,向其中寫入數(shù)據(jù)10
cout<<*p; //通過(guò)指針變量p間接訪問所分配的內(nèi)存單元
delete p; //內(nèi)存使用完后资溃,用delete運(yùn)算符釋放該內(nèi)存空間
上述語(yǔ)句可以簡(jiǎn)化為:
int *p = new int(10); //動(dòng)態(tài)分配變量時(shí)進(jìn)行初始化
cout<<*p; //通過(guò)指針變量p間接訪問所分配的內(nèi)存單元
delete p; //內(nèi)存使用完后,用delete運(yùn)算符釋放該內(nèi)存空間
2烈炭、一維數(shù)組的動(dòng)態(tài)分配與釋放
C++語(yǔ)法:
指針變量名 = new 數(shù)據(jù)類型[整數(shù)表達(dá)式];
delete[]指針變量名溶锭;
語(yǔ)法說(shuō)明:
- 數(shù)據(jù)類型指定動(dòng)態(tài)分配數(shù)組變量的數(shù)據(jù)類型;
- 表達(dá)式指定一維數(shù)組的元素個(gè)數(shù)符隙,用中括號(hào)“[]”括起來(lái)趴捅,表達(dá)式可以是單個(gè)常量、變量或是一個(gè)整數(shù)表達(dá)式霹疫,其結(jié)果必須為正整數(shù)驻售。
- 計(jì)算機(jī)執(zhí)行new運(yùn)算符時(shí)將按照數(shù)據(jù)類型和元素個(gè)數(shù)分配相應(yīng)字節(jié)的內(nèi)存空間,然后返回所分配的內(nèi)存單元的首地址更米,應(yīng)當(dāng)通過(guò)賦值語(yǔ)句將該首地址保存到一個(gè)預(yù)先定義好的同類型指針變量中,特別注意:動(dòng)態(tài)分配的數(shù)組變量不能初始化毫痕;
- 計(jì)算機(jī)執(zhí)行delete運(yùn)算符時(shí)征峦,將按照指針變量中的地址釋放指定的內(nèi)存單元,“[]”表示所釋放的內(nèi)存空間是一個(gè)數(shù)組消请,其中包含多個(gè)內(nèi)存單元栏笆,應(yīng)同時(shí)釋放;
int *p = new int[5]; //動(dòng)態(tài)分配一個(gè)int型一維數(shù)組變量臊泰,包含5個(gè)數(shù)組元素
*(p+1) = 10; //通過(guò)指針運(yùn)算符訪問第1個(gè)元素蛉加,向其中寫入數(shù)據(jù)10
p[1] = 10 //或通過(guò)下標(biāo)運(yùn)算符訪問第1個(gè)元素
cout << *(p+1); //通過(guò)指針運(yùn)算符訪問第1個(gè)元素,讀取其中數(shù)據(jù)10并顯示出來(lái)
cout<<p[1]; //或通過(guò)下標(biāo)運(yùn)算符訪問第1個(gè)元素
delete[]p; //內(nèi)存使用完后缸逃,用delete運(yùn)算符釋放該數(shù)組變量所分配的內(nèi)存空間针饥,將內(nèi)存空間全部釋放
實(shí)列:計(jì)算斐波那契額數(shù)列
#include <iostream>
using namespace std;
int main(){
int N; //定義一個(gè)int變量N
cin >> N; //鍵盤輸入要顯示數(shù)列的前多少項(xiàng),將數(shù)值保存在變量N中
int *p = new int[N]; //動(dòng)態(tài)創(chuàng)建包含N個(gè)元素的數(shù)組需频,用于保存數(shù)列的前N項(xiàng)
p[0] = 0; p[1] = 1; //指定數(shù)列的前2項(xiàng)
int n; //為循環(huán)語(yǔ)句定義好循環(huán)變量n
for(n=2; n<N;n++) //使用循環(huán)結(jié)構(gòu)計(jì)算處剩余的數(shù)列項(xiàng)
p[n] = p[n-1] + p[n-2];//每一項(xiàng)等于其前2項(xiàng)之和
for(n=0; n<N;n++) //使用循環(huán)結(jié)構(gòu)遍歷顯示數(shù)組
{
cout << p[n] << ","; //各數(shù)列項(xiàng)用逗號(hào)隔開
if((n+1)%5 == 0) cout<<endl; //一行顯示5項(xiàng)丁眼,每5項(xiàng)一次換行
}
delete[]p; //數(shù)組使用結(jié)束,動(dòng)態(tài)釋放其內(nèi)存空間
return 0;
}
三昭殉、字符類型
計(jì)算機(jī)只能儲(chǔ)存和處理數(shù)值類型的數(shù)據(jù)苞七,為了進(jìn)行文字處理,計(jì)算機(jī)需要講文字字符轉(zhuǎn)換成字符編碼挪丢,這樣文字處理問題蹂风,就轉(zhuǎn)換成了數(shù)值計(jì)算問題,字符編碼需要遵循統(tǒng)一的標(biāo)準(zhǔn)乾蓬,需要考慮以下兩個(gè)方面的內(nèi)容:
- 字符集
- 編碼值
3.1 字符集
首先要確定有那些字符惠啄,然后確定每個(gè)字符的編碼值,早期的計(jì)算機(jī)只考慮英文處理,因此ASCII字符編碼只收錄了阿拉伯?dāng)?shù)字礁阁、英文字母巧号、常用符號(hào)、控制字符等英文處理要用到的字符共計(jì)128個(gè)姥闭,分別用0-127來(lái)表示這128個(gè)字符丹鸿,可以用一個(gè)字節(jié),就是8位來(lái)儲(chǔ)存一個(gè)字符編碼棚品,ASCII編碼的特點(diǎn)如下:
- 阿拉伯?dāng)?shù)字0-9按從小到大的順序連續(xù)編碼
- 英文字母也按照字母順序連續(xù)編碼
- 大小寫字母分別編碼靠欢,小寫字母的碼值比大寫字母大32
- 0表示一種特殊字符,統(tǒng)稱為控字符铜跑。
c++語(yǔ)言通過(guò)字符類型來(lái)存儲(chǔ)字符編碼门怪,這個(gè)編碼是一個(gè)單字節(jié)整數(shù),c++語(yǔ)言講字符類型和單字節(jié)整數(shù)類型合二為一锅纺,統(tǒng)稱為:char類型掷空,占用1個(gè)字節(jié)。char更多的時(shí)候都是用來(lái)保存字符的囤锉,因此將char類型稱為字符型坦弟。一個(gè)字符型變量可以保存一個(gè)字符,保存的是該字符的ASCII碼值官地。
字符型常量:
指的是某個(gè)特定的字符酿傍,用單引號(hào)‘ ’括起來(lái),例如:'a'驱入、'?'等赤炒,
char ch;
ch = 'M';//等價(jià)于:ch=77,因?yàn)榇髮懽帜窶的ASCII值等于77
但是在ASCII字符集中含有33個(gè)不可見的控制字符,它們無(wú)法用單引號(hào)的形式來(lái)書寫亏较,例如Esc鍵(ASCII=27)莺褒,在C++語(yǔ)言中可以使用16進(jìn)制或8進(jìn)制的ASCII值來(lái)書寫這些不可見的字符常量,書寫時(shí)需要用到轉(zhuǎn)義字符反斜杠\
/*例如Esc鍵宴杀,ASCII=27*/
char ch;
ch = '\x1B'; //Esc的ASCII碼16進(jìn)制為1B
ch = '\33'; //Esc的ASCII碼8進(jìn)制為33
這種書寫字符常量的方式癣朗,我們稱為轉(zhuǎn)義字符,反斜杠是轉(zhuǎn)義字符的標(biāo)記.旺罢】跤啵可見字符也可以使用轉(zhuǎn)義的形式進(jìn)行書寫,例如'M'扁达,轉(zhuǎn)義形式:'\x4D'正卧、'\115',為了方便程序員跪解,c++語(yǔ)言還預(yù)定義了一些常用的轉(zhuǎn)義字符常量:
轉(zhuǎn)移字符 | 含義 | 注釋 |
---|---|---|
\0 | 空字符 | ASCII碼值:0 |
\a | 響鈴 | ASCII碼值:7 |
\b | 退格 | ASCII碼值:8 |
\t | 水平制表符 | ASCII碼值:9 |
\n | 換行炉旷,等價(jià)于endl | ASCII碼值:10 |
\v | 垂直制表符(打印機(jī)有效) | ASCII碼值:11 |
\r | 回車 | ASCII碼值:13 |
\' | 單引號(hào) | 被賦予了特殊含義,需轉(zhuǎn)義恢復(fù)其原來(lái)含義 |
\" | 雙引號(hào) | 被賦予了特殊含義,需轉(zhuǎn)義恢復(fù)其原來(lái)含義 |
\\ | 反斜杠 | 被賦予了特殊含義窘行,需轉(zhuǎn)義恢復(fù)其原來(lái)含義 |
3.2 字符型運(yùn)算
可以對(duì)字符型數(shù)據(jù)進(jìn)行算術(shù)運(yùn)算饥追,運(yùn)算時(shí),將字符的ASCII碼值作為整數(shù)參數(shù)參與運(yùn)算罐盔。
#include <iostream>
using namespace std;
int main(){
char ch='A';
for(int n=1; n<=26; n++) //利用循環(huán)結(jié)構(gòu)但绕,顯示26個(gè)英文字母
{
cout << ch; //根據(jù)ch中的ASCII值,將結(jié)構(gòu)打印出來(lái)
ch++; //將保存的ASCII值加1惶看,顯示下一個(gè)字母
}
cout << "\n"; //等價(jià)于cout<<endl;
return 0;
}
可以對(duì)字符型數(shù)據(jù)進(jìn)行關(guān)系運(yùn)算捏顺,運(yùn)算時(shí)將字符的ASCII碼值作為整數(shù)進(jìn)行比較,比較其大小纬黎,其實(shí)是在比較其ASCII碼值的大小幅骄。
實(shí)例
#include <iostream>
using namespace std;
int main(){
char ch;
cout << "請(qǐng)輸入:";
cin >>ch;
if(ch>='0'&&ch<='9')
cout << "您輸入的是數(shù)字"<< endl;
else if(ch>='a' && ch<='z')
cout<<"您輸入的是小寫字母"<< endl;
else if(ch>='A'&&ch<='Z')
cout<<"您輸入的是大寫字母"<< endl;
else
cout<<"您輸入的是其他鍵"<< endl;
cout<<"該字符的ASCII值="<<(int)ch<<endl;
return 0;
}
四、字符數(shù)組與文字處理
一個(gè)字符變量可以保存一個(gè)字節(jié)本今,而要保存一片文字就是一組字符拆座,我們就需要使用字符類型的數(shù)組變量,簡(jiǎn)稱字符數(shù)組冠息。
一個(gè)單詞懂拾,一句話,一篇文章都是一種由字符組成的序列铐达,我們稱為字符串。
c++語(yǔ)言使用字符數(shù)組來(lái)保存字符串檬果,對(duì)字符串的處理主要包括:復(fù)制瓮孙、連接、插入和刪除等等选脊。
用雙引號(hào)“ ”括起來(lái)的字符序列杭抠,被稱為字符串常量,例如:“china”恳啥、“P”等等偏灿,計(jì)算機(jī)會(huì)為c++程序中的字符串常量分配內(nèi)存空間,并自動(dòng)在末尾添加控制符0作為結(jié)束標(biāo)記钝的,存儲(chǔ)一個(gè)字符串常量所需內(nèi)存空間的字節(jié)數(shù)等于字符個(gè)數(shù)加一翁垂,就是加一個(gè)結(jié)束標(biāo)記。例如“china”硝桩,總共5個(gè)字符沿猜,加上末尾的控制符0,共計(jì)6個(gè)字節(jié)來(lái)儲(chǔ)存china碗脊。
在c++語(yǔ)言中單引號(hào)‘ ’和雙引號(hào)“ ”是不同的概念啼肩,單引號(hào)只能括起單個(gè)字符,表示字符常量,包含多個(gè)字符的字符串常量必須使用雙引號(hào)祈坠。單個(gè)字符加上雙引號(hào)會(huì)被當(dāng)做字符串進(jìn)行處理害碾。例如:“A”,在存儲(chǔ)時(shí)會(huì)在末尾加上控制符0赦拘,占用2個(gè)字節(jié)的內(nèi)存慌随。
4.1 字符串常量
可以將一個(gè)字符串常量賦值給一個(gè)字符型指針變量,其含義是將字符串常量在內(nèi)存單元中的首地址賦值給字符型指針變量另绩。
char *p;
p = "china"; //將china在內(nèi)存中的首地址賦值給p儒陨,或者說(shuō)p指向china在內(nèi)存中的首地址
字符串常量可以包含轉(zhuǎn)義字符浦旱,c++語(yǔ)言中傀蚌,反斜杠,單引號(hào)露乏,雙引號(hào)车海,被賦予了特殊含義笛园,如果我們需要顯示這些符號(hào),需要在前面添加反斜杠侍芝。舉例:
cout<<"Yes\nNo"; //輸出結(jié)果為:Yes換行No
cout<<"\"Yes\",\'No\'"; //輸出為:"Yes",'No'
4.2 字符數(shù)組
可以定義字符數(shù)組來(lái)保存字符串研铆,定義字符數(shù)組時(shí),可以使用字符常量初始化數(shù)組元素州叠,
char str[10] = {'C','h','i','n','a'};//使用'C','h','i','n','a'初始化前5個(gè)常量棵红,剩余元素自動(dòng)初始化為'0'
char str[] = {'C','h','i','n','a'};//c++會(huì)自動(dòng)將下標(biāo)設(shè)為5
定義字符數(shù)組時(shí),若沒有給出下標(biāo)的值咧栗,c++語(yǔ)言會(huì)根據(jù)初始值的個(gè)數(shù)逆甜,自動(dòng)給出下標(biāo)。定義字符數(shù)組時(shí)致板,也可以使用字符串常量來(lái)初始化元素交煞。
char str[10]="china"; //使用字符串初始化字符數(shù)組的前5個(gè)元素
char str[]="china";//此時(shí)下標(biāo)自動(dòng)設(shè)為6,因?yàn)樽址A坑幸粋€(gè)結(jié)束的下標(biāo)0
char str[3][10]={"Tom","John","Mary"};
4.3 字符數(shù)組的整體輸入/輸出
通常斟或,cin和cout只能輸入/輸出單個(gè)元素素征,因此數(shù)組整體輸入輸出需要使用循環(huán)結(jié)構(gòu)逐個(gè)輸入/輸出各數(shù)組元素。
但c++語(yǔ)言對(duì)cin/cout指令做了特殊處理萝挤,對(duì)字符型數(shù)組可以直接整體輸出/輸出御毅,從而簡(jiǎn)化了字符數(shù)組的輸入輸出。
char str[10];cin>>str; //可以使用cin一次性整體輸入str怜珍,而不使用循環(huán)
cout<<str;
需要注意的是亚享,在鍵盤輸入時(shí)不能超過(guò)字符數(shù)組定義的長(zhǎng)度,否則會(huì)出現(xiàn)越界錯(cuò)誤绘面。輸出時(shí)欺税,從第0個(gè)字符開始依次輸出侈沪,到空字符時(shí)結(jié)束,空字符是字符串結(jié)束的標(biāo)記晚凿。
4.4 指針變量輸出
如果指針變量保存了另外某個(gè)變量的地址亭罪,可以用cout來(lái)顯示該地址值,但是對(duì)字符型指針變量歼秽,cout語(yǔ)句會(huì)有一些不同的處理应役,實(shí)例如下:
/*通過(guò)cout輸出int型指針變量時(shí),輸出的時(shí)指針變量指向的變量?jī)?nèi)存地址的值*/
int x,*p=&x;cout<<p<<endl; //此時(shí)結(jié)果顯示的是x的內(nèi)存地址
/*通過(guò)cout輸出字符型指針變量時(shí)燥筷,輸出的結(jié)果是該字符型指針變量指向的字符串的值*/
char str[10]="China";
char *p = str;
cout<<p<<endl; //顯示結(jié)果:China
cout<<p+2<<endl; //顯示結(jié)果:ina
cout<<(int *)p<<endl;//強(qiáng)制轉(zhuǎn)換字符型指針變量為int型指針變量箩祥,即可得到該變量所指向的內(nèi)存地址值
通過(guò)cout輸出字符型指針變量時(shí),輸出的結(jié)果是該字符型指針變量指向的字符串的值肆氓。如果想顯示字符型指針變量中保存的地址值袍祖,需要將字符型指針強(qiáng)制轉(zhuǎn)換為其他類型指針。
實(shí)例:求字符串中字符的長(zhǎng)度
#include <iostream>
using namespace std;
int main(){
char str[10]="China";
int n=0;
while(str[n]!='\0') //通過(guò)循環(huán)結(jié)構(gòu)谢揪,從0開始判斷是否是結(jié)束符'\0' n++; //如果不是結(jié)束符'\0'蕉陋,將下標(biāo)加一
cout<<n<<endl;
return 0;
}
實(shí)例:在字符串中插入字符串
#include <iostream>
using namespace std;
int main(){
char str[10]="Chna";
char ch='i'; //要插入的字符
char oldch; //該變量的作用是保存上一次時(shí),撤入位置后面的字符串
int n=2; //確定要插入的位置
do
{
oldch=str[n];//把當(dāng)前位置的原來(lái)的字符先保存起來(lái)拨扶,以便后移
str[n]=ch; //將ch保存到當(dāng)前位置
ch = oldch; //將oldch保存的字符轉(zhuǎn)存到ch中凳鬓,在一次循環(huán)時(shí)進(jìn)行插入
n++; //轉(zhuǎn)入下一位置,循環(huán)插入
}while(ch!='\0'); //若ch保存的值是結(jié)束符患民,停止操作
str[n]='\0'; //為插入操作后的字符串添加結(jié)束符'\0'
cout<<str<<endl; //顯示結(jié)果為China return 0;}
實(shí)例:字符串拷貝
#include <iostream>
using namespace std;
int main(){
char str1[10]="China";
char str2[20];//要考入的字符數(shù)組要大于原數(shù)組缩举,否則會(huì)導(dǎo)致越界錯(cuò)誤
int n=0;
while (str1[n]!='\n')
{
str2[n]=str1[n];//拷貝第n個(gè)元素
n++; //下標(biāo)加1,繼續(xù)拷貝下一個(gè)元素
}
str2[n]='\0';//為字符串str2添加結(jié)束符'\0'
cout<<str2<<endl;//顯示拷貝的字符串
return 0;
}
五匹颤、中文處理
計(jì)算機(jī)要處理中文蚁孔,要滿足3個(gè)方面的條件,
-
漢字字符編碼標(biāo)準(zhǔn)惋嚎,例如GB2312
為處理中文,我們首先要制定漢字字符處理標(biāo)準(zhǔn)站刑,GB2312就是我們國(guó)家制定的國(guó)標(biāo)另伍。
-
需要一個(gè)支持中文編碼標(biāo)準(zhǔn)的操作系統(tǒng),例如中文Windows
中文操作系統(tǒng)應(yīng)該能夠提供漢字輸入法绞旅,以及顯示或者打印用的漢字庫(kù)摆尝,
-
需要支持中文處理的中文應(yīng)用軟件,例如中文word
用戶使用應(yīng)用軟件來(lái)處理文字
前兩項(xiàng)是中文處理的基礎(chǔ)因悲,有了這個(gè)基礎(chǔ)堕汞,程序員才能編寫中文處理軟件。程序員在使用c++語(yǔ)言編寫程序時(shí)晃琳,可以在c++語(yǔ)言中直接編寫中文字符串常量讯检。
演示程序:
#include <iostream>
using namespace std;
int main(){
char str1[]="China"; //英文字符串
char str2[]="中國(guó)"; //中文字符串
char str3[]="China,中國(guó)"; //中英文混合
cout<<str1<<endl;
cout<<str2<<endl;
cout<<str3<<endl;
return 0;
}
中文字符串和英文字符串在使用上沒有什么區(qū)別琐鲁,但是由于漢字字符串的編碼標(biāo)準(zhǔn)與英文字符不同,漢字字符在存儲(chǔ)和算法上人灼,也會(huì)因此有所不同围段,為了編寫中文處理軟件,程序員需要深入理解漢字字符的編碼方法投放。
5.1 字符編碼標(biāo)準(zhǔn)
ASCII碼是一個(gè)種英文的編碼標(biāo)準(zhǔn)奈泪,ASCII的字符集包含以英文字母為主的128個(gè)文字符號(hào),只能用于英文處理灸芳。為了處理本國(guó)語(yǔ)言涝桅,各個(gè)國(guó)家和地區(qū)分別制定了本國(guó),或本地區(qū)的編碼標(biāo)準(zhǔn)烙样。
漢字編碼首先要確定有哪些漢字字符冯遂,及字符集,然后再確定每個(gè)漢字字符的編碼值误阻,ASCII使用單字節(jié)也就是8位編碼债蜜,只有256個(gè)碼值,最多只能為256個(gè)字符編碼究反,而漢字有幾萬(wàn)個(gè)字符寻定,常用的有數(shù)千個(gè),因此漢字編碼需要使用雙字節(jié)精耐,也就是16位編碼狼速,理論上雙字節(jié)編碼可以提供6萬(wàn)多個(gè)字符編碼,
- ASCII編碼:?jiǎn)巫止?jié)字符集
- 漢字編碼:雙字節(jié)字符集
日文和韓文和中文的處理方式類似卦停,國(guó)際上通常將這3種文字稱為CJK向胡,就是中文、日文惊完、韓文的首字母縮寫僵芹。
ANSI編碼:
操作系統(tǒng)提供文字處理相關(guān)的輸入法,編碼小槐,顯示和打印字符的相關(guān)基礎(chǔ)功能拇派,通常,操作系統(tǒng)可以同時(shí)處理英文凿跳,和一種非英語(yǔ)文字件豌,例如中文版windows可以同時(shí)處理中文和英文。英文符號(hào)使用單字節(jié)ASCII編碼控嗜,而非英文符號(hào)茧彤,則分別使用各國(guó)自己制定的雙字節(jié)編碼標(biāo)準(zhǔn),這種混合編碼標(biāo)準(zhǔn)被稱為ANSI編碼
Unicode編碼:
基于ANSI編碼標(biāo)準(zhǔn)的計(jì)算機(jī)存在一個(gè)缺陷疆栏,就是只能英文可以和其他語(yǔ)種混用曾掂,因此開發(fā)多語(yǔ)種軟件時(shí)惫谤,需要開發(fā)時(shí),需要分別開發(fā)多個(gè)語(yǔ)種的不同版本遭殉,例如中文版石挂、日文版、俄語(yǔ)版等等险污。為了解決這個(gè)問題痹愚,相關(guān)國(guó)際組織制定了新的統(tǒng)一的編碼標(biāo)準(zhǔn),稱為Unicode編碼標(biāo)準(zhǔn)蛔糯。該編碼標(biāo)準(zhǔn)將世界上主要的語(yǔ)言文字合在一起拯腮,構(gòu)建了一個(gè)大的字符集,然后統(tǒng)一進(jìn)行編碼蚁飒,可以實(shí)現(xiàn)多語(yǔ)種混用动壤,未來(lái)開發(fā)軟件,應(yīng)當(dāng)基于Unicode編碼標(biāo)準(zhǔn)進(jìn)行開發(fā)淮逻,這樣可以更方便的推廣到全球市場(chǎng)琼懊。
一個(gè)計(jì)算機(jī)程序是否支持中文處理,有2層含義:
- 是否具有適合中國(guó)用戶的中文界面
- 是否需要處理中文爬早,例如對(duì)中文字符串的插入哼丈、刪除等操作。
為了編寫中文處理軟件筛严,程序員需要深入理解漢字字符的編碼標(biāo)準(zhǔn)醉旦,為了處理中文,首先需要建立中文文字的處理標(biāo)準(zhǔn)桨啃,中文編碼標(biāo)準(zhǔn)首先要確定有哪些字符车胡,就是字符集,然后再確定每個(gè)字符的編碼值照瘾,1980年中國(guó)國(guó)家標(biāo)準(zhǔn)總局匈棘,發(fā)布了GB2312標(biāo)準(zhǔn),共計(jì)6763個(gè)常用漢字和一些圖形符號(hào)析命,1995年主卫,全國(guó)信息技術(shù)標(biāo)準(zhǔn)化委員會(huì)對(duì)該編碼標(biāo)準(zhǔn)進(jìn)行了擴(kuò)充,制定了漢字內(nèi)碼擴(kuò)展規(guī)范碳却,也就是目前使用的GBK編碼,共計(jì)21000個(gè)漢字和圖形符號(hào)笑旺,同時(shí)還收錄了藏文昼浦、蒙文、維吾爾文等少數(shù)民族文字筒主,現(xiàn)在的Windows操作系統(tǒng)都至此GBK編碼关噪,某些嵌入式系統(tǒng)可能還在使用GB2312標(biāo)準(zhǔn)鸟蟹。
基于ANSI標(biāo)準(zhǔn)的中文Windows操作系統(tǒng)包含2套字符集,一套是ASCII碼字符集使兔,采用單字節(jié)存儲(chǔ)建钥,碼值范圍是0-127,ASCII只使用了7位虐沥,因此再存儲(chǔ)ASCII碼時(shí)字節(jié)的最高位都為0熊经,另外一套字符集就是GBk編碼字符集,它使用雙字節(jié)存儲(chǔ)欲险,其中第一個(gè)字節(jié)稱為前導(dǎo)字節(jié)镐依,存儲(chǔ)時(shí)這個(gè)字節(jié)的最高位都為1,c++程序可以根據(jù)字節(jié)的最高進(jìn)行判斷字符的類型天试,最高位為0槐壳,表示為ASCII碼字符,是1則表示是GBK字符喜每。
1务唐、基于ANSI的中文處理程序
在c++語(yǔ)言種,中文字符串和英文字符串在以下幾個(gè)方面是完全一樣的:
- 都使用字符數(shù)組來(lái)儲(chǔ)存
- 都使用空字符串'\0'作為字符串結(jié)束標(biāo)記
- 都可以使用cin指令直接從鍵盤輸入带兜,并保持到某個(gè)字符數(shù)組中
- 都可以使用cout指令枫笛,將保存在某個(gè)字符數(shù)組中的字符串輸出到顯示器上
c++語(yǔ)言只支持雙引號(hào)括起來(lái)的中文字符串常量,不支持單引號(hào)括起來(lái)的字符串常量鞋真,例如:"中"是正確的崇堰,但是‘中’,這種寫法是非法的涩咖。
實(shí)例:篩選中文字符串
#include <iostream>
using namespace std;
int main(){
char str[20];
cout << "請(qǐng)輸入一個(gè)中英文混合的字符串長(zhǎng)度不能超過(guò)20個(gè):";
cin >> str;
char cstr[20]; //用于保存篩選的字符串海诲,長(zhǎng)度必須大于或等于輸入的字符串,避免越界錯(cuò)誤
int n,ch; //n表示str的下標(biāo)檩互,ch表示cstr的下標(biāo)
n=0;ch=0;
while(str[n]!='\0')
{
if((str[n]& 0x80) != 0) //通過(guò)位與運(yùn)算來(lái)檢查當(dāng)前字節(jié)最高位是否為0特幔,0x80掩碼是一個(gè)最高位為1的掩碼,其他7位為0闸昨。
{
cstr[ch] = str[n] ;cstr[ch+1] = str[n+1];//因?yàn)橹形淖址鎯?chǔ)為雙字節(jié)蚯斯,故要復(fù)制2個(gè)相鄰字節(jié)的數(shù)據(jù)
ch+=2; n+=2; //下標(biāo)加2,轉(zhuǎn)到下一個(gè)字符元素饵较。
}
else
n++; //若不是中文字符拍嵌,就執(zhí)行n+1的操作,因?yàn)橛⑽淖址鎯?chǔ)占1個(gè)字節(jié)
}
cstr[ch] = '\0';
cout << "您輸入的復(fù)合字符串中包含的中文有:"<<cstr<<endl;
return 0;
}
2循诉、基于Unicode編碼的中文處理
Unicode字符集也叫通用字符集横辆,目前已經(jīng)收錄超過(guò)10萬(wàn)個(gè)字符,Unicode編碼中的ASCII碼值是一樣的茄猫,但是其中包含的GBK碼值不一樣狈蚤。不同的操作系統(tǒng)存儲(chǔ)一個(gè)Unicode字符所需要的位數(shù)是不一樣的困肩,例如32位的Windows操作系統(tǒng)和VC 6.0存儲(chǔ)的一個(gè)Unicode字符需要2個(gè)字節(jié),而Linux操作系統(tǒng)和java語(yǔ)言需要4個(gè)字節(jié)脆侮,這是因?yàn)樗麄儗?duì)Unicode編碼實(shí)現(xiàn)方式不同锌畸,Unicode編碼主要有3種實(shí)現(xiàn)方式:utf-8、utf-16靖避、utf-32潭枣,其中utf表示Unicode的轉(zhuǎn)換個(gè)數(shù), 而8筋蓖、16卸耘、32表示儲(chǔ)存位數(shù)。
utf-32:位使用4個(gè)字節(jié)儲(chǔ)存Unicode編碼粘咖,utf-32格式是定長(zhǎng)編碼蚣抗,簡(jiǎn)單直接,但占用儲(chǔ)存空間多
utf-8:格式瓮下,將Unicode編碼劃分為4個(gè)空間翰铡,分別進(jìn)行再編碼,最后形成一種變長(zhǎng)編碼讽坏,其長(zhǎng)度從1-4個(gè)字節(jié)不等锭魔,使用utf-8編碼,儲(chǔ)存一個(gè)英文字符只需呀一個(gè)字節(jié)路呜,而漢字字符迷捧,可能需要3-4個(gè)字節(jié),這種變長(zhǎng)編碼會(huì)增加文字算法的復(fù)雜性胀葱,比如插入和刪除操作漠秋。
utf-16:是一種介于utf-8和utf-32之間的一種格式,不管中文還是英文抵屿,儲(chǔ)存一個(gè)字符都是2個(gè)字節(jié)庆锦,這是一種定長(zhǎng)編碼,基于定長(zhǎng)編碼的文字處理算法比較簡(jiǎn)單轧葛,VC 6.0使用的是utf-16格式搂抒,來(lái)儲(chǔ)存Unicode編碼。
c++語(yǔ)言將Unicode編碼稱為寬字符類型尿扯,并專門定義了wchar_t關(guān)鍵字求晶,在vc 6.0中,寬字節(jié)字符類型占用2個(gè)字節(jié)衷笋,并按無(wú)符號(hào)的格式儲(chǔ)存Unicode編碼芳杏,c++語(yǔ)言用大寫的字母'L',來(lái)指定寬字符類型常量和寬字符串常量,類如:'a'是一個(gè)字符串常量蚜锨,而L'a'是一個(gè)寬字符常量,L'中國(guó)'是一個(gè)寬字符串常量慢蜓。編譯程序時(shí)亚再,vc 6.0編譯器會(huì)將寬字符常量轉(zhuǎn)換為uft-16格式,并取寬字符常量和寬字符串常量的結(jié)束控制符也是2個(gè)字節(jié)晨抡,也就是兩個(gè)'\0'氛悬。
語(yǔ)法:
wchar_t wch=L'中'; //占用2個(gè)字節(jié)。
wchar_t wstr[]=L"中國(guó)abc"; //此時(shí)占用12個(gè)字節(jié)耘柱,無(wú)論英文如捅、中文還是結(jié)束控制符都占用2個(gè)字節(jié),編譯后下標(biāo)格式自動(dòng)設(shè)為6
基于定長(zhǎng)編碼的文字處理算法比較簡(jiǎn)單调煎,
實(shí)例:刪除字符串中某個(gè)字符
#include <iostream>
#include <locale.h>
#include <locale>
#include <io.h>
#include <fcntl.h>
using namespace std;
int main(){
wchar_t wstr[20]=L"中國(guó)abc";
int n; //定義號(hào)wste所需的下標(biāo)镜遣,變量位n
n = 2; //刪除數(shù)組wstr中的字符‘a(chǎn)’,其下標(biāo)為2
while(wstr[n] != L'\0') //寬空字符L'\0'時(shí)寬字符的結(jié)束標(biāo)記
{
wstr[n] = wstr[n+1]; //將其后面的字符往前移一位
n++; //下標(biāo)加1士袄,轉(zhuǎn)到下一個(gè)字符
}
_setmode(_fileno(stdout), _O_U16TEXT);
wcout<<wstr<<endl; //顯示寬字符串時(shí)改用wcout指令
return 0;
}
wcout:
輸出寬字符串需改用wcout指令悲关,wcout指令在顯示中文時(shí),首先將Unicode編碼轉(zhuǎn)換為GBK編碼娄柳,然后再顯示GBK編碼的中文字符寓辱。使用wcout指令前,需將語(yǔ)言設(shè)置為中文簡(jiǎn)體赤拒,即GBK編碼秫筏。
wcin
輸入寬字符串需要改用wcin指令,wcin指令再輸入中文時(shí)挎挖,先轉(zhuǎn)換成GBK編碼这敬,然后將GBK編碼轉(zhuǎn)換成Unicode編碼,使用wcout指令前肋乍,需將語(yǔ)言設(shè)置為中文簡(jiǎn)體鹅颊,即GBK編碼。