你也可以上程序咖(https://meta.chengxuka.com),打開大學(xué)幕題板塊,不但有答案,講解,還可以在線答題。

題目1:什么是文件型指針?通過文件指針訪問文件有什么好處?
答:
緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡稱“文件指針”。每個被使用的文件都在內(nèi)存中開辟一個相應(yīng)的文件信息區(qū),用來存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當前位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)聲明的,取名為FILE。所以,在C語言上,文件型指針就是指FILE類型的指針,它指向一個文件類型的結(jié)構(gòu),結(jié)構(gòu)里包含著該文件的各種屬性。
通過文件指針訪問文件的好處是:可以隨機訪問文件,有效表示數(shù)據(jù)結(jié)構(gòu),動態(tài)分配內(nèi)存,方便使用字符串,有效使用數(shù)組。
題目2:對文件的打開與關(guān)閉的含義是什么?為什么要打開和關(guān)閉文件?
答:
打開文件,是建立文件的各種相關(guān)信息,并使文件類型指針指向該文件,以便進行其它操作。而關(guān)閉文件操作可強制把緩沖區(qū)中的數(shù)據(jù)寫入磁盤文件,保證文件的完整性,同時還將釋放文件緩沖區(qū)單元和FILE結(jié)構(gòu),使文件類型指針與具體文件脫鉤。
要對一個文件進行操作,必須先將其打開,讀寫完畢后還要將其關(guān)閉,以防止不正常的操作。
”打開“是指為文件建立相應(yīng)的信息區(qū)(用來存放有關(guān)文件的信息)和文件緩沖區(qū)(用來暫時存放輸出的數(shù)據(jù))。
”關(guān)閉“是指撤銷文件信息區(qū)和文件緩沖區(qū),使文件指針變量不再指向該文件,顯然就無法進行對文件的讀寫了。
題目3:從鍵盤輸入一個字符串,將其中的小寫字母全部轉(zhuǎn)換成大寫字母,然后輸出到一個磁盤文件 test中保存,輸入的字符串以"!"結(jié)束。
解:
答案代碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char str[100];
int i = 0;
if ((fp = fopen("test.txt", "w")) == NULL)
{
printf("can not open file\n");
exit(0);
}
printf("input a string:\n");
gets(str);
while (str[i] != '!')
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] = str[i] - 32;
fputc(str[i], fp);
i++;
}
fclose(fp);
fp = fopen("test.txt", "r");
fgets(str, strlen(str) + 1, fp);
printf("%s\n", str);
fclose(fp);
return 0;
}
運行結(jié)果:

可以發(fā)現(xiàn)多了一個文件:test.txt,我們打開它:

題目4:有兩個磁盤文件A和B,各存放一行字母,今要求把這兩個文件中的信息合并(按字母順序排列),輸出到一個新文件C中去。
解:先用第 3 題的程序分別建立兩個文件 A 和 B ,其中內(nèi)容分別是 "I LOVE CHINA" 和 "I LOVE BEIJING" 。在程序中先分別將 A,B 文件的內(nèi)容讀出放到數(shù)組 c 中,再對數(shù)組 c 排序。最后將數(shù)組內(nèi)容寫到 C 文件中。流程圖如圖10.1所示。

程序如下∶
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
int i, j, n, i1;
char c[100], t, ch;
if ((fp = fopen("a1", "r")) == NULL)
{
printf("\ncan not open file\n");
exit(0);
}
printf("file A :\n");
for (i = 0; (ch = fgetc(fp)) != EOF; i++)
{
c[i] = ch;
putchar(c[i]);
}
fclose(fp);
i1 = i;
if ((fp = fopen("b1", "r")) == NULL)
{
printf("\ncan not open file\n");
exit(0);
}
printf("\nfile B:\n");
for (i = i1; (ch = fgetc(fp)) != EOF; i++)
{
c[i] = ch;
putchar(c[i]);
}
fclose(fp);
n = i;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
if (c[i] > c[j])
{
t = c[i];
c[i] = c[j];
c[j] = t;
}
printf("\nfile C :\n");
fp = fopen("c1", "w");
for (i = 0; i < n; i++)
{
putc(c[i], fp);
putchar(c[i]);
}
printf("\n");
fclose(fp);
return 0;
}
首先要創(chuàng)建文件a1和b1,里面分別存入題目要求的文本內(nèi)容。然后再運行程序。
運行結(jié)果:

