C語言ADT(抽象資料型別程式設計)
C語言是一種計算機程式設計語言。它既具有高階語言的特點,又具有組合語言的特點。它可以作為工作系統設計語言,編寫系統應用程式,也可以作為應用程式設計語言,編寫不依賴計算機硬體的應用程式。因此,它的應用範圍廣泛,不僅僅是在軟體開發上,而且各類科研都需要用到C語言,具體應用比如微控制器以及嵌入式系統開發。(摘自“百度百科”)
在嵌入式系統開發中,隨著系統功能要求越來越多,除了硬體系統不斷擴充套件外,晶片中軟體設計的規模也越來大,演算法越來越複雜,所以需要對程式結構進行良好設計,方便後來的修改和維護。
下面是對ADT的一些簡單介紹:
1.2.1 ADT定義及主要特點:
為型別的屬性和可對型別執行的操作提供一個抽象的描述。不受特定的實現和程式語言的約束。這種正式的抽象描述被稱為抽象資料型別(Abstract Data Type,ADT)。
抽象資料型別概念的引入,降低了大型軟體設計的複雜性;提高了系統的可讀性與可維護性;使系統的各部分相對隔離,在一定程式上解決了軟體的可靠性、生產率等方面的問題。
1.2.2定義步驟:
1、定義一個數據型別。提供儲存資料的方式,提供操作資料的方式。
2、開發一個實現該ADT的程式設計介面。即說明如何儲存資料,並描述用於執行所需操作的函式集合。例如,提供一個結構體型別的定義,同時提供用來操作該結構體的函式的原型。
3、編寫程式碼實現這個介面。
1.2.3抽象資料型別優點:
程式便於維護,靈活應對需求的變更;如果有些功能執行不正常,可以將問題集中到一個函式上;如果想用更好的辦法來完成一個任務,比如新增專案,則只需重新編寫那一個函式;如果需要增加新的屬性或操作,則修改抽象型別即可。
上面的都是在本科階段學習C++裡面的一講《抽象資料型別》裡面的內容。當時教學時是先講C++基本的語法規則,再講類。C++基本的語法規則和C語言基本類似,所以在講C++“面向物件”最重要的特點――類之前,用“抽象資料型別”進行了一次過渡。C++目前基本上沒有用過,類也用得不深入,但是“抽象資料型別”的思想卻留下來了,這樣使得自己對大規模的C語言程式設計的基本模式有了比較好的基礎和概念了。
下面是結合ADT程式設計模式的例子進行介紹:
檢視工作區,裡面包含三個檔案:
list.h:資料的定義和宣告,介面函式的宣告 list.cpp:介面函式的實現 cw0901d.cpp:用於引用和測試程式碼塊 |
“list.h”檔案內容如下:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*
列表抽象資料型別的標頭檔案
*/
#ifndef _LIST_H_
#define _LIST_H_
//////////////////////////////////////////////////////////////////////////////////特定於程式的宣告
//
const int TITLESIZE=51; //存放片名的陣列長度
struct MyFilm
{
char title[TITLESIZE];
int rating;
};
//////////////////////////////////////////////////////////////////////////////////一般型別定義
//
typedef MyFilm Item;
struct Node
{
Item item;
Node *next;
};
typedef Node * List;
//////////////////////////////////////////////////////////////////////////////////函式原型
////操 作:初始化一個列表
//操作前:list引用一個列表
//操作後:該列表為初始化為空列表void InitializeList(List &list);
//操 作:確定列表是否為空列表
//操作前:list引用一個已初始化的列表
//操作後:如果該列表為空則返回true,否則返回falsebool ListIsEmpty(const List &list);
//操 作:確定列表是否已滿
//操作前:list引用一個已初始化的列表
//操作後:如果該列表已滿則返回true,否則返回falsebool ListIsFull(const List &list);
//操 作:確定列表中專案的個數
//操作前:list引用一個已初始化的列表
//操作後:返回列表中專案的個數unsigned int ListItemCount(const List &list);
//操 作:在列表的尾部新增一個專案
//操作前:item是要被新增到列表的專案
// list引用一個已初始化的列表
//操作後:如果可能的話,在列表的尾部新增一個新專案,
// 成功則返回true,否則返回falsebool AppendItem(Item item, List &list);
//操 作:把一個函式作用於列表中的每個專案
//操作前:list引用一個已初始化的列表
// pFun指向一個函式,該函式接受一個Item引用引數,
// 並且無返回值
//操作後:pFun指向的函式被作用到列表中的每一個專案一次void Traverse(const List &list, void (*pFun)(Item &item));
//操 作:釋放已分配的記憶體
//操作前:list引用一個已初始化的列表
//操作後:為該列表分配的記憶體已被釋放,
// 且該列表被置為空列表void EmptyList(List &list);
#endif
“list.cpp”檔案內容如下:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*
列表抽象資料型別的實現
*/
#include <iostream.h>
#include "list.h"
//把Item專案拷貝到列表的一個Node節點的item中static void CopyToNode(const Item &item, Node &node);
void InitializeList(List &list)
{
list = NULL;
}
bool ListIsEmpty(const List &list)
{
if (list==NULL)
return true;
else
return false;
}
bool ListIsFull(const List &list)
{
Node *pNode = new Node;
if (pNode==NULL)
return true;
else
{
delete pNode;
return false;
}
}
unsigned int ListItemCount(const List &list)
{
unsigned int count=0;
Node *pNode = list;
while (pNode != NULL)
{
count++;
pNode = pNode->next;
}
return count;
}
bool AppendItem(Item item, List &list)
{
Node *pNewNode, *pNode=list;
pNewNode = new Node;
if (pNewNode == NULL)
return false;
CopyToNode(item, *pNewNode);
pNewNode->next = NULL;
if (pNode == NULL)
list = pNewNode;
else
{
while (pNode->next != NULL)
pNode = pNode->next;
pNode->next = pNewNode;
}
return true;
}
void Traverse(const List &list, void (*pFun)(Item &item))
{
Node *pNode = list;
while (pNode != NULL)
{
pFun(pNode->item);
pNode = pNode->next;
}
}
void EmptyList(List &list)
{
Node *pNode = list, *pTemp;
while (pNode != NULL)
{
pTemp = pNode;
pNode = pNode->next;
delete pTemp;
}
}
static void CopyToNode(const Item &item, Node &node)
{
node.item = item; //結構體直接賦值實現拷貝}
“cw0901d.cpp”檔案內容如下:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*
用定義的抽象資料型別——列表(List)——儲存電影列表
*/
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include "list.h"
void ShowFilm(Item &item); //顯示列表專案的函式
void main()
{
List filmList;
Item film;
//初始化列表 InitializeList(filmList);
if (ListIsFull(filmList))
{
cout<<"錯誤:記憶體不足!"<<endl;
exit(1);
}
//讀取資料,建立列表 cout<<"請輸入第一個電影的片名:"<<endl;
cin.getline(film.title, TITLESIZE);
while (film.title[0]!='\0')
{
cout<<"請輸入你的評價等級(0~9):"<<endl;
cin>>film.rating;
cin.get();
if (!AppendItem(film, filmList))
{
cout<<"錯誤:分配記憶體錯誤!"<<endl;
break;
}
if (ListIsFull(filmList))
{
cout<<"錯誤:列表已滿!"<<endl;
break;
}
cout<<"請輸入下一個電影的片名:"<<endl;
cin.getline(film.title, TITLESIZE);
}
//輸出列表 if (ListIsEmpty(filmList))
{
cout<<"你沒有輸入有效的資料!"<<endl;
}
else
{
cout<<"下面是你輸入的電影列表:"<<endl;
Traverse(filmList, ShowFilm);
}
cout<<"你一共輸入了"<<ListItemCount(filmList)<<"部電影。"<<endl;
//清除 EmptyList(filmList);
cout<<"\nBye!"<<endl;
}
void ShowFilm(Item &film)
{
cout<<setw(TITLESIZE+1)<<setiosflags(ios::left)
<<film.title<<film.rating<<endl;
}
在“list.h”中定義一種資料型別,這種資料型別一般是適用於你要解決的實際問題的一種結構體,並在此檔案中為這種抽象資料型別定義必要的方法,這些方法都在對應的“list.cpp”中進行實現,於是“list.h”和“list.cpp”就形成了一個功能模組,這就是用C語言的語法規則初步實現C++的物件“類”的思想。
實現模組化的引用的具體注意事項是:
1. 在list.h中定義抽象資料並宣告介面函式(將程式碼塊定義在一個條件編譯#ifndef……#define……#endif中可防止標頭檔案被重複包含)
2. 在list.cpp檔案的開頭包含list.h並實現介面函式)
3. 在測試檔案cw0901d.cpp檔案的開頭包含list.h標頭檔案(編譯器會自動根據標頭檔案去連線具體的.cpp具體程式碼實現的檔案)
實現上述的三個步驟後,cw0901d.cpp中就能直接對list.h中的資料和方法進行引用了,使用者不用再關心那些方法的具體實現,只需要知道這些函式訪求的功能即可。這樣做的好處不言而喻:一方面使得程式模組化,結構更加清晰,另外一方面使得程式的可擴充套件性的可修改性變強,更加方便維護。
後記:對於高階的面向物件的語言來說,本文肯定是多此一舉了,因為C++,C#的“類”完全比ADT要好用,但是對於C語言這種面向過程的語言來說,ADT無疑是將C++高階語言的程式設計思想在C語言中的一次很有意義的應用,使得大規模的嵌入式系統的C語言程式設計變得更加容易了。本文僅是簡單的整理和講解,具體過程其實可以直接套用附件模板。