前言
在純C語(yǔ)言編程中,數(shù)組的創(chuàng)建必須是固定的大小,因?yàn)镃語(yǔ)言本身沒(méi)有提供動(dòng)態(tài)數(shù)組這種數(shù)據(jù)結(jié)構(gòu),這是一個(gè)讓習(xí)慣了使用高級(jí)語(yǔ)言編程的人轉(zhuǎn)做C開(kāi)發(fā)面臨的一個(gè)很頭疼的問(wèn)題,本篇文章就將介紹如何使用純C語(yǔ)言編程實(shí)現(xiàn)一個(gè)對(duì)象來(lái)作為動(dòng)態(tài)數(shù)組。
閱讀本篇文章前,作者假設(shè)讀者已經(jīng)對(duì)C語(yǔ)言的基礎(chǔ)概念有了一定了解,比如知道什么叫數(shù)組,知道C語(yǔ)言的基礎(chǔ)語(yǔ)法等。如果讀者還對(duì)C語(yǔ)言一無(wú)所知,請(qǐng)先對(duì)C語(yǔ)言做一個(gè)了解和入門級(jí)的學(xué)習(xí)之后,再來(lái)閱讀本篇文章。
1:C語(yǔ)言中的數(shù)組分析
1.int my_array[100];
如上的代碼,是使用C語(yǔ)言來(lái)創(chuàng)建了一個(gè)可以存放100個(gè)整數(shù)的數(shù)組,這個(gè)就是C語(yǔ)言中的數(shù)組。
2.這行代碼一共做了兩件事情:
(1):在?;蛘呷?jǐn)?shù)據(jù)區(qū)開(kāi)辟了內(nèi)存空間(如果是寫在某個(gè)函數(shù)的內(nèi)部,就是在棧上開(kāi)辟的空間,如果是寫在函數(shù)外面,就是在全局?jǐn)?shù)據(jù)區(qū)上開(kāi)辟的空間),開(kāi)辟的內(nèi)存空間大小為100*sizeof(int)個(gè)字節(jié)的內(nèi)存空間。如果是在棧上開(kāi)辟的,那么這塊內(nèi)存空間會(huì)在走到所在函數(shù)return之后釋放,如果是在全局?jǐn)?shù)據(jù)區(qū),會(huì)隨著進(jìn)程的結(jié)束而釋放。
(2):創(chuàng)建一個(gè)指針指向新開(kāi)辟的內(nèi)存區(qū)域,并將該區(qū)域的地址賦值給my_array保存,這樣,我們就可以通過(guò)下標(biāo)來(lái)對(duì)數(shù)組中的成員進(jìn)行訪問(wèn),比如:my_array[9]可以訪問(wèn)第10個(gè)成員。此外,還可以通過(guò)取地址指向內(nèi)容的方式來(lái)訪問(wèn)數(shù)組成員,比如*(my_array+10),同樣可以得到和my_array[10]一樣的值。
3.從上面分析int my_array[100];這行代碼可以看出,數(shù)組的操作本質(zhì)上就是內(nèi)存的操作,小標(biāo)的索引只是一種糖衣語(yǔ)法。
?4.這種數(shù)組的缺點(diǎn)大家可以很容易想到,數(shù)組開(kāi)辟的空間大小不根據(jù)實(shí)際數(shù)據(jù)的多少來(lái)決定,造成了空間上的浪費(fèi),另外當(dāng)數(shù)據(jù)量大余數(shù)組的最大容量時(shí),會(huì)造成程序的崩潰。
補(bǔ)充:有的朋友也許會(huì)說(shuō),按照上面的寫法開(kāi)辟數(shù)組后,執(zhí)行my_array[100]=1或者my_array[102]=1都不出現(xiàn)崩潰,這個(gè)只是因?yàn)槟愕倪\(yùn)氣好,原因是在my_array指向的內(nèi)存區(qū)域中,第101個(gè)或者第102位置正好有空間而已,因?yàn)槲覀儗憁y_array[100]只能保證有100個(gè)位置是可以使用的,至于100以后的,那就要看系統(tǒng)的“心情”了!
二.定義一個(gè)my_vector結(jié)構(gòu)體
接下來(lái)要介紹動(dòng)態(tài)數(shù)組使用到的結(jié)構(gòu)體以及對(duì)應(yīng)的方法聲明。首先創(chuàng)建一個(gè)myVector.h的文件,并編寫如下的代碼:
// my_vector默認(rèn)大小 #define MY_VECTOR_DEF_SIZE 10 // 結(jié)構(gòu)體定義 typedef struct { int curSize; // 已用的大小 int maxSize; // 數(shù)組最大存儲(chǔ)大小 int *data; // 實(shí)際的數(shù)據(jù)地址 } my_vector; // 初始化結(jié)構(gòu)體 void InitMyVector(my_vector *vector); // 追加成員 void AppendMyVector(my_vector *vector, int value); // 返回指定下標(biāo)中的數(shù)據(jù),如果失敗返回-1 int GetMyVector(my_vector *vector, int index); // 設(shè)置指定位置的指為指定數(shù)據(jù) void SetMyVector(my_vector *vector, int index, int value); // 將當(dāng)前的my_vecotr存儲(chǔ)空間直接擴(kuò)大一倍 void DoubleCapacityMyVector(my_vector *vector); // 釋放資源 void FreeMyVector(my_vector *vector);
三.實(shí)現(xiàn)定義的my_vector結(jié)構(gòu)體
聲明完成之后要做的就是實(shí)現(xiàn)聲明的函數(shù)了。創(chuàng)建一個(gè)myVector. C的文件,并編寫如下代碼:
#include <stdio.h> #include <stdlib.h> #include "myVector.h" // 初始化 void InitMyVector(my_vector *vector) { // 數(shù)據(jù)初始化 vector->curSize = 0; vector->maxSize = MY_VECTOR_DEF_SIZE; // 開(kāi)辟存儲(chǔ)實(shí)際數(shù)據(jù)的空間 vector->data = (int*)malloc(sizeof(int) * vector->maxSize); } // 追加值 void AppendMyVector(my_vector *vector, int value) { // 空間不夠了需要增大 DoubleCapacityMyVector(vector); // 添加新的數(shù)據(jù)到數(shù)組尾 vector->data[vector->curSize++] = value; } // 獲的值 int GetMyVector(my_vector *vector, int index) { // 輸入的數(shù)據(jù)如果小于0或者是大余數(shù)組最大存儲(chǔ)值時(shí),直接退出程序,因?yàn)閿?shù)據(jù)不合法 if (index >= vector->curSize || index < 0) { exit(1); } // 如果輸入的是一個(gè)合法的數(shù)據(jù)那么返回對(duì)應(yīng)的數(shù)據(jù) return vector->data[index]; } // 設(shè)置值 void SetMyVector(my_vector *vector, int index, int value) { // 用0作為默認(rèn)值來(lái)他填充數(shù)組 while (index >= vector->curSize) { AppendMyVector(vector, 0); } vector->data[index] = value; } // 擴(kuò)大空間 void DoubleCapacityMyVector(my_vector *vector) { if (vector->curSize >= vector->maxSize) { // 擴(kuò)大數(shù)組大小為當(dāng)前的兩倍 vector->maxSize *= 2; vector->data = (int*)realloc(vector->data, sizeof(int) * vector->maxSize); } } //釋放空間 void FreeMyVector(my_vector *vector) { free(vector->data); }
四.使用my_vector結(jié)構(gòu)體創(chuàng)建結(jié)構(gòu)體對(duì)象
創(chuàng)建一個(gè)main.c的文件,并編寫如下代碼
#include <stdio.h> #include "myVector.h" int main() { // 聲明vector對(duì)象 my_vector vector; int i; // 初始化vector對(duì)象 InitMyVector(&vector); // 隨便初始化點(diǎn)數(shù)據(jù) for (i = 0; i <200; i++) { AppendMyVector(&vector, i); } // 測(cè)試用,在第200位置設(shè)置1,200之前的數(shù)據(jù)如果為空自動(dòng)填充為0,當(dāng)前程序就是200-299為0 SetMyVector(&vector, 300, 1); // 測(cè)試用,取指定位置的數(shù)據(jù) printf("%d\n", GetMyVector(&vector, 6)); // 測(cè)試用,輸出每一個(gè)成員 for (i = 0; i < vector.curSize; i++) { printf("%d %d\n", i, GetMyVector(&vector, i)); } // 使用完之后要釋放,不然會(huì)有內(nèi)存泄露 FreeMyVector(&vector); return 0; }
到此為止,我們已經(jīng)實(shí)現(xiàn)了用C語(yǔ)言去創(chuàng)建動(dòng)態(tài)數(shù)組,其實(shí)動(dòng)態(tài)數(shù)組的本質(zhì)也是靜態(tài)的,只不過(guò)空間的增加我們做了一些手動(dòng)的處理而已。
類似的,刪除指定位置的數(shù)據(jù)也可以用上面的方式去實(shí)現(xiàn)。請(qǐng)大家自己理解學(xué)習(xí)嘗試進(jìn)行實(shí)現(xiàn)!