題目5:有 5 個學(xué)生,每個學(xué)生有 3 門課程的成績,從鍵盤輸入學(xué)生數(shù)據(jù)(包括學(xué)號,姓名,3 門課程成績),計算出平均成績,將原有數(shù)據(jù)和計算出的平均分數(shù)存放在磁盤文件 stud 中。
解:
解法一:N-S圖如圖10.2所示。

答案代碼:
#include <stdio.h>
struct student
{
char num[10];
char name[8];
int score[3];
float ave;
} stu[5];
int main()
{
int i, j, sum;
FILE *fp;
for (i = 0; i < 5; i++)
{
printf("\ninput score of student %d:\n", i + 1);
printf("NO.:");
scanf("%s", stu[i].num);
printf("name:");
scanf("%s", stu[i].name);
sum = 0;
for (j = 0; j < 3; j++)
{
printf("score %d:", j + 1);
scanf("%d", &stu[i].score[j]);
sum += stu[i].score[j];
}
stu[i].ave = sum / 3.0;
}
//將數(shù)據(jù)寫入文件
fp = fopen("stud", "w");
for (i = 0; i < 5; i++)
if (fwrite(&stu[i], sizeof(struct student), 1, fp) != 1)
printf("file write error\n");
fclose(fp);
fp = fopen("stud", "r");
for (i = 0; i < 5; i++)
{
fread(&stu[i], sizeof(struct student), 1, fp);
printf("\n%s,%s,%d,%d,%d,%6.2f\n", stu[i].num, stu[i].name, stu[i].score[0], stu[i].score[1], stu[i].score[2], stu[i].ave);
}
return 0;
}
運行結(jié)果:

說明:在程序的第 1 個 for 循環(huán)中,有兩個 printf 函數(shù)語句用來提示用戶輸入數(shù)據(jù),即"printf("input score of student %d∶\n",i+1);" 和 "printf("score %d;",j+1);" ,其中用 "i十1" 和 "j十1" 而不是用 i 和 j 的用意是使顯示提示時,序號從 1 起,即學(xué)生 1 和成績 1(而不是學(xué)生 0 和成績 0 ),以符合們的習慣,但在內(nèi)存中數(shù)組元素下標仍從 0 算起。
程序最后 5 行用來檢查文件 stud 中的內(nèi)容是否正確,從結(jié)果來看,是正確的。請注意:用 fwrite 函數(shù)向文件輸出數(shù)據(jù)時不是按 ASCII 碼方式輸出的,而是按內(nèi)存中存儲數(shù)據(jù)的方式輸出的(例如一個整數(shù)占 2 個或 4 個字節(jié),一個實數(shù)占 4 個字節(jié)),因此不能用 DOS 的 type 命令輸出該文件中的數(shù)據(jù)。
解法二:也可以用下面的程序來實現(xiàn):
#include <stdio.h>
#define SIZE 5
struct student
{
char name[10];
int num;
int score[3];
float ave;
} stud[SIZE];
int main()
{
void save(void); //函數(shù)聲明
int i;
float sum[SIZE];
FILE *fp1;
for (i = 0; i < SIZE; i++) //輸入數(shù)據(jù),并求每個學(xué)生的平均分
{
scanf("%s %d %d %d %d", stud[i].name, &stud[i].num, &stud[i].score[0], &stud[i].score[1], &stud[i].score[2]);
sum[i] = stud[i].score[0] + stud[i].score[1] + stud[i].score[2];
stud[i].ave = sum[i] / 3;
}
save(); //調(diào)用 save 函數(shù),向文件 stu.dat 輸出數(shù)據(jù)
fp1 = fopen("stu.dat", "rb"); //用只讀方式打開 stu. dat文件
printf("\n name NO. score1 score2 score3 ave\n");
printf("----------------------------------------\n"); //輸出表頭
for (i = 0; i < SIZE; i++) //從文件讀入數(shù)據(jù)并在屏幕輸出
{
fread(&stud[i], sizeof(struct student), 1, fp1);
printf("%-10s %3d %7d %7d %7d %8.2f\n", stud[i].name, stud[i].num, stud[i].score[0], stud[i].score[1], stud[i].score[2], stud[i].ave);
}
fclose(fp1);
return 0;
}
void save(void) //向文件輸出數(shù)據(jù)的函數(shù):
{
FILE *fp;
int i;
if ((fp = fopen("stu.dat", "wb")) == NULL)
{
printf("The file can not open\n");
return;
}
for (i = 0; i < SIZE; i++)
if (fwrite(&stud[i], sizeof(struct student), 1, fp) != 1)
{
printf("file write error\n");
return;
}
fclose(fp);
}
運行結(jié)果∶

