計算機等級考試二級C語言鍊錶複習

2021-09-24 14:54:11 字數 4892 閱讀 2625

一、為什麼用動態記憶體分配

但我們未學習鍊錶的時候,如果要儲存數量比較多的同型別或同結構的資料的時候,總是使用乙個陣列。比如說我們要儲存乙個班級學生的某科分數,總是定義乙個float型(存在0.5分)陣列:

floatscore[30];

但是,在使用陣列的時候,總有乙個問題困擾著我們:陣列應該有多大?

在很多的情況下,你並不能確定要使用多大的陣列,比如上例,你可能並不知道該班級的學生的人數,那麼你就要把陣列定義得足夠大。這樣,你的程式在執行時就申請了固定大小的你認為足夠大的記憶體空間。即使你知道該班級的學生數,但是如果因為某種特殊原因人數有增加或者減少,你又必須重新去修改程式,擴大陣列的儲存範圍。

這種分配固定大小的記憶體分配方法稱之為靜態記憶體分配。但是這種記憶體分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的記憶體空間,在少數情況下,當你定義的陣列不夠大時,可能引起下標越界錯誤,甚至導致嚴重後果。

那麼有沒有其它的方法來解決這樣的外呢體呢?有,那就是動態記憶體分配。

所謂動態記憶體分配就是指在程式執行的過程中動態地分配或者**儲存空間的分配記憶體的方法。動態記憶體分配不象陣列等靜態記憶體分配方法那樣需要預先分配儲存空間,而是由系統根據程式的需要即時分配,且分配的大小就是程式要求的大小。從以上動、靜態記憶體分配比較可以知道動態記憶體分配相對於景泰記憶體分配的特點:

1、不需要預先分配儲存空間;

2、分配的空間可以根據程式的需要擴大或縮小。

二、如何實現動態記憶體分配及其管理

要實現根據程式的需要動態分配儲存空間,就必須用到以下幾個函式

1、malloc函式

malloc函式的原型為:

void*malloc(unsignedintsize)

其作用是在記憶體的動態儲存區中分配乙個長度為size的連續空間。其引數是乙個無符號整形數,返回值是乙個指向所分配的連續儲存域的起始位址的指標。還有一點必須注意的是,當函式未能成功分配儲存空間(如記憶體不足)就會返回乙個null指標。

所以在呼叫該函式時應該檢測返回值是否為null並執行相應的操作。

下例是乙個動態分配的程式:

#include

#include

main()

for(count=0;count〈10;count++)/*給陣列賦值*/

array[count]=count;

for(count=0;count〈10;count++)/*列印陣列元素*/

printf("-",array[count]);

} 上例中動態分配了10個整型儲存區域,然後進行賦值並列印。例中if((array(int*)malloc(10*sizeof(int)))==null)語句可以分為以下幾步:

1)分配10個整型的連續儲存空間,並返回乙個指向其起始位址的整型指標

2)把此整型指標位址賦給array

3)檢測返回值是否為null

2、free函式

由於記憶體區域總是有限的,不能不限制地分配下去,而且乙個程式要盡量節省資源,所以當所分配的記憶體區域不用時,就要釋放它,以便其它的變數或者程式使用。這時我們就要用到free函式。

其函式原型是:

voidfree(void*p)

作用是釋放指標p所指向的記憶體區。

其引數p必須是先前呼叫malloc函式或calloc函式(另乙個動態分配儲存區域的函式)時返回的指標。給free函式傳遞其它的值很可能造成宕機或其它災難性的後果。

注意:這裡重要的是指標的值,而不是用來申請動態記憶體的指標本身。例:

int*p1,*p2;

p1=malloc(10*sizeof(int));

p2=p1;

…… free(p2)/*或者free(p2)*/

malloc返回值賦給p1,又把p1的值賦給p2,所以此時p1,p2都可作為free函式的引數。

malloc函式是對儲存區域進行分配的。

free函式是釋放已經不用的記憶體區域的。

所以由這兩個函式就可以實現對記憶體區域進行動態分配並進行簡單的管理了。

三、單鏈表的建立

有了動態記憶體分配的基礎,要實現鍊錶就不難了。

所謂鍊錶,就是用一組任意的儲存單元儲存線性表元素的一種資料結構。

鍊錶又分為單鏈表、雙向鍊錶和迴圈鍊錶等。我們先講講單鏈表。

所謂單鏈表,是指資料接點是單向排列的。乙個單鏈表結點,其結構型別分為兩部分:

1、資料域:用來儲存本身資料

2、鏈域或稱為指標域:用來儲存下乙個結點位址或者說指向其直接後繼的指標。

例:typedef struct node

stud;

這樣就定義了乙個單鏈表的結構,其中char name[20]是乙個用來儲存姓名的字元型陣列,指標*link是乙個用來儲存其直接後繼的指標。

定義好了鍊錶的結構之後,只要在程式執行的時候愛資料域中儲存適當的資料,如有後繼結點,則把鏈域指向其直接後繼,若沒有,則置為null。

下面就來看乙個建立帶表頭(若未說明,以下所指鍊錶均帶表頭)的單鏈表的完整程式。

#include

