C語言實現抽象資料型別(ADT

2021-10-11 03:19:54 字數 3457 閱讀 8657

c/c++有固有資料型別,比如int,float,double。int a;就宣告且定義出乙個int型變數(或者叫資料物件);但光有這些固有的資料型別不能滿足程式設計的可讀、可復用、可維護性的要求。比如想要處理乙個現實中「學生小明」的物件,如果能有乙個名叫「student」的「學生」型別(好比「int」型別),通過像student xiaoming;這樣的語句,就可以定義出乙個名為xiaoming的學生型別物件(就好比「int a;」定義出乙個名為a的int整型變數那樣),那就好辦了。同樣的,如果能實現乙個名叫「stack」的棧資料型別,名叫「list」的鍊錶資料型別,名叫「car」的汽車資料型別,名叫「plane」的飛機資料型別……,就很方便了。用c++的話說來就是class student; student xiaoming;class stack; stack my_stack;class plane; plane boing747;,如此我們自定義出想要的資料型別,然後使用它。

用物件導向的語言和語法,更容易理解抽象資料型別,就像上面寫的那樣。「抽象、封裝、繼承、多型」是物件導向的4個特點,抽象就是把同一資料型別的共有特徵概括出來。乙個資料物件有四個屬性:v(值),a(位址),n(名稱),t(型別)。在程式編譯完成後,可執行程式裡面產生了資訊缺失:程式中的資料物件只有位址和值,沒有資料型別、資料名稱、資料意義等資訊了。所以抽象完成在編寫程式的時候。抽象得出的資料型別的特點包含兩個方面:屬性和方法。拿「student」學生型別來說,姓名,性別,年級,班級,成績等就是學生型別的「屬性」,可以由各種變數表示;努力學習,公升學,考試,翹課,掛科,被加分,被表揚,被扣分,被處分等就是學生型別的「方法」,可以由各種函式表示。方法可以對屬性進行操作,比如「被加分」會修改「成績」這個屬性。封裝就是通過一定的語法形式,把抽象出來的屬性和方法「**在一起」,在形式上寫成乙個整體,使人從形式上就能看出兩者的緊密關係,這個過程叫封裝。通過封裝,還可以將部分屬性和方法隱藏起來,對外只留一定的介面(函式),實現「資訊隱藏」。封裝可以理解為抽象的具體表現形式。

c語言實現抽象資料型別不如物件導向語言來的方便,不過抽象和封裝還是能實現的。

c語言用不完整型別作為唯一的封裝工具。不完整型別的描述是:描述了物件但缺少定義物件大小所需的資訊。

例如宣告 struct t; //宣告不完整型別t。
這告訴編譯器t是乙個結構標記,但並沒有描述結構的成員,所以,編譯器沒有足夠的資訊去確定該結構的大小,sizeof不能用在不完整型別上,也不能用它來宣告變數:

struct t s;(這是錯誤的)。
但是可以定義乙個指標型別指向不完整型別:

typedef struct t *t;
這個型別定義表明,型別t 的變數是指向標記為t的結構的指標。現在可以宣告型別t的變數,將其作為函式的引數進行傳遞,並可以執行其他合法的指標運算(指標的大小並不依賴於它指向的物件,這就解釋了為什麼c語言允許這種行為)。不完整型別的資訊將在程式的其他地方補充完整。

舉學生資料型別的例子說明利用不完整型別實現抽象資料型別:實現抽象資料型別,形式上還是用標頭檔案,原始檔的方式,標頭檔案是供其他人看的,供其他模組其他客戶呼叫的「庫」、「模組對外介面」,在標頭檔案裡定義學生抽象資料型別,並給出代表學生型別「方法」(公升學,考試,翹課,掛科……)的函式的原型:

studentadt.h

#ifndef studentadt_h

#define studentadt_h

struct student; //宣告不完整型別student

typedef struct student * pstudent;//定義學生抽象資料型別,客戶用pstudent而不是student來定義adt

pstudent create(char * name, char * school, int id, int age );

void destroy(pstudent s);

void jiafen(pstudent s, int score); //被加分

void koufen(pstudent s, int score); //被扣分

void shengxue(pstudent s, char * school); //公升學,可能公升到其他學校去了

void showinfo(pstudent s); //顯示adt變數的具體資訊

//……可能還有其他函式實現各種學生型別的「方法」

#endif

宣告的struct這個結構體裡具體有哪些變數,也就是學生型別具體細節(比如學生成績既有可能是用陣列儲存的,也有可能是用鍊錶儲存的),都不在這裡體現,在這裡隱藏起來。在原始檔中再具體實現。客戶不能訪問struct結構的成員。pstudent才是為客戶定義的,供客戶使用的學生抽象資料型別(而不是student型別),包含此標頭檔案的客戶可以使用pstudent型別的變數,呼叫這個標頭檔案中的函式。

抽象資料型別需要create和destroy這樣的函式。int a;//內建型別的宣告,直接它自己就分配出乙個int型的空間。,而抽象資料型別是自定義出來的,需要我們自己手動分配和釋放空間。

客戶可以這樣使用學生adt:

pstudent xiaoming;

xiaoming = cteate("xiaoming", "peking university", 20200001, 18);

//定義出乙個xiaoming的學生adt變數,並做初始化:他的名字叫「xiaoming」,學校是北京大學,學號20200001,年齡18歲。

jiafen(xiaoming, 2);//小明被加分了,加了2分。

koufen(xiaoming, 1);//小明被扣分了,扣了1分。

shengxue(xiaoming, "tsinghua university");//小明公升學去了清華。

destroy(xiaoming);//不再使用xiaoming變數後,釋放動態分配的記憶體,以免記憶體洩漏

studentadt.c可能像這樣實現:

#include #include #include "studentadt.h"

struct student ;

pstudent create(char * name, char * school, int id, int age )

void destroy(pstudent s)

void jiafen(pstudent s, int score)

void koufen(pstudent s, int score)

void shengxue(pstudent s, char * school)

void showinfo(pstudent s)

《c語言程式設計:現代方法》k.n.king; 《新標準c++程式設計教程》郭煒;《基於linux的c++》mooc課程,喬林

抽象資料型別(ADT

說到抽象資料型別,那麼就得先提到資料型別 資料型別指的是乙個值的集合以及定義在這個集合上的一組操作 為什麼要有不同的資料型別呢 當我們計算1 1的時候,只需要很小的儲存空間,但是當我們去計算10000 100000的時候,所需要的空間就會大許多,那麼我們為了去區分這些類別的差異,就有了不同的資料型別...

抽象資料型別(ADT

說到抽象資料型別,那麼就得先提到資料型別 資料型別指的是乙個值的集合以及定義在這個集合上的一組操作 為什麼要有不同的資料型別呢 當我們計算1 1的時候,只需要很小的儲存空間,但是當我們去計算10000 100000的時候,所需要的空間就會大許多,那麼我們為了去區分這些類別的差異,就有了不同的資料型別...

c語言的抽象資料型別(ADT)

定義 抽象資料型 adt 是乙個資料型別,其資料物件和物件上操作的規格說明獨立於物件的儲存表示和物件上的操作的實現。有些程式語言提供了把規格說明與其實現區分開的顯示機制。例如,ada有稱為包 package 的概念,而c 中有稱為類 class 的概念。這兩個概念都有助於程式設計師實現抽象資料型別。...