C語言中二維字符數組的定義和初始化
一般來說,我們可能會希望定義一個二維字符數組并且在定義的時候就用一些字符串來初始化它。比如說: 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"}; 通常使用二維字符數組是為了在程序中存儲一些字符串關鍵字。用這樣的方式來初始化就最簡單不過了。其中,MAX_LENGTH是所有字符串中最大的長度。當然不能忘記'\0'了。 而定義一個字符二維數組,C也提供了簡潔的方式,如果我不想統計字符串的長度,我還可以這樣定義: 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"}; 也就是說,可以不再數組定義的時候指定字符串的長度,但是注意字符串的個數是一定要指定的,像這樣寫 char **testcase = ... 是不行的,不過肯定不行了,因為int *pt=3 也不行,呵呵,這兩個例子是一個道理啊。 我覺得肯定是人都喜歡第二種初始化方法了,而且它還有一個優點,起碼對喜歡用指針的同志來說是一個大優點。就是可以將這樣定義的指針賦給一個二維指針,比如 char **pointer = testcase; 想形式1的定義方法肯定不能這樣賦值了。 不過非常非常值得注意的是,上面定義的兩個指針,一個一維,一個二維,他們必須在const關鍵字上一致,意思就是說如果定義testcase前面加了const關鍵字,定義pointer時也必須加上,否則就會報錯: error C2440: 'initializing' : cannot convert from 'char *[30]' to 'const char ** 在寫這篇 日志的過程中,我突然想到一個問題,就似乎利用上面的方法二初始化二維字符串數組之中,字符串是如何分布的呢?因為字符串的長度是不相等的,完全由編譯器 來計算,那么它是會按照最長的字符串來定制字符數組的長度,還是讓每一個字符串數組都按照自身的大小來占據內存,靠'\0'來識別結尾呢? 二維字符串數組的初始化-動態內存分配 昨天在用FBS200指紋采集芯片采集到一個二維數組數據后,利用串口傳輸上來的數據是以十六進制的數據格式表示的二維矩陣,比如“FF”、“BD”、“5C”等等這樣的形式,而對于一幅灰度圖像,一般都是在0~255之間的數據來表示其亮度值,因此想通過二維字符串數組來對采集過來的數據進行轉化顯示。但在動態分配一個char **str;str=new char*[128];之后對其進行初始化時,總是出現錯誤,不知道如何才能很好的對其賦值,還得深入學習一下。 其實對一個字符的轉化很容易,但對一個字符串形式的字符來轉化,而且是對一個多維數組來轉化就有點吃力了。首先建立一個多維字符串數組,這里是二維的字符串數組,程序如下所示: #i nclude "stdio.h" void main() { char *str1[2][2]={"FF","F9","FA","F9"};//初始化一個二維字符串數組 char *str;//定義一個一維字符串變量 int a,b; int i,j; int result1; for (i=0;i<2;i++) { for (j=0;j<2;j++) { str=str1[i][j];//對一維字符串賦值 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”之間的轉化結果 } 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”之間的轉化結果 } 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”之間的轉化結果 } else { a='A'-str[0]+1; b='A'-str[1]+1; result1=a*16+b;//“00”~“99”之間的轉化結果 } printf("a=%d\n",a); printf("b=%d\n",b); printf("%d\n",result1); } } } 這里只是用2×2的字符串數組做了一個實驗,一幅圖像都是比較大的,這樣在對數組初始化時會占用很多的內存,這樣有時會造成編譯無法通過,昨天就很有幾次死機,當時只是用到64×64的數組。后來把數組的初始化放到main的外面,作為全局變量,在棧中靜態的分配一塊內存空間,雖然可行,但也很占內存,于是想到了在函數中動態分配內存,對動態分配內存又重新學習了一遍,不了解的可以和我一起學習一下。
動態內存分配 1.堆內存分配 : C/C++定義了4個內存區間:代碼區,全局變量與靜態變量區,局部變量區即棧區,動態存儲區,即堆(heap)區或自由存儲區(free store)。 堆的概念: 通常定義變量(或對象),編譯器在編譯時都可以根據該變量(或對象)的類型知道所需內存空間的大小,從而系統在適當的時候為他們分配確定的存儲空間。這種內存分配稱為靜態存儲分配; 有些操作對象只在程序運行時才能確定,這樣編譯時就無法為他們預定存儲空間,只能在程序運行時,系統根據運行時的要求進行內存分配,這種方法稱為動態存儲分配。所有動態存儲分配都在堆區中進行。 當程序運行到需要一個動態分配的變量或對象時,必須向系統申請取得堆中的一塊所需大小的存貯空間,用于存貯該變量或對象。當不再使用該變量或對象時,也就是它的生命結束時,要顯式釋放它所占用的存貯空間,這樣系統就能對該堆空間進行再次分配,做到重復使用有限的資源。 2.堆內存的分配與釋放 堆空間申請、釋放的方法: 在C++中,申請和釋放堆中分配的存貯空間,分別使用new和delete的兩個運算符來完成: 指針變量名=new 類型名(初始化式); delete 指針名; 例如: 1、 int *pi=new int(0); 它與下列代碼序列大體等價: 2、int ival=0, *pi=&ival; 區別:pi所指向的變量是由庫操作符new()分配的,位于程序的堆區中,并且該對象未命名。 堆空間申請、釋放說明: ⑴.new運算符返回的是一個指向所分配類型變量(對象)的指針。對所創建的變量或對象,都是通過該指針來間接操作的,而且動態創建的對象本身沒有名字。 ⑵.一般定義變量和對象時要用標識符命名,稱命名對象,而動態的稱無名對象(請注意與棧區中的臨時對象的區別,兩者完全不同:生命期不同,操作方法不同,臨時變量對程序員是透明的)。 ⑶.堆區是不會在分配時做自動初始化的(包括清零),所以必須用初始化式(initializer)來顯式初始化。new表達式的操作序列如下:從堆區分配對象,然后用括號中的值初始化該對象。 3.堆空間申請、釋放演示: ⑴.用初始化式(initializer)來顯式初始化 int *pi=new int(0); ⑵.當pi生命周期結束時,必須釋放pi所指向的目標: delete pi; 注意這時釋放了pi所指的目標的內存空間,也就是撤銷了該目標,稱動態內存釋放(dynamic memory deallocation),但指針pi本身并沒有撤銷,它自己仍然存在,該指針所占內存空間并未釋放。 下面是關于new 操作的說明 ⑴.new運算符返回的是一個指向所分配類型變量(對象)的指針。對所創建的變量或對象,都是通過該指針來間接操作的,而動態創建的對象本身沒有名字。 ⑵.一般定義變量和對象時要用標識符命名,稱命名對象,而動態的稱無名對象(請注意與棧區中的臨時對象的區別,兩者完全不同:生命期不同,操作方法不同,臨時變量對程序員是透明的)。 ⑶.堆區是不會在分配時做自動初始化的(包括清零),所以必須用初始化式(initializer)來顯式初始化。new表達式的操作序列如下:從堆區分配對象,然后用括號中的值初始化該對象。 4. 在堆中建立動態一維數組 ①申請數組空間: 指針變量名=new 類型名[下標表達式]; 注意:“下標表達式”不是常量表達式,即它的值不必在編譯時確定,可以在運行時確定。 ②釋放數組空間: delete [ ]指向該數組的指針變量名; 注意:方括號非常重要的,如果delete語句中少了方括號,因編譯器認為該指針是指向數組第一個元素的,會產生回收不徹底的問題(只回收了第一個元素所占空間),加了方括號后就轉化為指向數組的指針,回收整個數組。delete [ ]的方括號中不需要填數組元素數,系統自知。即使寫了,編譯器也忽略。 #i nclude <iostream.h> #i nclude <string.h> void main(){ int n; char *pc; cout<<"請輸入動態數組的元素個數"<<endl; cin>>n; //n在運行時確定,可輸入17 pc=new char[n]; //申請17個字符(可裝8個漢字和一個結束符)的內存空間 strcpy(pc,“堆內存的動態分配”);// cout<<pc<<endl; delete []pc;//釋放pc所指向的n個字符的內存空間 return ; } 5. 動態一維數組的說明 ① 變量n在編譯時沒有確定的值,而是在運行中輸入,按運行時所需分配堆空間,這一點是動態分配的優點,可克服數組“大開小用”的弊端,在表、排序與查找中的算法,若用動態數組,通用性更佳。一定注意:delete []pc是將n個字符的空間釋放,而用delete pc則只釋放了一個字符的空間; ② 如果有一個char *pc1,令pc1=p,同樣可用delete [] pc1來釋放該空間。盡管C++不對數組作邊界檢查,但在堆空間分配時,對數組分配空間大小是紀錄在案的。 ③ 沒有初始化式(initializer),不可對數組初始化。 6.指針數組和數組指針 指針類型: (1)int*ptr;//指針所指向的類型是int (2)char*ptr;//指針所指向的的類型是char (3)int**ptr;//指針所指向的的類型是int* (也就是一個int * 型指針) (4)int(*ptr)[3];//指針所指向的的類型是int()[3] //二維指針的聲明 指針數組: 一個數組里存放的都是同一個類型的指針,通常我們把他叫做指針數組。 比如 int * a[2];它里邊放了2個int * 型變量 . int * a[2]; a[0]= new int[3]; a[1]=new int[3]; delete a[0]; delete a[1]; 注意這里 是一個數組,不能delete [] ; |