成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

動(dòng)態(tài)文件版通訊錄及C語言中的文件的讀寫操作

h9911 / 1388人閱讀

摘要:那么我們首先來改造儲(chǔ)存空間也就是通訊錄結(jié)構(gòu)體靜態(tài)版本人信息存放在數(shù)組中統(tǒng)計(jì)存放的人數(shù)動(dòng)態(tài)版本統(tǒng)計(jì)存放的人數(shù)有效容量我們將原本的結(jié)構(gòu)體數(shù)組改為一個(gè)結(jié)構(gòu)體指針,以此來維護(hù)用以儲(chǔ)存?zhèn)€人信息的空間。

上一期我們編寫了一個(gè)C語言版本的簡易通訊錄,但是我們的之前的通訊錄是沒有記憶功能的,也就是說,一旦關(guān)閉了程序我們存儲(chǔ)在里面的數(shù)據(jù)也就消失了。那么今天我們就來實(shí)現(xiàn)一個(gè)附帶數(shù)據(jù)儲(chǔ)存的通訊錄。

在此之前,我們先來了解一下C語言中文件的讀寫函數(shù):

1.fopen及fclose

fopen的作用是打開我們計(jì)算機(jī)儲(chǔ)存的某個(gè)文件,函數(shù)返回值是FILE*類型,需要兩個(gè)參數(shù):1.文件路徑 2.操作類型。下面我們來演示一下:

int main(){	FILE* pf = fopen("data.txt", "r");	//打開文件	if (pf == NULL)	{		perror("fopen");		return -1;	}	//讀文件	//關(guān)閉文件	fclose(pf);	pf = NULL;	return 0;}

我們?cè)囍\(yùn)行這段代碼:

我們?cè)O(shè)置的錯(cuò)誤函數(shù)提醒我們不存在該文件。

關(guān)于參數(shù):

一.文件路徑:我們?cè)谑褂迷摵瘮?shù)的時(shí)候,打開文件所用的路徑有兩種:1.絕對(duì)路徑 2.相對(duì)路徑。

下面我們一一演示一下:

1.絕對(duì)路徑:

