c语言 自动测试,C语言测试。自己实现scandir 函数
在C語(yǔ)言課程的后端,講完指針和標(biāo)準(zhǔn)文件IO處理,我會(huì)做出一個(gè)難度較大練習(xí),題目就是,利用標(biāo)準(zhǔn)的目錄處理函數(shù) opendir/readdir/closedir實(shí)現(xiàn)類似于 scandir的功能。其中接口要scandir 函數(shù)一致。
這個(gè)題目看起來簡(jiǎn)單,實(shí)現(xiàn)難度相當(dāng)大,主要采用復(fù)雜指針的操作。我第一次拿出來測(cè)試,全班大約只一二名實(shí)現(xiàn)80%的功能,其余很多覺得無從下手。程序很容易就會(huì)出現(xiàn)段錯(cuò)誤。基本上短時(shí)間內(nèi)正確的做出來的人可以劃歸專業(yè)級(jí)的程度了。有興趣的人可以先不看后面內(nèi)容,自行實(shí)現(xiàn)一下。
首先看一下man的scandir 接口定義
int scandir(const char *dir, struct dirent ***namelist,
int(*filter)(const struct dirent *),
int(*compar)(const struct dirent **, const struct dirent **));,從定義來看就不是一個(gè)簡(jiǎn)單的函數(shù),形參里,出現(xiàn)一個(gè)三級(jí)指針,二個(gè)函數(shù)指針。它的功能是,掃描名字為dir的目錄,把滿足filter函數(shù)的過濾條件(即filter執(zhí)行為非0值)的目錄項(xiàng)加入到一維指針數(shù)組namelist.數(shù)組的總長(zhǎng)度為返回值n,如果compar不為空,則最終輸出結(jié)果還要調(diào)用qsort來對(duì)數(shù)組進(jìn)行排序后再輸出。
從scandir的演示代碼,我們可以推算出namelist是一個(gè)指向一維指針數(shù)組的指針。(一維指針數(shù)組等同于 struct dirent ** namelist,這里寫在三級(jí)指針是因?yàn)橐獜暮瘮?shù)里改變namelist的值,必須再多做一級(jí))原因可以參考我的函數(shù)傳值類型的說明。
以下是一個(gè)簡(jiǎn)單掃描 /usr/lib,并且把所有以lib打頭的文件掃描到namelist數(shù)組的測(cè)試程序,這是參考scandir 提供的樣例來修改,alphasort是做原始的ASCII碼值比較進(jìn)行排序的
可以看到namelist是完全動(dòng)態(tài)分配的,不僅數(shù)組本身是動(dòng)態(tài)分配,而且數(shù)組項(xiàng)指向的空間也是動(dòng)態(tài)分配的。
#include
#include
#include
#include
#include
#include
#include
#include
//掃描所有的lib打頭的文件
int filter_fn(const struct dirent * ent)
{
if(ent->d_type != DT_REG)
return 0;
return (strncmp(ent->d_name,"lib",3) == 0);
}
void scan_lib(char * dir_name)
{
int n;
struct dirent **namelist; // struct dirent * namelist[];
n = scandir(dir_name, &namelist, filter_fn, alphasort);
if (n < 0)
perror("scandir");
else {
while(n--) {
printf("%s\n", namelist[n]->d_name);
free(namelist[n]);
}
free(namelist);
}
}
int main(int argc ,char * argv[])
{
scan_lib("/usr/lib");
}
從這個(gè)樣例,我們可以推算出namelist 的數(shù)據(jù)結(jié)構(gòu)是.另外一個(gè)難點(diǎn)是,這個(gè)數(shù)組是動(dòng)態(tài)形成的。即根據(jù)掃描結(jié)果來生成數(shù)組。這樣在函數(shù)里構(gòu)造這樣數(shù)據(jù)結(jié)構(gòu)還是相當(dāng)有難度。
最后正式程序如下。完全的源碼及測(cè)試程序參見附件。
/*
* Author : Andrew Huang *
*/
#define MAX_DIR_ENT 1024
typedef int(*qsort_compar)(const void *, const void *);
int hxy_scandir(const char *dir, struct dirent ***namelist,
int(*filter)(const struct dirent *),
int(*compar)(const struct dirent **, const struct dirent **))
{
DIR * od;
int n = 0;
struct dirent ** list = NULL;
struct dirent * ent ,* p;
if((dir == NULL) || (namelist == NULL))
return -1;
od = opendir(dir);
if(od == NULL)
return -1;
/* 分配一個(gè)最大數(shù)組 */
list = (struct dirent **)malloc(MAX_DIR_ENT*sizeof(struct dirent *));
while(( ent = readdir(od)) != NULL)
{
if( filter&& !filter(ent))
continue;
p = (struct dirent *)malloc(sizeof(struct dirent));
memcpy((void *)p,(void *)ent,sizeof(struct dirent));
list[n] = p;
n++;
if(n >= MAX_DIR_ENT)
break;
}
closedir(od);
/* 改變返回?cái)?shù)組大小*/
*namelist = realloc((void *)list,n*sizeof(struct dirent *));
if(*namelist == NULL)
*namelist = list;
/* 數(shù)組排序*/
if(compar)
qsort((void *)*namelist,n,sizeof(struct dirent *),(qsort_compar)compar);
return n;
}
文件:
hxy_scandir.zip
大小:
1KB
下載:
程序分析
1.這一個(gè)程序的第一個(gè)難點(diǎn)是 namelist個(gè)數(shù)不確定的.是根據(jù)掃描目錄的結(jié)果來確定,并且通過返回值告訴調(diào)用者.一種辦法是做兩次循環(huán),先掃描一次readdir從頭讀一次,確定個(gè)數(shù),然后再重新讀一次讀入內(nèi)容,這樣結(jié)果是準(zhǔn)確了,但是效率極低.另外一種方法讀入時(shí)采用是使用鏈表緩存,然后最后一次性存入數(shù)組.這樣代碼過于復(fù)雜了.
最后采用一個(gè)折中的辦法,即開始一次性分配最大值(1024)的數(shù)組,在讀入時(shí)直接對(duì)數(shù)組操作.這樣代碼處理簡(jiǎn)單,絕大部分情況能正確運(yùn)行.萬一有超過1024,一種是簡(jiǎn)單丟棄多余,二是擴(kuò)大最大值.這個(gè)方法是在效率和正確性采用一個(gè)折衷。
2.最后輸出時(shí),可以用realloc調(diào)整namelist大小再輸出,這樣可以節(jié)約堆空間。
3.關(guān)于最后的數(shù)組的排序,scandir文檔明確告之是采用qsort進(jìn)行排序,因此最后需要進(jìn)行這一步,關(guān)鍵是參數(shù)怎么填寫。
4.這個(gè)函數(shù)內(nèi)部的指針操作相當(dāng)復(fù)雜,象三級(jí)指針namelist最好不要直接使用,而是要在函數(shù)用一個(gè)中間指針變量struct dirent ** list來簡(jiǎn)化。而且在函數(shù)是直接將其作為數(shù)組
總結(jié)
以上是生活随笔為你收集整理的c语言 自动测试,C语言测试。自己实现scandir 函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全球货币环境继续宽松,未来投资者的财富增
- 下一篇: 住房商业贷款利率2018