#include /*包含動態記憶體分配函式的標頭檔案*/

#define n 10 /*n為人數*/

typedef struct node

stud;

stud * creat(int n) /*建立單鏈表的函式,形參n為人數*/

h->name[0]='\0'; /*把表頭結點的資料域置空*/

h->link=null; /*把表頭結點的鏈域置空*/

p=h; /*p指向表頭結點*/

for(i=0;ilink=s; /*把s的位址賦給p所指向的結點的鏈域,這樣就把p和s所指向的結點連線起來了*/

printf("請輸入第%d個人的姓名",i+1);

scanf("%s",s->name); /*在當前結點s的資料域中儲存姓名*/

s->link=null;

p=s;

}return(h);

}main()

這樣就寫好了乙個可以建立包含n個人姓名的單鏈表了。

寫動態記憶體分配的程式應注意,請盡量對分配是否成功進行檢測。

四、單鏈表的基本運算

建立了乙個單鏈表之後,如果要進行一些如插入、刪除等操作該怎麼辦?所以還須掌握一些單鏈表的基本演算法,來實現這些操作。單鏈表的基本運算包括:

查詢、插入和刪除。下面我們就一一介紹這三種基本運算的演算法,並結合我們建立單鏈表的例子寫出相應的程式。

1、查詢

對單鏈表進行查詢的思路為:對單鏈表的結點依次掃瞄,檢測其資料域是否是我們所要查好的值,若是返回該結點的指標,否則返回null。

因為在單鏈表的鏈域中包含了後繼結點的儲存位址,所以當我們實現的時候,只要知道該單鏈表的頭指標,即可依次對每個結點的資料域進行檢測。

以下是應用查詢演算法的乙個例子:

#include

#include

#include /*包含一些字串處理函式的標頭檔案*/

#define n 10

typedef struct node

stud;

stud * creat(int n) /*建立鍊錶的函式*/

h->name[0]='\0';

h->link=null;

p=h;

for(i=0;ilink=s;

printf("請輸入第%d個人的姓名",i+1);

scanf("%s",s->name);

s->link=null;

p=s;

}return(h);

}stud * search(stud *h,char *x) /*查詢鍊錶的函式,其中h指標是鍊錶的表頭指標,x指標是要查詢的人的姓名*/

if(p==null)

printf("沒有查詢到該資料!");

}main()

2、插入(後插)

假設在乙個單鏈表中存在2個連續結點p、q(其中p為q的直接前驅),若我們需要在p、q之間插入乙個新結點s,那麼我們必須先為s分配空間並賦值,然後使p的鏈域儲存s的位址,s的鏈域儲存q的位址即可。(p->link=s;s->link=q),這樣就完成了插入操作。

下例是應用插入演算法的乙個例子:

#include

#include

#include

#define n 10

typedef struct node

stud;

stud * creat(int n) /*建立單鏈表的函式*/

h->name[0]='\0';

h->link=null;

p=h;

for(i=0;ilink=s;

printf("請輸入第%d個人的姓名:",i+1);

scanf("%s",s->name);

s->link=null;

p=s;

}return(h);

}stud * search(stud *h,char *x) /*查詢函式*/

if(p==null)

printf("沒有查詢到該資料!");

}void insert(stud *p) /*插入函式,在指標p後插入*/

printf("請輸入你要插入的人的姓名:");

scanf("%s",stuname);

strcpy(s->name,stuname); /*把指標stuname所指向的陣列元素拷貝給新結點的資料域*/

s->link=p->link; /*把新結點的鏈域指向原來p結點的後繼結點*/

p->link=s; /*p結點的鏈域指向新結點*/

}main()

3、刪除

假如我們已經知道了要刪除的結點p的位置,那麼要刪除p結點時只要令p結點的前驅結點的鏈域由儲存p結點的位址該為儲存p的後繼結點的位址,並**p結點即可。

以下便是應用刪除演算法的例項:

#include

#include

#include

#define n 10

計算機等級考試二級C語言模擬試題

2010年9月計算機等級考試二級c語言模擬試題 三 1 筆試部分 一 選擇題 1.對下面程式描述正確的一項是 每行程式前面的數字表示行號 main int i for i 0 i 3 i scanf d a i for i 1 i 3 i a 0 a 0 a i printf f n a 0 a.沒...

2019計算機等級考試二級Access複習歸納

53 資料模型是資料庫設計的核心。資料模型按不同的應用層次分為三種型別,它們是概念資料模型 邏輯資料模型和物理資料模型。資料模型所描述的內容有三個部分,它們是資料結構 資料操作和資料約束。54 在e r圖中用矩形表示實體集,橢圓表示屬性,菱形表示聯絡,層次模型 網狀模型和關係模型 二維 是目前資料庫...

計算機二級考試C語言全

第一章資料結構與演算法 1.1 演算法 1 是指解題方 而完整的描述。換句話說,演算法是對特定問題求解步驟的一種描述。演算法不等於程式,也不等於計算方法。程式的編制不可能優於演算法的設計。2 演算法的基本特徵 1 可行性。針對實際問題而設計的演算法,執行後能夠得到滿意的結果。2 確定性。每一條指令的...