int main(){	FILE* pf = fopen("C://Users//win10//Desktop//data.txt", "r");	//打開文件	if (pf == NULL)	{		perror("fopen");		return -1;	}	//讀文件	//關(guān)閉文件	fclose(pf);	pf = NULL;	return 0;}

?要注意使用絕對(duì)路徑時(shí),原本"/"處我們應(yīng)再加上一條“/”,防止其變成轉(zhuǎn)義字符導(dǎo)致路徑失效。我們運(yùn)行看看:

現(xiàn)在我們可以看到程序運(yùn)行成功沒有報(bào)錯(cuò)。

2.相對(duì)路徑:相對(duì)路徑是指將文件放置在源文件的文件夾內(nèi)

int main(){	FILE* pf = fopen("data.txt", "r");	//打開文件	if (pf == NULL)	{		perror("fopen");		return -1;	}	//讀文件	//關(guān)閉文件	fclose(pf);	pf = NULL;	return 0;}

運(yùn)行結(jié)果與絕對(duì)路徑一致。

二.操作符號(hào)

下面我們嘗試在文件中寫入一些我們想要的數(shù)據(jù)。

int main(){	FILE* pf = fopen("data.txt", "w");	//打開文件	if (pf == NULL)	{		perror("fopen");		return -1;	}	//寫文件	fputc("h", pf);	fputc("e", pf);	fputc("l", pf);	fputc("l", pf);	fputc("o", pf);	//關(guān)閉文件	fclose(pf);	pf = NULL;	return 0;}

?可以注意到,我們使用的是相對(duì)路徑,打開后的操作為寫。寫入數(shù)據(jù)的函數(shù)為fputs,該函數(shù)一次只能輸入一個(gè)字符,第一個(gè)參數(shù)為想要輸入的字符,第二個(gè)參數(shù)為先前打開文件返回的地址。下面我們來看一下運(yùn)行結(jié)果:

看起來好像什么都沒有發(fā)生,實(shí)際上:

打開文檔的時(shí)候我們發(fā)現(xiàn),我們想要的東西已經(jīng)寫入到了文檔中。

int main(){	FILE* pf = fopen("data.txt", "w");	//打開文件	if (pf == NULL)	{		perror("fopen");		return -1;	}	//讀文件	/*fputc("h", pf);	fputc("e", pf);	fputc("l", pf);	fputc("l", pf);	fputc("o", pf);*/	fputs("hello", pf);	//關(guān)閉文件	fclose(pf);	pf = NULL;	return 0;}

?另外我們也可以使用fputs函數(shù),一次可以輸入一串字符串(如上圖所示)。

實(shí)現(xiàn)了寫入的方法后,我們不禁會(huì)去思考,既然可以把數(shù)據(jù)寫入一個(gè)我們準(zhǔn)備好的文檔,那么我們是否也可以從那個(gè)文檔中拿出我們想要的數(shù)據(jù)呢?答案是肯定的。下面我們就來讀取我們剛剛寫入到文檔中的"hello"。

int main(){	FILE* pf = fopen("data.txt", "r");	if (pf == NULL)	{		perror("fopen");		return -1;	}	int ch = getc(pf);	printf("%c", ch);	ch = getc(pf);	printf("%c", ch);	ch = getc(pf);	printf("%c", ch);	ch = getc(pf);	printf("%c", ch);	ch = getc(pf);	printf("%c", ch);	fclose(pf);	pf = NULL;	return 0;}

我們首先使用fopen函數(shù)打開文件,然后使用命令"r",也就是讀取命令。讀取字符的函數(shù)我們使用的是getc函數(shù)。該函數(shù)每次可以讀取一個(gè)字符,每讀取一次就會(huì)向后跳動(dòng)一個(gè)字符,因此我們使用五次就可以讀取我們先前儲(chǔ)存在文檔中的單詞了,沒讀取一次我們就將它打在屏幕上:

我們也可以通過fgets函數(shù)一次性讀取一行的數(shù)據(jù):

int main(){	char arr[20] = { 0 };	FILE* pf = fopen("data.txt", "r");	if (pf == NULL)	{		perror("fopen");		return -1;	}	char* ch = fgets(arr,6,pf);    printf("%s",arr);	fclose(pf);	pf = NULL;	return 0;}

?它的三個(gè)參數(shù)分別是:1.讀取后儲(chǔ)存的位置 2.讀取的字符(n-1個(gè),因此在設(shè)置參數(shù)時(shí)應(yīng)比想要讀取的字符要多一個(gè))3.源數(shù)據(jù)地址。

我們可以看到這個(gè)函數(shù)也很好的實(shí)現(xiàn)了一樣的功能。

下面我們來介紹一下今天用于改造通訊錄的兩個(gè)函數(shù):fread,fwrite?

我們直接來看一下fwrite的用法:

struct S {	int n;	double x;	char name[10];};int main(){	struct S a = { 10,3.14,"張三" };	FILE* pf = fopen("data.txt", "w");	if (pf == NULL)	{		perror(fopen);		return -1;	}	fwrite(&a, sizeof(a), 1, pf);	fclose(pf);	pf = NULL;	return 0;}

該函數(shù)一共需要四個(gè)參數(shù):1.數(shù)據(jù)地址 2.數(shù)據(jù)大小 3.每次寫入的個(gè)數(shù) 4.寫到什么地方

程序運(yùn)行結(jié)果:

該函數(shù)的寫入方式為二進(jìn)制,所以我們未必可以直接讀。

下面我們用fread來讀取一下:?

struct S {	int n;	double x;	char name[10];};int main(){	//struct S a = { 10,3.14,"張三" };	struct S s = { 0 };	FILE* pf = fopen("data.txt", "wb");	if (pf == NULL)	{		perror(fopen);		return -1;	}	//fwrite(&a, sizeof(a), 1, pf);	fread(&s, sizeof(struct S), 1, pf);	printf("%d %lf %s",s.n, s.x, s.name);	fclose(pf);	pf = NULL;	return 0;}

運(yùn)行結(jié)果:

知道這些函數(shù)的作用和用法之后我們就可以開始對(duì)通訊錄進(jìn)行改造了!

首先,我們先前的通訊錄的儲(chǔ)存版本是1000個(gè)人的數(shù)據(jù),但是在實(shí)際生活當(dāng)中,因?yàn)槊總€(gè)人的情況不一樣我們是用不了那么大的容量的。那么我們首先來實(shí)現(xiàn)通訊錄的動(dòng)態(tài)版本!

首先我們要改造的是存放數(shù)據(jù)的空間,原先我們是創(chuàng)造了一個(gè)結(jié)構(gòu)體,在結(jié)構(gòu)體內(nèi)定義了一個(gè)結(jié)構(gòu)體數(shù)組,數(shù)組元素個(gè)數(shù)是1000,以及一個(gè)用來記錄儲(chǔ)存人數(shù)的整形。

那么如果我們想要一個(gè)可有隨儲(chǔ)存人數(shù)變化而變化的空間,那么我們就需要以下幾步:1.開辟初始空間 2.檢查空間是否充足 3.充足(存入數(shù)據(jù));不充足(開辟新空間)4.存入新數(shù)據(jù)。

那么我們首先來改造儲(chǔ)存空間也就是通訊錄結(jié)構(gòu)體:

靜態(tài)版本//struct contact//{//	struct peoinfo data [max];//100人信息存放在數(shù)組中//	int sz;//統(tǒng)計(jì)存放的人數(shù)//};動(dòng)態(tài)版本struct contact{	struct peoinfo* data;	int sz;//統(tǒng)計(jì)存放的人數(shù)	int capacity;//有效容量};

我們將原本的結(jié)構(gòu)體數(shù)組改為一個(gè)結(jié)構(gòu)體指針,以此來維護(hù)用以儲(chǔ)存?zhèn)€人信息的空間。同時(shí)我們?cè)黾恿艘粋€(gè)整形變量capacity,它代表的是有效的容量,在后期增加人數(shù)的時(shí)候,當(dāng)有效容量等于儲(chǔ)存人數(shù)的時(shí)候我們就需要開辟新的空間用以儲(chǔ)存新的人員信息。

當(dāng)儲(chǔ)存空間開辟方式發(fā)生變化,那么初始化函數(shù)也應(yīng)當(dāng)隨之變化:

///靜態(tài)版本//void initcontact(struct contact* con)//{//	con->sz = 0;//	memset(con->date,0,sizeof(struct peoinfo));//	//memset(con->date, 0, sizeof(con->date));//}//動(dòng)態(tài)版本void initcontact(struct contact* con){	con->sz = 0;	con->data = (struct peoinfo* )malloc(def * sizeof(struct peoinfo ));//開辟空間	con->capacity = def;}

原本靜態(tài)的初始化函數(shù)只是將sz,儲(chǔ)存信息都初始化為0,在動(dòng)態(tài)版本中,我們?cè)O(shè)置初始化容量為3(原本是1000),同時(shí)使用malloc函數(shù)將空間開辟為能夠儲(chǔ)存三個(gè)人信息的大小同時(shí)將這塊空間的指針轉(zhuǎn)化為結(jié)構(gòu)體類型傳遞給我們剛剛設(shè)置的data指針。

到這里,之前我們提到的三步我們完成了第一步,現(xiàn)在我們要開始第二步:2.檢查空間是否充足 3.充足(存入數(shù)據(jù));不充足(開辟新空間)

原本的靜態(tài)增加聯(lián)系人的函數(shù)我們只有判斷空間是否充足+新增聯(lián)系人兩步。而現(xiàn)在我們要加入第三步:空間不足時(shí)開辟新的空間。

void checksize(struct contact* con)	{		if (con->sz == con->capacity)		{			struct peoinfo* ptr = (struct peoinfo*)realloc(con->data,              (con->capacity + 2) * sizeof(struct peoinfo));			if (ptr != NULL)			{				con->data = ptr;				printf("增容成功!/n");				con->capacity += 2;			}			else			{				exit(1);			}		}//檢查容量	}

首先我們封裝一個(gè)判斷函數(shù),一進(jìn)入該函數(shù)首先檢查sz是否等于有效容量,如果容量不足我們就使用realloc函數(shù)開辟新的空間;需要注意的是,如果函數(shù)增容成功會(huì)返回一個(gè)非空指針,因此我們可以以此來判斷是否增容成功,如果失敗率則異常退出。

下面是完整的增加函數(shù):

void modifycontact(struct contact* con)	{		int as = searcontact(con);		if (as >= 0)		{			printf("請(qǐng)輸入聯(lián)系人姓名:");			scanf("%s", con->data[con->sz].name);			printf("請(qǐng)輸入聯(lián)系人年齡:");			scanf("%d", &con->data[con->sz].age);			printf("請(qǐng)輸入聯(lián)系人性別:");			scanf("%s", con->data[con->sz].sex);			printf("請(qǐng)輸入聯(lián)系人電話:");			scanf("%s", con->data[con->sz].tele);			printf("請(qǐng)輸入聯(lián)系人住址:");			scanf("%s", con->data[con->sz].adr);			printf("修改成功!/n");			con->sz++;//儲(chǔ)存人數(shù)加一		}	}

到這里我們的通訊錄的空間就可以隨著儲(chǔ)存人數(shù)的增加而增加了,但是這不意味著就結(jié)束了。那些我們開辟用來存放數(shù)據(jù)的空間在程序結(jié)束以后應(yīng)當(dāng)重新釋放掉,所以我們還有最后一步:銷毀通訊錄。

void destory(struct contact* con)	{		con->sz = 0;		con->capacity = 0;		free(con->data);		con->data = NULL;	}

我們用這個(gè)函數(shù)將人數(shù)和有效容量定義為0,同時(shí)釋放掉我們之前開辟的空間放置內(nèi)存泄漏。最后將data置為空指針。

到這里我們就將之前的通訊錄成功改造成了動(dòng)態(tài)內(nèi)存的版本,但是這樣說的通訊錄依舊是不完美的,我們每次進(jìn)入通訊錄都需要重新錄入信息才能使用,如果是這樣這通訊錄也就失去了它的價(jià)值,那么我們接下來將通訊錄再次改造使他成為具有記憶功能。

實(shí)現(xiàn)記憶功能我們分為下面兩大步:1.將之前輸入的數(shù)據(jù)輸入到我們實(shí)現(xiàn)準(zhǔn)備好的文檔 2.啟動(dòng)通訊錄進(jìn)行初始化后讀取文檔內(nèi)的信息

下面我們實(shí)現(xiàn)第一步:將數(shù)據(jù)輸入到文檔中。

我們事先創(chuàng)建好一個(gè)TXT文檔在源文件的文件夾當(dāng)中,我們?cè)诮Y(jié)束時(shí)中加入寫入函數(shù):

case EXIT:			//儲(chǔ)存通訊錄數(shù)據(jù)			savecontact(&con);			destory(&con);			printf("退出通訊錄!/n");			break;		

下面是儲(chǔ)存函數(shù)實(shí)現(xiàn):

void savecontact(struct contact* con)	{		//打開文件		FILE* pf = fopen("contact.txt", "wb");		if (pf == NULL)		{			perror("savecontact::fopen");			return;//結(jié)束函數(shù)		}		//寫入數(shù)據(jù)		int i = 0;		for (i = 0; i < con->sz; i++)		{			fwrite(con->data+i, sizeof(struct contact), 1, pf);		}		//關(guān)閉文件		fclose(pf);		pf = NULL;	}

通訊錄有幾個(gè)人的信息我們就寫入幾次,該功能的實(shí)現(xiàn)主要依靠fwirte函數(shù),該函數(shù)的使用我們已經(jīng)在開頭介紹過就不在詳述了。

第二步:初始化讀取信息

void initcontact(struct contact* con){	con->sz = 0;	con->data = (struct peoinfo* )malloc(def * sizeof(struct peoinfo ));//開辟空間	if (con->data == NULL)	{		perror(con->data);		return;	}	con->capacity = def;	//加載數(shù)據(jù)	loadcontact(con);}

我們?cè)谧詈蠹尤爰虞d函數(shù),下面是加載函數(shù)的代碼:

void loadcontact(struct contact* con)	{		int i = 0;		FILE* pf = fopen("contact.txt", "rb");		if (pf == NULL)		{			printf("加載失敗/n");			return;		}		struct peoinfo tmp = { 0 };		while (fread(&tmp, sizeof(struct peoinfo), 1, pf))		{			checksize(con);			con->data[con->sz] = tmp;			con->sz++;			printf("加載成功!/n");		}		//關(guān)閉文件		fclose(pf);		pf = NULL;	}

需要注意的是,我們每讀取一個(gè)數(shù)據(jù)前都要檢查一下容量是否充足,所以我們調(diào)用了之前寫的判斷函數(shù)。每讀取一次,我們就將信息儲(chǔ)存到我們用來保存信息的結(jié)構(gòu)體中,同時(shí)有效容量和人數(shù)都++一次。最后加載完成關(guān)閉文件。

到這里,通訊錄就改造完成了哦。喜歡的話就一鍵三連吧!謝謝大家!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/121534.html

相關(guān)文章

  • C語言實(shí)現(xiàn)訊錄(靜態(tài))

    摘要:二靜態(tài)通訊錄接口函數(shù)實(shí)現(xiàn)文件名功能通訊錄函數(shù)接口的實(shí)現(xiàn)宏定義,頭文件,接口函數(shù)的聲明函數(shù)接口測試靜態(tài)通訊錄的基本結(jié)構(gòu)通訊錄是一個(gè)結(jié)構(gòu)體。 前言:之前,博主已經(jīng)寫過兩個(gè)有意思的小項(xiàng)目:三子棋和掃雷,接下來,博主繼續(xù)更新一個(gè)小項(xiàng)目-通訊錄,包括3種版本,靜態(tài)版,動(dòng)態(tài)版,文件保存版。接下來,我們先...

    szysky 評(píng)論0 收藏0
  • 全棧開發(fā)自學(xué)路線

    摘要:前言這里筑夢師是一名正在努力學(xué)習(xí)的開發(fā)工程師目前致力于全棧方向的學(xué)習(xí)希望可以和大家一起交流技術(shù)共同進(jìn)步用簡書記錄下自己的學(xué)習(xí)歷程個(gè)人學(xué)習(xí)方法分享本文目錄更新說明目錄學(xué)習(xí)方法學(xué)習(xí)態(tài)度全棧開發(fā)學(xué)習(xí)路線很長知識(shí)拓展很長在這里收取很多人的建議以后決 前言 這里筑夢師,是一名正在努力學(xué)習(xí)的iOS開發(fā)工程師,目前致力于全棧方向的學(xué)習(xí),希望可以和大家一起交流技術(shù),共同進(jìn)步,用簡書記錄下自己的學(xué)習(xí)歷程...

    galaxy_robot 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<