Makefile系列的構(gòu)造工具,而是使用集成開發(fā)環(huán)境直接一站式的完成所有的工作,而我們只需要專注于編寫有用的代碼即可。在完成備份之前,首先想想要如何構(gòu)造這個(gè)備份模型
隊(duì)列模型
隊(duì)列實(shí)體
新建 Queue.h Queue.c
Queue.h
typedef struct _vector_queue queue;
typedef struct _combine combine;
| 返回值 | | 函數(shù)類型名 || 參數(shù)類型 |
typedef int (*fpPushBack)(queue * __restrict, const char * __restrict, const char * __restrict);
typedef const combine * (*fpPopFront)(queue *);
typedef void (*fpDelete)(queue *);
五個(gè)typedef不知道有沒有眼前一懵。,希望能夠很好的理解
前兩個(gè)是結(jié)構(gòu)體的聲明,分別對應(yīng)著 隊(duì)列模型 和 路徑模型。
后兩個(gè)是函數(shù)指針,作用是放在結(jié)構(gòu)體里,使C語言的結(jié)構(gòu)體也能夠擁有一些簡單的面向?qū)ο蠊δ?,例?strong>成員函數(shù)功能,原理就是可以給這些函數(shù)指針類型的變量賦值。稍后例子更加明顯。試著解讀一下,很簡單的。
struct _combine{
char * src_from_path; /* 源路徑 */
char * dst_to_path; /* 目的路徑 */
};
struct _vector_queue{
combine ** path_contain; /* 存儲路徑的容器主體 */
unsigned int rear; /* 隊(duì)尾坐標(biāo) */
unsigned int front; /* 隊(duì)首坐標(biāo) */
int empty; /* 是否為空 */
unsigned int capcity; /* 容器的容量 */
fpPushBack PushBack; /* 將元素壓入隊(duì)尾 */
fpPopFront PopFront; /* 將隊(duì)首出隊(duì) */
fpDelete Delete; /* 析構(gòu)釋放整個(gè)隊(duì)列空間 */
};
/**
* @version 1.0 2015/10/03
* @author wushengxin
* @param object 外部傳入的對象指針,相當(dāng)于 this
* @function 初始化隊(duì)列模型,建立隊(duì)列實(shí)體,分配空間,以及設(shè)置屬性。
*/
int newQueue(queue* object);
可以看到,上方的函數(shù)指針類型,被用在了結(jié)構(gòu)體內(nèi),此處少了一個(gè)初始化函數(shù),是因?yàn)椴淮蛩惆阉?dāng)作成員函數(shù)(借用面向?qū)ο笮g(shù)語)
在使用的時(shí)候可以直接obj_name.PushBack(..., ..., ...);
更詳細(xì)的可以看后面的實(shí)現(xiàn)部分。成為成員函數(shù)的三個(gè)函數(shù),將被實(shí)現(xiàn)為 static 函數(shù),不被外界訪問。
queue.c
int newQueue(queue * object)
{
queue* loc_que = object;
combine** loc_arr = NULL;
loc_arr = (combine**)Malloc_s(CAPCITY * sizeof(combine*));
if (!loc_arr)
return 1;
loc_que->capcity = CAPCITY; /* 容量 */
loc_que->front = 0; /* 隊(duì)首 */
loc_que->rear = 0; /* 隊(duì)尾 */
loc_que->path_contain = loc_arr; /* 將分配好的空間,放進(jìn)對象中 */
loc_que->PushBack = push_back;
loc_que->PopFront = pop_front;
loc_que->Delete = del_queue;
return 0;
}
在初始化函數(shù)中,可以看到,設(shè)置了隊(duì)首隊(duì)尾以及容量,分配了容器空間,配置了成員函數(shù)。
最后三句配置函數(shù)的語句中,push_back, pop_front, del_queue在后方以static 函數(shù)實(shí)現(xiàn)。
但是由于沒有聲明,所以切記要將三個(gè)static函數(shù)的實(shí)現(xiàn)放在newQueue的前方
/**
* @version 1.0 2015/10/03
* @author wushengxin
* @param object 外部傳入的對象指針 相當(dāng)于 this
* @function 釋放整個(gè)隊(duì)列實(shí)體的空間
*/
static void del_queue(queue * object)
{
Free_s(object->path_contain);
return;
}
/**
* @version 1.0 2015/10/03
* @author wushengxin
* @param object 外部傳入的對象指針 相當(dāng)于 this
src 源路徑
dst 目的路徑
* @function 將外部傳入的<源路徑,目的路徑> 存入隊(duì)列中
*/
static int push_back(queue * __restrict object, const char * __restrict src, const char * __restrict dst)
{
int times = 0;
char* loc_src = NULL; /* 本地變量,盡量利用寄存器以及緩存 */
char* loc_dst = NULL;
combine* loc_com = NULL;
queue* loc_que = object;
size_t len_src = strlen(src); /* 獲取路徑長度 */
size_t len_dst = strlen(dst);
size_t rear = loc_que->rear; /*獲取隊(duì)尾*/
size_t front = loc_que->front; /*獲取隊(duì)首*/
loc_src = Malloc_s(len_src + 1); /* 分配空間 */
if (!loc_src)
return 1;
loc_dst = Malloc_s(len_dst + 1);
if (!loc_dst)
return 2;
strcpy(loc_src, src);
strcpy(loc_dst, dst);
loc_com = Malloc_s(sizeof(combine));
if (!loc_com)
return 3;
loc_com->dst_to_path = loc_dst;
loc_com->src_from_path = loc_src;
loc_que->path_contain[rear++] = loc_com; /* 將本地路徑加入實(shí)體 */
loc_que->rear = (rear % CAPCITY); /* 用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的步驟 */
if (loc_que->rear == loc_que->front)
loc_que->empty = 0;
return 0;
}
/**
* @version 1.0 2015/10/03
* @author wushengxin
* @param object 外部傳入的對象指針
*/
static const combine * pop_front(queue* object)
{
size_t loc_front = object->front; /*獲取當(dāng)前隊(duì)首*/
combine* loc_com = object->path_contain[loc_front]; /*獲取當(dāng)前文件名*/
object->path_contain[loc_front] = NULL; /*出隊(duì)操作*/
object->front = ((object->front) + 1) % 20; /*完成出隊(duì)*/
if (object->front == object->rear)
object->empty = 1;
else
object->empty = 0;
return loc_com;
}
一個(gè)一個(gè)的說這些函數(shù)
del_queue:釋放函數(shù),直接調(diào)用Free_s
push_back:壓入函數(shù),將外部傳入的兩個(gè)原始的沒有組成的路徑字符串,組合成一個(gè)combine,并壓入路徑,每次都判斷并置是否為空標(biāo)志位,實(shí)際上這個(gè)函數(shù)中有累贅代碼的嫌疑,應(yīng)該再分出一個(gè)函數(shù),專門用來分配三個(gè)空間,防止這個(gè)函數(shù)過長(接近40行)
pop_front:彈出函數(shù),將隊(duì)列的隊(duì)首combine彈出,用于復(fù)制,但是這里有一個(gè)隱患,就是要將釋放的工作交給外者,如果疏忽大意的話,隱患就是內(nèi)存泄漏。
沒有特地的提供一個(gè)接口,用來判斷是否為空,因?yàn)楫?dāng)編譯器一優(yōu)化,也會將這種接口給優(yōu)化成直接使用成員的形式,某種形式上的內(nèi)聯(lián)。
先設(shè)計(jì)一下二級界面
二級界面
backup.h backup.c 文件
backup.h
/**
* @version 1.0 2015/10/03
* @author wushengxin
* function 顯示二級界面
*/
void sec_main_windows();
backup.c
void sec_main_windows()
{
char tmpBuf[256];
int selects;
do{
setjmp(select_jmp);
system("cls");
puts("-------------------1. Back Up------------------ ");
puts(" For This Select, You can choose Two Options: ");
puts(" 1. Start Back up (The Directory Path That You Enter LATER) ");
puts(" 2. Back To last level ");
puts("----------------------------------------------- ");
fprintf(stdout, "Enter Your Selection: ");
fgets(tmpBuf, 256, stdin);
sscanf(tmpBuf, "%d", &selects);
if (selects != 1 && selects != 2 )
{
fprintf(stdout, "\n Your Select \" %s \" is Invalid!\n Try Again \n", tmpBuf);
longjmp(select_jmp, 1);
}
switch (selects)
{
jmp_buf enter_path_jmp;
case 1:
{
char tmpBuf[LARGEST_PATH], tmpPath[LARGEST_PATH]; /* 使用棧分配空間,因?yàn)橹挥梅峙湟淮?*/
setjmp(enter_path_jmp); /* enter jump to there */
puts(" Enter the Full Path You want to BackUp(e.g: C:/Programing/)");
fprintf(stdout, " Or Enter q to back to select\nYour Enter : ");
fgets(tmpBuf, LARGEST_PATH, stdin);
sscanf(tmpBuf, "%s", tmpPath);
if (_access(tmpPath, 0) != 0) /*檢查路徑是否存在,有效*/
{
if (tmpPath[0] == 'q' || tmpPath[0] == 'Q')
longjmp(select_jmp, 0); /* 回到可以選擇返回的界面 */
fprintf(stderr, "The Path You Enter is Not Exit! \n Try Again : ");
longjmp(enter_path_jmp, 0); /* enter jump from here */
}
}
break;
case 2:
return;
default:
break;
}/* switch */
} while (1);
return;
}
這個(gè)函數(shù)只說幾點(diǎn),首先是`switch`的`case 1`,之所以用**花括號**包裹起來的原因是,這樣才能在里面定義**本地變量**,直接在冒號后面定義是**編譯錯(cuò)誤**,這個(gè)特性可能比較少用,這里提一下,前面也有說過。