C語言接收函數(shù)返回的指針不隨出棧銷毀
在C語言中除了棧,還有堆可以存儲數(shù)據(jù),其存儲的數(shù)據(jù)不隨棧彈出而消失,但需要手動釋放。今天我們使用動態(tài)內存分配方法,從函數(shù)內傳出變長數(shù)組。
舉個例子:
設想場景:你寫了一個程序,從文件中讀取所有的男同學學生信息。
學生信息包含了:姓名,年齡,性別,學號,語文成績,數(shù)學成績,英語成績。除了學號是唯一的身份識別,其他身份特征是模糊的,也就是說通過性別讀取,將讀取一堆學生。我們嘗試著定義了一個結構體數(shù)組來接收數(shù)據(jù),數(shù)組長度為100,當讀取數(shù)量超過100后,如果沒有對指針加以限制,會導致數(shù)據(jù)越界,甚至棧溢出。為了數(shù)據(jù)安全,我們得確定數(shù)據(jù)長度才行!
數(shù)據(jù)放在棧中不太可行,將其放在堆中才是合理的解決辦法( 內存充足的情況下 )。使用 realloc() 函數(shù)在堆中實時重分配空間,對要分配的數(shù)據(jù)加以補充。realloc()函數(shù)原型為:?
void* realloc (void* ptr, size_t size);?
void* 返回重分配內存的首地址
void* ptr 之前的分配的內存區(qū)域
size_t size 重分配的內存大小
注意:當ptr為 NULL 時,realloc()?與 malloc() 無區(qū)別;重分配的內存大于之前分配的內存,原數(shù)據(jù)不會受要影響,同時轉移至新分配的的內存中,但新增加的內存中殘存不確定的值,若重分配的內存小于之前內存空間大小,則切除多余的部分,但實際核驗中,函數(shù)只是將內存大小縮小了,其連接的數(shù)據(jù)在內存充足的情況下,還一直存在,但不保證隨時會消失;
接下來,是相關數(shù)據(jù)定義:
這是學生結構體,使用 typedef 重定義類型名稱,它儲存著學生的信息,STUDENT,LPSTU 分別為?struct stu 的別名和別名指針:
下面是定義文件指針,接收結果的指針,以及打開文件的方式。
這里定義了20個數(shù)據(jù)塊,并初始化,以及定義了一個指針指向它,LSPSTU 就是 strucu stu *,緊接著寫入了12個數(shù)據(jù)塊。
接下來定義和實現(xiàn)了一個寫入函數(shù)與輸出函數(shù),
int writeDta(FILE *fp,STUDENT * stu,size_t length);//寫入函數(shù)
void printData(LPSTU student,size_t length);//輸出函數(shù)
實際操作中,寫入了15個數(shù)據(jù),目的是產生垃圾數(shù)據(jù),讓主要功能函數(shù)實現(xiàn)甄別的能力。
接下來就是實現(xiàn)所述功能的函數(shù),設想思路:
先讀取文件,如果沒有數(shù)據(jù)則不在堆中申請內存,返回文件異常,如果有數(shù)據(jù), 無論數(shù)據(jù)是否有效,申請一個內存為10 * 44的暫存區(qū),此處為初始化,暫存區(qū)大小為10 * 44,這是為了減少對內存的頻繁掃描,即查找合適的內存大小供分配。
之后所有的數(shù)據(jù)要進行比對,只有匹配給出的數(shù)據(jù),才能存儲到暫存區(qū),當有效數(shù)據(jù)個數(shù)大于暫存區(qū)時,進行重新分配,然后再存儲到新的暫存區(qū)。
當讀取至文件結尾, 數(shù)據(jù)篩選完畢, 這時收縮內存, 按照個數(shù)進行收縮, 假如已分配30 * 44的大小空間,但實際使用25 * 44, 最終將分配的內存大小收縮至25?* 44。
最后將指針指向該內存,并返回。
這是主要功能函數(shù)的定義:
LPSTU findStuByGender(FILE *fp,char *gender,STUDENT **student);
LPSTU 為 struct stu * 的別名;
FILE * fp 文件指針;
char *gender 要匹配的性別
STUDENT?**student 傳遞二級指針,用于接收指向的變長數(shù)組
函數(shù)的實現(xiàn):
如何獲取分配內存區(qū)的長度?
up查了很多資料,發(fā)現(xiàn)兩個辦法,第一個是分配內存時,會在分配的內存的前4字節(jié)儲存長度,實際操作一番發(fā)現(xiàn)并不是,可能是編譯器不支持;第二是使用編譯器自帶的函數(shù)
size_t _msize(void *_Memory)?獲取獲取分配的長度( up 使用版本 gcc version 8.1.0 (x86_64-posix-seh-rev0 by MinGW-W64 project) )。函數(shù)內部還可以繼續(xù)完善,up主已將函數(shù)重寫了三遍,實在沒精力了。
最后是代碼的全貌:
up能力有限,若出現(xiàn)錯誤,歡迎在評論區(qū)指正。