本程序用 save 函數(shù)將數(shù)據(jù)寫到磁盤文件上,再從文件讀回,然后用 printf 函數(shù)輸出,從運行結(jié)果可以看到文件中的數(shù)據(jù)是正確的。
題目6:將第 5 題 stud 文件中的學(xué)生數(shù)據(jù),按平均分進行排序處理,將已排序的學(xué)生數(shù)據(jù)存入一個新文件 stu_sort 中。
解:
解法一:N-S圖如圖10.3所示。

答案代碼:
#include <stdio.h>
#include <stdlib.h>
#define N 10
struct student
{
char num[10];
char name[8];
int score[3];
float ave;
} st[N], temp;
int main()
{
FILE *fp;
int i, j, n;
//讀文件
if ((fp = fopen("stud", "r")) == NULL)
{
printf("can not open.\n");
exit(0);
}
printf("File 'stud':");
for (i = 0; fread(&st[i], sizeof(struct student), 1, fp) != 0; i++)
{
printf("\n%8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
printf("\n");
fclose(fp);
n = i;
//排序
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
if (st[i].ave < st[j].ave)
{
temp = st[i];
st[i] = st[j];
st[j] = temp;
}
//輸出
printf("\nNow:");
fp = fopen("stu_sort", "w");
for (i = 0; i < n; i++)
{
fwrite(&st[i], sizeof(struct student), 1, fp);
printf("\n%8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
printf("\n");
fclose(fp);
return 0;
}
運行結(jié)果:

解法二:與第5題解法二相應(yīng),可以接著使用下面的程序來實現(xiàn)本題要求。
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
struct student
{
char name[10];
int num;
int score[3];
float ave;
} stud[SIZE], work;
int main()
{
void sort(void);
int i;
FILE *fp;
sort();
fp = fopen("stud_sort.dat", "rb");
printf("sorted student's scores list as follow\n");
printf("------------------------------------------------------\n");
printf("NAME N0. SCORE1 SCORE2 SCORE3 AVE\n");
printf("------------------------------------------------------\n");
for (i = 0; i < SIZE; i++)
{
fread(&stud[i], sizeof(struct student), 1, fp);
printf("%-10s %3d %8d %8d %8d %9.2f\n", stud[i].name, stud[i].num, stud[i].score[0], stud[i].score[1], stud[i].score[2], stud[i].ave);
}
fclose(fp);
return 0;
}
void sort(void)
{
FILE *fp1, *fp2;
int i, j;
if ((fp1 = fopen("stu.dat", "rb")) == NULL)
{
printf("The file can not open\n\n");
exit(0);
}
if ((fp2 = fopen("stud_sort.dat", "wb")) == NULL)
{
printf("The file write error\n");
exit(0);
}
for (i = 0; i < SIZE; i++)
if (fread(&stud[i], sizeof(struct student), 1, fp1) != 1)
{
printf("file read error\n");
exit(0);
}
for (i = 0; i < SIZE; i++)
{
for (j = i + 1; j < SIZE; j++)
if (stud[i].ave < stud[j].ave)
{
work = stud[i];
stud[i] = stud[j];
stud[j] = work;
}
fwrite(&stud[i], sizeof(struct student), 1, fp2);
}
fclose(fp1);
fclose(fp2);
}
運行結(jié)果:

題目7:將第 6 題已排序的學(xué)生成績文件進行插入處理。插入一個學(xué)生的 3 門課程成績,程序先計算新插入學(xué)生的平均成績,然后將它按成績高低順序插入,插入后建立一個新文件。
解:N-S圖如圖10.4所示。

答案代碼:
#include <stdio.h>
#include <stdlib.h>
struct student
{
char num[10];
char name[8];
int score[3];
float ave;
} st[10], s;
int main()
{
FILE *fp, *fp1;
int i, j, t, n;
printf("\nNO.:");
scanf("%s", s.num);
printf("name:");
scanf("%s", s.name);
printf("score1,score2,score3:");
scanf("%d,%d,%d", &s.score[0], &s.score[1], &s.score[2]);
s.ave = (s.score[0] + s.score[1] + s.score[2]) / 3.0;
//從文件讀數(shù)據(jù)
if ((fp = fopen("stu_sort", "r")) == NULL)
{
printf("can not open file.");
exit(0);
}
printf("original data:\n");
for (i = 0; fread(&st[i], sizeof(struct student), 1, fp) != 0; i++)
{
printf("\n%8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
n = i;
for (t = 0; st[t].ave > s.ave && t < n; t++)
;
//向文件寫數(shù)據(jù)
printf("\nNow:\n");
fp1 = fopen("sort1.dat", "w");
for (i = 0; i < t; i++)
{
fwrite(&st[i], sizeof(struct student), 1, fp1);
printf("\n %8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
fwrite(&s, sizeof(struct student), 1, fp1);
printf("\n %8s %7s %7d %7d%7d%10.2f", s.num, s.name, s.score[0], s.score[1], s.score[2], s.ave);
for (i = t; i < n; i++)
{
fwrite(&st[i], sizeof(struct student), 1, fp1);
printf("\n %8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
printf("\n");
fclose(fp);
fclose(fp1);
return 0;
}
運行結(jié)果:

為節(jié)省篇幅,本題和第8題不再給出第6題"解法二"的程序,請讀者自已編寫程序。
題目8:將第 7 題結(jié)果仍存入原有的 stu_sort 文件而不另建立新文件。
解:
答案代碼:
#include <stdio.h>
#include <stdlib.h>
struct student
{
char num[10];
char name[8];
int score[3];
float ave;
} st[10], s;
int main()
{
FILE *fp, *fp1;
int i, j, t, n;
printf("\nNO.:");
scanf("%s", s.num);
printf("name:");
scanf("%s", s.name);
printf("score1,score2,score3:");
scanf("%d,%d,%d", &s.score[0], &s.score[1], &s.score[2]);
s.ave = (s.score[0] + s.score[1] + s.score[2]) / 3.0;
//從文件讀數(shù)據(jù)
if ((fp = fopen("stu_sort", "r")) == NULL)
{
printf("can not open file.");
exit(0);
}
printf("original data:\n");
for (i = 0; fread(&st[i], sizeof(struct student), 1, fp) != 0; i++)
{
printf("\n%8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
n = i;
for (t = 0; st[t].ave > s.ave && t < n; t++)
;
//向文件寫數(shù)據(jù)
printf("\nNow:\n");
fp1 = fopen("sort1.dat", "w");
for (i = 0; i < t; i++)
{
fwrite(&st[i], sizeof(struct student), 1, fp1);
printf("\n %8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
fwrite(&s, sizeof(struct student), 1, fp1);
printf("\n %8s %7s %7d %7d %7d %10.2f", s.num, s.name, s.score[0], s.score[1], s.score[2], s.ave);
for (i = t; i < n; i++)
{
fwrite(&st[i], sizeof(struct student), 1, fp1);
printf("\n %8s%8s", st[i].num, st[i].name);
for (j = 0; j < 3; j++)
printf("%8d", st[i].score[j]);
printf("%10.2f", st[i].ave);
}
printf("\n");
fclose(fp);
fclose(fp1);
return 0;
}
運行結(jié)果:

題目9:有一磁盤文件 employee ,內(nèi)存放職工的數(shù)據(jù)。每個職工的數(shù)據(jù)包括職工姓名、職工號、性別、年齡、住址、工資、健康狀況、文化程度。今要求將職工名、工資的信息單獨抽出來另建一個簡明的職工工資文件。
解:N-S圖如圖10.5所示。

答案代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct employee
{
char num[6];
char name[10];
char sex[2];
int age;
char addr[20];
int salary;
char health[8];
char class[10];
} em[10];
struct emp
{
char name[10];
int salary;
} em_case[10];
int main()
{
FILE *fp1, *fp2;
int i, j;
if ((fp1 = fopen("employee", "r")) == NULL)
{
printf("can not open file.\n");
exit(0);
}
printf("\n NO. name sex age addr salary health class\n");
for (i = 0; fread(&em[i], sizeof(struct employee), 1, fp1) != 0; i++)
{
printf("\n%4s%8s%4s%6d%10s%6d%10s%8s", em[i].num, em[i].name, em[i].sex, em[i].age, em[i].addr, em[i].salary, em[i].health, em[i].class);
strcpy(em_case[i].name, em[i].name);
em_case[i].salary = em[i].salary;
}
printf("\n\n**************************************************");
if ((fp2 = fopen("emp_salary", "wb")) == NULL)
{
printf("can not open file\n");
exit(0);
}
for (j = 0; j < i; j++)
{
if (fwrite(&em_case[j], sizeof(struct emp), 1, fp2) != 1)
printf("error!");
printf("\n %12s%10d", em_case[j].name, em_case[j].salary);
}
printf("\n\n**************************************************");
fclose(fp1);
fclose(fp2);
return 0;
}
運行結(jié)果:

說明:數(shù)據(jù)文件 employee 是事先建立好的,其中已有職工數(shù)據(jù),而 emp_salary 文件則是由程序建立的。
建立 employee 文件的程序如下:
#include <stdio.h>
#include <stdlib.h>
struct employee
{
char num[6];
char name[10];
char sex[2];
int age;
char addr[20];
int salary;
char health[8];
char class[10];
} em[10];
int main()
{
FILE *fp;
int i;
printf("input NO.,name,sex,age,addr,salary,health,class\n");
for (i = 0; i < 4; i++)
scanf("%s %s %s %d %s %d %s %s", em[i].num, em[i].name, em[i].sex, &em[i].age, em[i].addr, &em[i].salary, em[i].health, em[i].class);
//將數(shù)據(jù)寫入文件
if ((fp = fopen("employee", "w")) == NULL)
{
printf("can not open file.");
exit(0);
}
for (i = 0; i < 4; i++)
if (fwrite(&em[i], sizeof(struct employee), 1, fp) != 1)
printf("error\n");
fclose(fp);
return 0;
}
在運行此程序時從鍵盤輸入4個職工的數(shù)據(jù),程序?qū)⑺鼈儗懭?employee 文件。在運行前面一個程序時從 employee 文件中讀出數(shù)據(jù)并輸出到屏幕,然后建立一個簡明文件,同時在屏幕上輸出。

題目10:從第 9 題的"職工工資文件"中刪去一個職工的數(shù)據(jù),再存回原文件。
解:N-S圖如圖10.6所示。

答案代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct employee
{
char name[10];
int salary;
} emp[20];
int main()
{
FILE *fp;
int i, j, n, flag;
char name[10];
if ((fp = fopen("emp_salary", "rb")) == NULL)
{
printf("can not open file.\n");
exit(0);
}
printf("\noriginal data:\n");
for (i = 0; fread(&emp[i], sizeof(struct employee), 1, fp) != 0; i++)
printf("\n %8s %7d", emp[i].name, emp[i].salary);
fclose(fp);
n = i;
printf("\ninput name deleted:\n");
scanf("%s", name);
for (flag = 1, i = 0; flag && i < n; i++)
{
if (strcmp(name, emp[i].name) == 0)
{
for (j = i; j < n - 1; j++)
{
strcpy(emp[i].name, emp[+1].name);
emp[j].salary = emp[j + 1].salary;
}
flag = 0;
}
}
if (!flag)
n = n - 1;
else
printf("\nnot found!");
printf("\nNow,The content of file:\n");
if ((fp = fopen("emp_salary", "wb")) == NULL)
{
printf("can not open file\n");
exit(0);
}
for (i = 0; i < n; i++)
fwrite(&emp[i], sizeof(struct employee), 1, fp);
fclose(fp);
fp = fopen("emp_salary", "r");
for (i = 0; fread(&emp[i], sizeof(struct employee), 1, fp) != 0; i++)
printf("\n%8s %7d", emp[i].name, emp[i].salary);
printf("\n");
fclose(fp);
return 0;
}
運行結(jié)果:

題目11:從鍵盤輸入若干行字符(每行長度不等),輸入后把它們存儲到一磁盤文件中。再從該文件中讀入這些數(shù)據(jù),將其中小寫字母轉(zhuǎn)換成大寫字母后在顯示屏上輸出。
解:N-S圖如圖 10.7所示。

答案代碼:
#include <stdio.h>
int main()
{
int i, flag;
char str[80], c;
FILE *fp;
fp = fopen("text", "w");
flag = 1;
while (flag == 1)
{
printf("input string:\n");
gets(str);
fprintf(fp, "%s\n", str);
printf("continue?");
c = getchar();
if ((c == 'N') || (c == 'n'))
flag = 0;
getchar();
}
fclose(fp);
fp = fopen("text", "r");
while (fscanf(fp, "%s", str) != EOF)
{
for (i = 0; str[i] != '\0'; i++)
if ((str[i] >= 'a') && (str[i] <= 'z'))
str[i] -= 32;
printf("%s\n", str);
}
fclose(fp);
return 0;
}
運行結(jié)果:

此程序運行結(jié)果是正確的,但是如果輸入的字符串中包含了空格,就會發(fā)生一些問題,例如輸入:
inut string:
i am a student.
得到的結(jié)果是:
I
AM
A
STUDENT.
把一行分成幾行輸出。這是因為用fscanf 函數(shù)從文件讀入字符串時,把空格作為一個字符串的結(jié)束標志,因此把該行作為 4 個字符串來處理,分別輸出在 4 行上。請讀者考慮怎樣解決這個問題。
