C語(yǔ)言中二維字符數(shù)組的定義和初始化
一般來(lái)說(shuō),我們可能會(huì)希望定義一個(gè)二維字符數(shù)組并且在定義的時(shí)候就用一些字符串來(lái)初始化它。比如說(shuō):
Code:
1.char testcase[30][MAX_LENGTH]
= {"jo","vicent","tom","honey","gigi","lily","susan","peter","bob","ron",
2. "jason","henry","kiki","ken","auscar","vivian","yiyi","peace","iron","lotus"
3. "andy","arta","ophone","denial","pipe","wade","james","kobe","kent","angel"};
通常使用二維字符數(shù)組是為了在程序中存儲(chǔ)一些字符串關(guān)鍵字。用這樣的方式來(lái)初始化就最簡(jiǎn)單不過(guò)了。其中,MAX_LENGTH是所有字符串中最大的長(zhǎng)度。當(dāng)然不能忘記'\0'了。
而定義一個(gè)字符二維數(shù)組,C也提供了簡(jiǎn)潔的方式,如果我不想統(tǒng)計(jì)字符串的長(zhǎng)度,我還可以這樣定義:
Code:
1.char *testcase[30] = {"jo","vicent","tom","honey","gigi","lily","susan","peter","bob","ron",
2. "jason","henry","kiki","ken","auscar","vivian","yiyi","peace","iron","lotus"
3. "andy","arta","ophone","denial","pipe","wade","james","kobe","kent","angel"};
也就是說(shuō),可以不再數(shù)組定義的時(shí)候指定字符串的長(zhǎng)度,但是注意字符串的個(gè)數(shù)是一定要指定的,像這樣寫(xiě) char **testcase = ... 是不行的,不過(guò)肯定不行了,因?yàn)?span style="margin: 0px; padding: 0px; word-wrap: break-word;" lang="EN-US">int *pt=3 也不行,呵呵,這兩個(gè)例子是一個(gè)道理啊。
我覺(jué)得肯定是人都喜歡第二種初始化方法了,而且它還有一個(gè)優(yōu)點(diǎn),起碼對(duì)喜歡用指針的同志來(lái)說(shuō)是一個(gè)大優(yōu)點(diǎn)。就是可以將這樣定義的指針賦給一個(gè)二維指針,比如
char **pointer = testcase;
想形式1的定義方法肯定不能這樣賦值了。
不過(guò)非常非常值得注意的是,上面定義的兩個(gè)指針,一個(gè)一維,一個(gè)二維,他們必須在const關(guān)鍵字上一致,意思就是說(shuō)如果定義testcase前面加了const關(guān)鍵字,定義pointer時(shí)也必須加上,否則就會(huì)報(bào)錯(cuò):
error C2440: 'initializing' : cannot convert from 'char *[30]' to 'const char **
在寫(xiě)這篇 日志的過(guò)程中,我突然想到一個(gè)問(wèn)題,就似乎利用上面的方法二初始化二維字符串?dāng)?shù)組之中,字符串是如何分布的呢?因?yàn)樽址拈L(zhǎng)度是不相等的,完全由編譯器 來(lái)計(jì)算,那么它是會(huì)按照最長(zhǎng)的字符串來(lái)定制字符數(shù)組的長(zhǎng)度,還是讓每一個(gè)字符串?dāng)?shù)組都按照自身的大小來(lái)占據(jù)內(nèi)存,靠'\0'來(lái)識(shí)別結(jié)尾呢?
二維字符串?dāng)?shù)組的初始化-動(dòng)態(tài)內(nèi)存分配
昨天在用FBS200指紋采集芯片采集到一個(gè)二維數(shù)組數(shù)據(jù)后,利用串口傳輸上來(lái)的數(shù)據(jù)是以十六進(jìn)制的數(shù)據(jù)格式表示的二維矩陣,比如“FF”、“BD”、“5C”等等這樣的形式,而對(duì)于一幅灰度圖像,一般都是在0~255之間的數(shù)據(jù)來(lái)表示其亮度值,因此想通過(guò)二維字符串?dāng)?shù)組來(lái)對(duì)采集過(guò)來(lái)的數(shù)據(jù)進(jìn)行轉(zhuǎn)化顯示。但在動(dòng)態(tài)分配一個(gè)char **str;str=new char*[128];之后對(duì)其進(jìn)行初始化時(shí),總是出現(xiàn)錯(cuò)誤,不知道如何才能很好的對(duì)其賦值,還得深入學(xué)習(xí)一下。
其實(shí)對(duì)一個(gè)字符的轉(zhuǎn)化很容易,但對(duì)一個(gè)字符串形式的字符來(lái)轉(zhuǎn)化,而且是對(duì)一個(gè)多維數(shù)組來(lái)轉(zhuǎn)化就有點(diǎn)吃力了。首先建立一個(gè)多維字符串?dāng)?shù)組,這里是二維的字符串?dāng)?shù)組,程序如下所示:
#i nclude "stdio.h"
void main()
{
char *str1[2][2]={"FF","F9","FA","F9"};//初始化一個(gè)二維字符串?dāng)?shù)組
char *str;//定義一個(gè)一維字符串變量
int a,b;
int i,j;
int result1;
for (i=0;i<2;i++)
{
for (j=0;j<2;j++)
{
str=str1[i][j];//對(duì)一維字符串賦值
printf("%s\n",str);
if(str[0]>='A' && str[1]>='A')
{
a=int(str[0]-'A');
b=int(str[1]-'A');
result1=(a+10)*16+(b+10)*1;//“AA”~“FF”之間的轉(zhuǎn)化結(jié)果
}
else if (str[0]>='A' && str[1]<'A')
{
a=int(str[0]-'A');
b='A'-str[1]+1;
result1=(a+10)*16+b;//“A0”~“F9”之間的轉(zhuǎn)化結(jié)果
}
else if (str[0]<'A' && str[1]>='A')
{
a='A'-str[0]+1;
b=int(str[1]-'A');
result1=a*16+(b+10)*1;//“0A”~“9F”之間的轉(zhuǎn)化結(jié)果
}
else
{
a='A'-str[0]+1;
b='A'-str[1]+1;
result1=a*16+b;//“00”~“99”之間的轉(zhuǎn)化結(jié)果
}
printf("a=%d\n",a);
printf("b=%d\n",b);
printf("%d\n",result1);
}
}
}
這里只是用2×2的字符串?dāng)?shù)組做了一個(gè)實(shí)驗(yàn),一幅圖像都是比較大的,這樣在對(duì)數(shù)組初始化時(shí)會(huì)占用很多的內(nèi)存,這樣有時(shí)會(huì)造成編譯無(wú)法通過(guò),昨天就很有幾次死機(jī),當(dāng)時(shí)只是用到64×64的數(shù)組。后來(lái)把數(shù)組的初始化放到main的外面,作為全局變量,在棧中靜態(tài)的分配一塊內(nèi)存空間,雖然可行,但也很占內(nèi)存,于是想到了在函數(shù)中動(dòng)態(tài)分配內(nèi)存,對(duì)動(dòng)態(tài)分配內(nèi)存又重新學(xué)習(xí)了一遍,不了解的可以和我一起學(xué)習(xí)一下。
動(dòng)態(tài)內(nèi)存分配
1.堆內(nèi)存分配 :
C/C++定義了4個(gè)內(nèi)存區(qū)間:代碼區(qū),全局變量與靜態(tài)變量區(qū),局部變量區(qū)即棧區(qū),動(dòng)態(tài)存儲(chǔ)區(qū),即堆(heap)區(qū)或自由存儲(chǔ)區(qū)(free store)。
堆的概念:
通常定義變量(或?qū)ο螅,編譯器在編譯時(shí)都可以根據(jù)該變量(或?qū)ο螅┑念愋椭浪鑳?nèi)存空間的大小,從而系統(tǒng)在適當(dāng)?shù)臅r(shí)候?yàn)樗麄兎峙浯_定的存儲(chǔ)空間。這種內(nèi)存分配稱為靜態(tài)存儲(chǔ)分配;
有些操作對(duì)象只在程序運(yùn)行時(shí)才能確定,這樣編譯時(shí)就無(wú)法為他們預(yù)定存儲(chǔ)空間,只能在程序運(yùn)行時(shí),系統(tǒng)根據(jù)運(yùn)行時(shí)的要求進(jìn)行內(nèi)存分配,這種方法稱為動(dòng)態(tài)存儲(chǔ)分配。所有動(dòng)態(tài)存儲(chǔ)分配都在堆區(qū)中進(jìn)行。
當(dāng)程序運(yùn)行到需要一個(gè)動(dòng)態(tài)分配的變量或?qū)ο髸r(shí),必須向系統(tǒng)申請(qǐng)取得堆中的一塊所需大小的存貯空間,用于存貯該變量或?qū)ο。?dāng)不再使用該變量或?qū)ο髸r(shí),也就是它的生命結(jié)束時(shí),要顯式釋放它所占用的存貯空間,這樣系統(tǒng)就能對(duì)該堆空間進(jìn)行再次分配,做到重復(fù)使用有限的資源。
2.堆內(nèi)存的分配與釋放
堆空間申請(qǐng)、釋放的方法:
在C++中,申請(qǐng)和釋放堆中分配的存貯空間,分別使用new和delete的兩個(gè)運(yùn)算符來(lái)完成:
指針變量名=new 類型名(初始化式);
delete 指針名;
例如:
1、 int *pi=new int(0);
它與下列代碼序列大體等價(jià):
2、int ival=0, *pi=&ival;
區(qū)別:pi所指向的變量是由庫(kù)操作符new()分配的,位于程序的堆區(qū)中,并且該對(duì)象未命名!
堆空間申請(qǐng)、釋放說(shuō)明:
⑴.new運(yùn)算符返回的是一個(gè)指向所分配類型變量(對(duì)象)的指針。對(duì)所創(chuàng)建的變量或?qū)ο,都是通過(guò)該指針來(lái)間接操作的,而且動(dòng)態(tài)創(chuàng)建的對(duì)象本身沒(méi)有名字。
⑵.一般定義變量和對(duì)象時(shí)要用標(biāo)識(shí)符命名,稱命名對(duì)象,而動(dòng)態(tài)的稱無(wú)名對(duì)象(請(qǐng)注意與棧區(qū)中的臨時(shí)對(duì)象的區(qū)別,兩者完全不同:生命期不同,操作方法不同,臨時(shí)變量對(duì)程序員是透明的)。
⑶.堆區(qū)是不會(huì)在分配時(shí)做自動(dòng)初始化的(包括清零),所以必須用初始化式(initializer)來(lái)顯式初始化。new表達(dá)式的操作序列如下:從堆區(qū)分配對(duì)象,然后用括號(hào)中的值初始化該對(duì)象。
3.堆空間申請(qǐng)、釋放演示:
⑴.用初始化式(initializer)來(lái)顯式初始化
int *pi=new int(0);
⑵.當(dāng)pi生命周期結(jié)束時(shí),必須釋放pi所指向的目標(biāo):
delete pi;
注意這時(shí)釋放了pi所指的目標(biāo)的內(nèi)存空間,也就是撤銷了該目標(biāo),稱動(dòng)態(tài)內(nèi)存釋放(dynamic memory deallocation),但指針pi本身并沒(méi)有撤銷,它自己仍然存在,該指針?biāo)純?nèi)存空間并未釋放。
下面是關(guān)于new 操作的說(shuō)明
⑴.new運(yùn)算符返回的是一個(gè)指向所分配類型變量(對(duì)象)的指針。對(duì)所創(chuàng)建的變量或?qū)ο,都是通過(guò)該指針來(lái)間接操作的,而動(dòng)態(tài)創(chuàng)建的對(duì)象本身沒(méi)有名字。
⑵.一般定義變量和對(duì)象時(shí)要用標(biāo)識(shí)符命名,稱命名對(duì)象,而動(dòng)態(tài)的稱無(wú)名對(duì)象(請(qǐng)注意與棧區(qū)中的臨時(shí)對(duì)象的區(qū)別,兩者完全不同:生命期不同,操作方法不同,臨時(shí)變量對(duì)程序員是透明的)。
⑶.堆區(qū)是不會(huì)在分配時(shí)做自動(dòng)初始化的(包括清零),所以必須用初始化式(initializer)來(lái)顯式初始化。new表達(dá)式的操作序列如下:從堆區(qū)分配對(duì)象,然后用括號(hào)中的值初始化該對(duì)象。
4. 在堆中建立動(dòng)態(tài)一維數(shù)組
①申請(qǐng)數(shù)組空間:
指針變量名=new 類型名[下標(biāo)表達(dá)式];
注意:“下標(biāo)表達(dá)式”不是常量表達(dá)式,即它的值不必在編譯時(shí)確定,可以在運(yùn)行時(shí)確定。
②釋放數(shù)組空間:
delete [ ]指向該數(shù)組的指針變量名;
注意:方括號(hào)非常重要的,如果delete語(yǔ)句中少了方括號(hào),因編譯器認(rèn)為該指針是指向數(shù)組第一個(gè)元素的,會(huì)產(chǎn)生回收不徹底的問(wèn)題(只回收了第一個(gè)元素所占空間),加了方括號(hào)后就轉(zhuǎn)化為指向數(shù)組的指針,回收整個(gè)數(shù)組。delete [ ]的方括號(hào)中不需要填數(shù)組元素?cái)?shù),系統(tǒng)自知。即使寫(xiě)了,編譯器也忽略。
#i nclude <iostream.h>
#i nclude <string.h>
void main(){
int n;
char *pc;
cout<<"請(qǐng)輸入動(dòng)態(tài)數(shù)組的元素個(gè)數(shù)"<<endl;
cin>>n; //n在運(yùn)行時(shí)確定,可輸入17
pc=new char[n]; //申請(qǐng)17個(gè)字符(可裝8個(gè)漢字和一個(gè)結(jié)束符)的內(nèi)存空間
strcpy(pc,“堆內(nèi)存的動(dòng)態(tài)分配”);//
cout<<pc<<endl;
delete []pc;//釋放pc所指向的n個(gè)字符的內(nèi)存空間
return ; }
5. 動(dòng)態(tài)一維數(shù)組的說(shuō)明
① 變量n在編譯時(shí)沒(méi)有確定的值,而是在運(yùn)行中輸入,按運(yùn)行時(shí)所需分配堆空間,這一點(diǎn)是動(dòng)態(tài)分配的優(yōu)點(diǎn),可克服數(shù)組“大開(kāi)小用”的弊端,在表、排序與查找中的算法,若用動(dòng)態(tài)數(shù)組,通用性更佳。一定注意:delete []pc是將n個(gè)字符的空間釋放,而用delete pc則只釋放了一個(gè)字符的空間;
② 如果有一個(gè)char *pc1,令pc1=p,同樣可用delete [] pc1來(lái)釋放該空間。盡管C++不對(duì)數(shù)組作邊界檢查,但在堆空間分配時(shí),對(duì)數(shù)組分配空間大小是紀(jì)錄在案的。
③ 沒(méi)有初始化式(initializer),不可對(duì)數(shù)組初始化。
6.指針數(shù)組和數(shù)組指針
指針類型:
(1)int*ptr;//指針?biāo)赶虻念愋褪?span style="margin: 0px; padding: 0px; word-wrap: break-word;" lang="EN-US">int
(2)char*ptr;//指針?biāo)赶虻牡念愋褪?span style="margin: 0px; padding: 0px; word-wrap: break-word;" lang="EN-US">char
(3)int**ptr;//指針?biāo)赶虻牡念愋褪?span style="margin: 0px; padding: 0px; word-wrap: break-word;" lang="EN-US">int* (也就是一個(gè)int * 型指針)
(4)int(*ptr)[3];//指針?biāo)赶虻牡念愋褪?span style="margin: 0px; padding: 0px; word-wrap: break-word;" lang="EN-US">int()[3] //二維指針的聲明
指針數(shù)組:
一個(gè)數(shù)組里存放的都是同一個(gè)類型的指針,通常我們把他叫做指針數(shù)組。
比如 int * a[2];它里邊放了2個(gè)int * 型變量 .
int * a[2];
a[0]= new int[3];
a[1]=new int[3];
delete a[0];
delete a[1];
注意這里 是一個(gè)數(shù)組,不能delete [] ;
歡迎光臨 (http://www.torrancerestoration.com/bbs/) | Powered by Discuz! X3.1 |