點擊上方「嵌入式大雜燴」,完全「星標公眾號」第一時間查看精彩文章!類型
C語言類型
C的完全類型分為:
對象類型(char、int、類型數組、完全指針、類型結構體等) 函數類型 不完全類型
什么是完全不完全類型?
C/C++中不完全類型有三種不同形式:void、未指定長度的類型數組以及具有非指定內容的結構和聯合。使用不完全類型的完全指針或引用,不需要知道類型的類型全部內容。?比如:
我們常用以下方式聲明數組:
extern?int?array[];
此時的完全array就是一個不完全類型的數組,一般這樣的數組聲明會放在.h中,而其定義放在.c中,在定義的時候在給出數組的具體長度,若之后有需要改變數組的長度時,直接改.c里的就可以,對外的.h就保持原樣不用修改。
用數組來說明可能還是有點不太好理解,下面我們用結構體的例子來做說明。
在此之前,我們先思考一個問題,我們的結構體實體是在頭文件中定義還是源文件中定義呢?
實際上,在頭文件、源文件中定義都可以
。
下面我們以一個動態數組的管理
為例來做一些演示說明。
在此之前,有必要認識一下動態數組(以下說明來自百度百科):
動態數組,是相對于靜態數組而言。靜態數組的長度是預先定義好的,在整個程序中,一旦給定大小后就無法改變。而動態數組則不然,它可以隨程序需要而重新指定大小。
動態數組的內存空間是從堆(heap)上分配(即動態分配)的。是通過執行代碼而為其分配存儲空間。當程序執行到這些語句時,才為其分配。程序員自己負責釋放內存。使用動態數組的優點是可以根據用戶需要,有效利用存儲空間。
(1)結構體實體定義在頭文件中
比如我們本次的demo有如下三個文件:
此時dynamic_array.h
的內容如下:
我們創建了一些接口函數來操作DA對象,我們希望他人可以使用我們的這些接口來操作數據。并且,一般我們使用其它人寫的代碼時,一般也是優先找到相關頭文件,然后調用頭文件里提供的對外接口函數。
但是,從這個頭文件中,我們不僅僅看到了一些對外接口,還可以看到結構體實體。于是乎,可能就有些人寫出這樣的代碼:
命名有接口可以用,卻偏偏有人喜歡直接操作數據,這是比較容易出錯的做法。而且此時調用者推鍋的理由很充足:你暴露數據給我,我為什么不可以直接操控你的數據,我就不喜歡用你提供的接口,咋的。。。
所以dynamic_array.h
的提供者還是得背鍋。
(2)結構體實體定義在源文件中
為了不被推鍋,我們把我們的頭文件改為:
此時,這里的dynamic_array_def結構類型就是一個不完全類型。
我們把結構體實體定義挪到源文件中,這時候調用者看不到dynamic_array_def里有什么數據了,間接地就可以強迫調用者使用我們提供的接口了。此時如果出問題被推鍋,那我們也樂意接鍋,樂意查找問題呀。
不完全類型起到了數據隱藏的作用,用戶可以在頭文件中看到不包含具體細節的結構體,具體細節及實現隱藏在.c中。因為如果太多細節暴露給用戶,則用戶可能會依賴這些細節,一旦細節發生變化,則用戶代碼可能會失效。
關于數據抽象與封裝也可查看往期筆記:C語言對象編程第一彈:封裝與抽象
最后,順便貼一下本demo工程完整代碼,有需要的朋友自取:
dynamic_array.h:
左右滑動查看全部代碼>>>
#ifndef?__DYNAMIC_ARRAY_H
#define?__DYNAMIC_ARRAY_H
/*?結構體“重命名”?*/
typedef?struct?dynamic_array?dynamic_array_def;
/*?初始化dynamic_array?*/
dynamic_array_def?*DA_Init(void);
/*?銷毀dynamic_array?*/
void?DA_Clean(dynamic_array_def?*pThis);
/*?設置dynamic_array長度?*/
void?DA_SetSize(dynamic_array_def?*pThis,?unsigned?len);
/*?獲取dynamic_array長度?*/
unsigned?DA_GetSize(dynamic_array_def?*pThis);
/*?設置dynamic_array某元素的值?*/
int?DA_SetValue(dynamic_array_def?*pThis,?unsigned?index,?int?value);
/*?獲取dynamic_array某元素的值?*/
int?DA_GetValue(dynamic_array_def?*pThis,?unsigned?index,?int?*pValue);
#endif
dynamic_array.c:
左右滑動查看全部代碼>>>
#include?"dynamic_array.h"
#include?
/*?創建一個動態數組結構體模板?*/
struct?dynamic_array
{
????int?*array;
????unsigned?len;
};
/*?初始化dynamic_array?*/
dynamic_array_def?*DA_Init(void)
{
????dynamic_array_def?*pArray?=?malloc(sizeof(dynamic_array_def));
????pArray->array?=?NULL;
????pArray->len?=?0;
}
/*?銷毀dynamic_array?*/
void?DA_Clean(dynamic_array_def?*pThis)
{
????free(pThis->array);
????pThis->len?=?0;
????free(pThis);
}
/*?設置dynamic_array長度?*/
void?DA_SetSize(dynamic_array_def?*pThis,?size_t?len)
{
????pThis->len?=?len;
????pThis->array?=?(int*)realloc(pThis->array,?pThis->len*sizeof(int));
}
/*?獲取dynamic_array長度?*/
size_t?DA_GetSize(dynamic_array_def?*pThis)
{
????return?pThis->len;
}
/*?設置dynamic_array某元素的值?*/
int?DA_SetValue(dynamic_array_def?*pThis,?size_t?index,?int?value)
{
????if?(index?>?pThis->len)
????{
????????return?-1;
????}
????pThis->array[index]?=?value;
????return?0;
}
/*?獲取dynamic_array某元素的值?*/
int?DA_GetValue(dynamic_array_def?*pThis,?size_t?index,?int?*pValue)
{
????if?(index?>?pThis->len)
????{
????????return?-1;
????}
????*pValue?=?pThis->array[index];
????return?0;
}
main.c
左右滑動查看全部代碼>>>
#include?
#include?
#include?"dynamic_array.h"
int?main(void)
{
????int?arr_elem?=?0;
????/*?初始化一個動態數組?*/
?dynamic_array_def?*pArray?=?DA_Init();
????/*?設置數組長度為10?*/
????DA_SetSize(pArray,?10);
????/*?給數組元素賦值?*/
????for?(int?i?=?0;?i?10;?i++)
????{
????????DA_SetValue(pArray,?i,?i);
????}
????/*?遍歷數組元素并打印?*/
????for?(int?i?=?0;?i?10;?i++)
????{
????????DA_GetValue(pArray,?i,?&arr_elem);
????????printf("%d?",?arr_elem);
????}
????
????/*?數組清理?*/
????DA_Clean(pArray);
????
????return?0;
}
編譯、運行:
以上就是本次的分享,如有錯誤,歡迎指出!感謝閱讀與分享~
相關參考:
https://blog.csdn.net/candcplusplus/article/details/38498707
http://www.voidcn.com/article/p-dsixnffi-k.html
https://www.cnblogs.com/new0801/p/6177080.html
周立功《程序設計與數據結構》
猜你喜歡
一個不該被遺忘的打印輸出函數
分立式ARM+FPGA與ZYNQ SoC相比,有哪些好處?
1024G 嵌入式資源大放送!包括但不限于C/C++、單片機、Linux等。在公眾號聊天界面回復1024,即可免費獲取!
免責聲明:本文內容由21ic獲得授權后發布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!