c语言中void plusone,《C Primer Plus》第6版 编程练习答案参考 第十三章(全)

《C Primer Plus》第6版 编程练习 第十三章

目录(如果无法使用,可以选用右侧的目录选项)教程连接

先看这里(很重要!):

函数原型:

fopen_()   :

fgetc() 和 fputc():

rewind() 函数:

源码 + 题目 + 运行效果:

Pe13-1:

Pe13-2:

Pe13-3:

Pe13-4:

Pe13-5:

Pe13-6:

Pe13-7:

Pe13-8:

Pe13-9:

Pe13-10:

Pe13-11:

Pe13-12:

P13-14:

关于第14章的,这里先说:

先看这里(很重要!):

本书中所有使用的 fpoen() 函数由于 VS2017 提示不安全

所以全部使用 fopen_s() 函数代替,函数原型下面会一一展示出来。

恳请各位大佬使用 PC 端 查看,美感,很重要的!!!

编译环境 : VS 2017 Community

代码可以直接复制编译

对了,如果各位大佬们在编译代码时出现一些奇奇怪怪的错误,比如未定义或未声明,

可以看这个教程                 教程连接   ←   如果出现了某些错误,可以看看这篇文章!感谢!

函数原型:

fopen_()   :

_ACRTIMP errno_t __cdecl fopen_s(

_Outptr_result_maybenull_ FILE** _Stream,

_In_z_ char const* _FileName,

_In_z_ char const* _Mode

);

简单的说 就是:

返回值是 errno_t 类型,实际为int 类型,但我就用 errno_t 直接定义

typedef int errno_t;

所以后面的 errno_t 直接当作 int 就行了。

fopen_s() 函数

如果成功返回0,失败则返回相应的错误代码。

658a4268d75ea04d3d57bd7ddd5a1e23.png

开个玩笑哈!这是我测试的时候会这样(已经解决),下面是实际情况(我在 exit() 前加了 system("pause");)

f1b0dd02ee0a9c9244a9d5ae7f3b842c.png

一般情况下是一闪而过,直接退出的

还有就是传入的第一个参数 取文件指针的地址,

FILE * fp; //文件指针

errno_t err; //fopen_s() 返回errno_t (int)类型

char filename[30];//储存输入的文件名

/*获取文件名...*/

//第一个参数取文件指针的地址

//第二个参数取要打开文件的名称

//第三个参数不变,取模式

if ((err = fopen_s(&fp, filename, "r")) != 0)

/*一大堆.....结尾*/

fgetc() 和 fputc():

fgetc():

int fgetc (FILE * stream );

fgetc():

返回指定流的内部文件位置指示器当前指向的字符。然后将内部文件位置指示器推进到下一个字符。

如果在调用时流位于文件末尾, 则该函数返回 EOF 并设置流的文件结尾指示器 (feof).    (转至MSDN)

fputc():

int fputc (int character, FILE * stream );

fputc():

将字符写入流并前进位置指示器。

字符被写在由流的内部位置指示器指示的位置, 然后由一个自动推进.  (转至MSDN)

rewind() 函数:

rewind() (C库函数)功能:

将文件内部的指针重新指向一个流的开头

注意:不是文件指针而是文件内部的位置指针,

随着对文件的读写文件的位置指针(指向当前读写字节)向后移动。

而文件指针是指向整个文件,如果不重新赋值文件指针不会改变。

如果需要的,可以参考下面的 Pe13-7 练习题 或自行百度

源码 + 题目 + 运行效果:

Pe13-1:

/*

13-1 ----修改程序清单 13.1 中的程序,

要求提示用户输入文件名,并读取用户输入的信息,不使用命令行参数。

*/

#include

#include //提供 exit() 的原型

#define FNSIZE 30//用户输入文件名的长度

int main(void)

{

int ch; //读取文件时,储存每个字符的地方

FILE * fp; //文件指针

errno_t err;//fopen_s() 返回errno_t (int)类型

unsigned long count = 0;

char filename[FNSIZE]; //储存输入的文件名

printf("输入需要打开的文件名:");

while (scanf_s("%s", filename, FNSIZE) != 1)

{

printf("那不是一个有效的文件名,请输入正确的文件名:");

continue;//处理错误输入

}

if ((err = fopen_s(&fp, filename, "r")) != 0)

{

printf("打开 %s 文件失败, 退出中\n", filename);

exit(EXIT_FAILURE);//打开文件失败

}

while ((ch = getc(fp)) != EOF)

{

putc(ch, stdout);// 与 putchar(ch); 相同

count++;

}

fclose(fp);//关闭文件

printf("\n\n文件 %s 有 %lu 个字符\n", filename, count);

system("pause");

return 0;

}

89675ecf51381e4ea59595b6c66453c8.png

这里的49 个字符是包括换行符的(不包括文件结尾)

Pe13-2:

这里我(终于)使用了命令行参数

VS使用命令行参数的方法:       任意门

/*

13-2----编写一个文件拷贝程序,该程序通过命令行获取原始文件名。

尽量使用标准I/O 和二进制模式。

*/

#include

#include //提供 exit() 的原型

//拷贝文件函数(传递源文件名和目标文件名)

void cpyfile(const char * source, const char * target);

int main(int argc, char * argv[]) //使用命令行参数

{

int ch;

if (argc != 3)//命令行参数接收错误

{

puts("需要两个命令行参数,程序退出中......\n");

exit(EXIT_FAILURE);

}

cpyfile(argv[1], argv[2]); //拷贝文件函数

puts("文件拷贝完毕!\n");

while (ch = getchar()) //防止突然退出

{

continue;

}

return 0;

}

//拷贝文件函数

void cpyfile(const char * source, const char * target)

{

errno_t err; //fopen_s() 函数返回该类型(int)

FILE * fp1;

FILE * fp2;

int ch = 0;

if (err = fopen_s(&fp1, source, "rb") != 0)

{

printf("打开 %s 文件失败,退出中......\n", source);

exit(EXIT_FAILURE);

}

if (err = fopen_s(&fp2, target, "ab+") != 0)

{

printf("打开 %s 文件失败,退出中......\n", target);

/*因为先前打开源文件过了,所以需要关闭*/

if (fclose(fp1) != 0) //关闭源文件失败, 关闭成功返回0,否则EOF

{

printf("关闭 %s 文件失败,退出中......\n", source);

}

exit(EXIT_FAILURE);//只需要一个exit() 想想为什么

}

/* 成功打开两个文件后 */

while ((ch = fgetc(fp1)) != EOF)

{

fputc(ch, fp2);

/*

fgetc:

int fgetc (FILE * stream );

返回指定流的内部文件位置指示器当前指向的字符。

然后将内部文件位置指示器推进到下一个字符。

如果在调用时流位于文件末尾, 则该函数返回 EOF 并设置流的文件结尾指示器 (feof).

fputc:

int fputc (int character, FILE * stream );

将字符写入流并前进位置指示器。

字符被写在由流的内部位置指示器指示的位置, 然后由一个自动推进.

以上是MSDN的资料

使用这两个函数比使用 fread() 和 fwrite() 更简便

*/

}

//关闭文件

if (fclose(fp1) != 0)

{

printf("关闭 %s 文件失败,退出中......\n", source);

exit(EXIT_FAILURE);

}

if (fclose(fp2) != 0)

{

printf("关闭 %s 文件失败,退出中......\n", target);

exit(EXIT_FAILURE);

}

return;

}

这里我使用到了 fgetc() 和 fputc() 两个函数 代替 fread() 和 fwrite() 函数

如果注释看不清,可以在 函数原型 里找到这两个函数。

命令行参数:

4ea419ff4b5916bb1338880e355aa566.png

源文件:

920c4ac84d56b1a8b14d295a8dfbbaae.png

目标文件:

6c5cfb26cf37f6babd974691cdbc30f4.png

程序执行:

3a6ffbad5b2e2e61ea3e1ed6142025fa.png

目标文件:

072865d238e54e30c6d13545f753dc4f.png

Pe13-3:

/*

13-3----编写一个文件拷贝程序,提示用户输入文本文件名,

并以该文件作为原始文件名和输出文件名。

改成需要使用 ctype.h 中的 toupper () 函数,

再写入到输入文件时把所有文本转换成大写。

使用标准I/O 和文本模式。

*/

呃,原谅我真的搞不懂这个题目是什么意思...... 多线程?玩不来》。。。。

只好自己建立一个 infomation.txt 了

As the source file !!!

#include

#include //提供 exit() 的原型

#include //toupper() 函数

#define TEMPNAME "infomation.txt"

//拷贝文件函数(并转换成大写)

void cpyfile(FILE * source, FILE * target);

int main(void)

{

int ch;

char fname[256];

errno_t err;//fopen_s() 函数返回该类型(int)

FILE * fp1;//源文件

FILE * fp2;//目标文件

puts("输入目标文件名:");

gets_s(fname, 256);

/* 打开文件(失败) */

if (err = fopen_s(&fp1, TEMPNAME, "r") != 0)

{

printf("打开 %s 文件失败,程序退出中......\n", TEMPNAME);

exit(EXIT_FAILURE);

}

if (err = fopen_s(&fp2, fname, "a+") != 0)

{

printf("打开 %s 文件失败,程序退出中......\n", fname);

if (fclose(fp1) != 0)

printf("关闭 %s 文件失败,程序退出中......\n", TEMPNAME);

exit(EXIT_FAILURE);

}

cpyfile(fp1, fp2);//拷贝文件函数((并转换成大写))

puts("文件拷贝完毕!\n");

/* 关闭文件(失败) */

if (fclose(fp1) != 0)

{

printf("关闭 %s 文件失败,程序退出中......\n", TEMPNAME);

exit(EXIT_FAILURE);

}

if (fclose(fp2) != 0)

{

printf("关闭 %s 文件失败,程序退出中......\n", fname);

exit(EXIT_FAILURE);

}

while (ch = getchar())//防止突然退出

{

continue;

}

return 0;

}

//拷贝文件函数(并转换成大写)

void cpyfile(FILE * source, FILE * target)

{

int ch = 0;

while ((ch = fgetc(source)) != EOF)

{

ch = toupper(ch);

fputc(ch, target);

}

return;

}

运行效果:::::

a1725d59e137b430ab8a6160c7ab5158.png

02ba0cbd85046bc589950b29ad08545d.png

cb1f6caf3150826b02cccd77369c15c5.png

33b51140d06a689ed00c43b8dfe68055.png

Pe13-4:

/*

13-4----编写一个程序,按顺序在屏幕上显示命令行中列出的所有文件。

使用argc控制循环

*/

#include

int main(int argc, char *argv[])

{

int ch;

int ct;

errno_t err;//fopen_s()返回该类型(int)

FILE * fp;

char file[4096];

for (ct = 1; ct < argc; ct++)

{

//打开文件失败

if (err = fopen_s(&fp, argv[ct], "r") != 0)

{

printf("打开 %s 文件失败...\n", argv[ct]);

continue;//注意for () 使用continue ct 会递增

}

printf("%d) 文件 %s : \n\n", ct, argv[ct]);

while (fgets(file, 256, fp) != NULL)

{

fputs(file, stdout);

}

printf("\n\n");

fclose(fp);//别忘了关闭文件呦

}

printf("\n\n程序完结!\n");

while (ch = getchar())//防止突然退出

{

continue;

}

return 0;

}

运行:

a611bb7387fb74bf88adb87ba2681544.png

cf170431dbdee2b6f9eee0337de3ff18.png

Pe13-5:

/*

13-5----修改程序清单 13-5 中的程序,用命令界面代替交互式界面.

*/

这里我传递的命令格式:[目标文件] [源文件1] [源文件2] ......(以此类推)

5363d4ae185860bb7b3d8ff548774851.png

总共3个命令参数

文件:

eacca418885ca8f49d3c0be3efc62cc6.png

源码:

#include

#include

#include

#define BUFSIZE 4096

#define SLEN 81

void append(FILE * source, FILE * dest);

char * s_gets(char *st, int n);

int main(int argc, char ** argv)

{

FILE *fa, *fs;// fa 指向目标文件, fs 指向源文件

int files = 0;//附加的文件数量

/* argv[1] 表示源文件, argv[2] 表示目标文件 */

int ch;

errno_t err;

/* 打开目标文件 */

if ((err = fopen_s(&fa, argv[1], "a+")) != 0)

{

fprintf(stderr, "Can't open %s\n", argv[2]);

exit(EXIT_FAILURE);

}

//设置目标文件的缓冲区

if (setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0)

{

fputs("Can't create output buffer\n", stderr);

if (fclose(fa) != 0)

printf("Can't close %s\n", argv[2]);

exit(EXIT_FAILURE);

}

for (int ct = 2; ct < argc; ct++)

{

//比较字符串(如果相同,则不拷贝) 且 源字符串不是空文件

if (strcmp(argv[1], argv[ct]) && *argv[ct] == '\0')

{

fputs("Can't append file itself\n", stderr);

}

//打开源文件

else if ((err = fopen_s(&fs, argv[ct], "r")) != 0)

{

fprintf(stderr, "Can't open %s\n", argv[2]);

}

else

{

//设置源文件的缓冲区

if (setvbuf(fs, NULL, _IOFBF, BUFSIZE) != 0)

{

fputs("Can't create input buffer\n", stderr);

continue;

}

//拷贝文件

append(fs, fa);

if (ferror(fs) != 0)

fprintf(stderr, "Error in reading file %s.\n", argv[ct]);

if (ferror(fa) != 0)

fprintf(stderr, "Error in reading file %s.\n", argv[1]);

fclose(fs);

files++;

printf("File %s appended.\n", argv[ct]);

}

}

printf("Done appending. %d files appended.\n\n", files);

rewind(fa);//回到文件开始处

printf("%s contents:\n", argv[1]);

//打印目标文件的内容

while ((ch = fgetc(fa)) != EOF)//这里我用了 fgetc() 而不是getc()

{

putchar(ch);//fgetc() 是函数 getc() 是宏定义

} //资料自行百度

puts("\n\nDone displaying.");

fclose(fa);

return 0;

}

void append(FILE * source, FILE * dest)

{

size_t bytes;

static char temp[BUFSIZE]; //只分配一次

while ((bytes = fread_s(temp, sizeof(temp), sizeof(char),

BUFSIZE, source)) > 0)

{

fwrite(temp, sizeof(char), bytes, dest);

}

}

char * s_gets(char *st, int n)

{

char * ret_val;

char * find;

ret_val = fgets(st, n, stdin);

if (ret_val)

{

find = strchr(st, '\n');

if (find)

{

*find = 0;

}

else

{

while (getchar() != '\n')

continue;

}

}

return ret_val;

}

运行:

c589810e13e1e815add503eaf34a8282.png

Pe13-6:

/*

13-6-----重写程序清单 13.2 中的程序,不使用命令行参数,而是提示用户输入所需的信息。

*/

#include

#include //提供 exit() 的原型

#include //提供 strcpy(),strcat()的原型

#define LEN 40

int main(void)

{

FILE * in, * out;

errno_t err;

int ch;

int ct = 0;//count 的缩写

char Tname[LEN] = { '\0' };//目标文件名

char Sname[LEN] = { '\0' };//源文件名

printf("Enter the name of source file:");

do

{ //使用 do while 很舒服!

gets_s(Sname, LEN);//如果源文件名为空,则重新输入

} while (Sname[0] == '\0');

/* 打开源文件 */

if ((err = fopen_s(&in, Sname, "r")) != 0)

{

fprintf(stderr, "Can't open %s file", Sname);

exit(EXIT_FAILURE);

}

//设置输出

strncpy_s(Tname, LEN, Sname, LEN - 5);

Tname[LEN - 5] = '\0';

/* 在文件名后添加 .red */

strcat_s(Tname, sizeof(Tname), ".red");

//打开目标文件

if ((err = fopen_s(&out, Tname, "w")) != 0)

{

fprintf(stderr, "Can't create output file.\n");

exit(3);

}

//拷贝数据

while ((ch = fgetc(in)) != EOF)

{

if (ct++ % 3 == 0)

{

fputc(ch, out);

}

}

//收尾工作

if (fclose(in) != 0 || fclose(out) != 0)

{

fprintf(stderr, "Error in closing files\n");

}

return 0;

}

a8011395b6fbb6ce7085e608c0e5f589.png

Pe13-7:

/*

13-7------编写一个程序打开两个文件。

可以使用命令行参数或提示用户输入人文件名。

a.    该程序以这样的顺序打印:打印第 1 个文件的第 1 行,第 2 个文件的第 2 行,

第 1 个文件的第 2 行,第 2 个文件的第 2 行,以此类推,打印到行数较多文件的最后一行

b.    修改该程序,把行号相同的行打印成一行

*/

注意这里的 rewind() 函数,我写在函数原型里了

#include

#include

#include

#define BUFSIZE 256

#define LEN 81

int Pe13_7_a(FILE * fp1, FILE * fp2);

int Pe13_7_b(FILE * fp1, FILE * fp2);

char * Getfname(char * fname, int Maxlen);//获取文件名

int main(void)

{

errno_t err;

FILE * fp1, *fp2;//两个文件指针

char fname1[LEN] = {'\0'};//文件名1, 初始化为空

char fname2[LEN] = {'\0'};//文件名2, 初始化为空

printf("Enter the first file name: ");//获取文件名1

Getfname(fname1, LEN);

printf("Enter the second file name: ");//获取文件名2

Getfname(fname2, LEN);

/* 打开两个文件 */

if ((err = fopen_s(&fp1, fname1, "r")) != 0)

{

fprintf(stderr, "Can't open the file: %s \n", fname1);

exit(EXIT_FAILURE);

}

if ((err = fopen_s(&fp2, fname2, "r")) != 0)

{

fprintf(stderr, "Can't open the file: %s \n", fname2);

fclose(fp1);

exit(EXIT_FAILURE);

}

Pe13_7_a(fp1, fp2);//函数调用

Pe13_7_b(fp1, fp2);//函数调用

//收尾工作

if ((fclose(fp1) != 0) || (fclose(fp2) != 0))

{

fprintf(stderr, "Something wrongs in closing the files.\n");

}

return 0;

}

int Pe13_7_a(FILE * fp1, FILE * fp2)

{

char buf[BUFSIZE];//创建缓冲区

int ct = 1,

time = 1;//标记行号

int flag1 = 1,

flag2 = 1;//标记文件是否结束

int ret_val = 1; //返回值默认为1,返回0 表示成功调用函数

printf("Here are the 'a'(one line by one line): \n");

while (flag1 != 0 || flag2 != 0)

{

if (flag1 != 0)//分别打印文件1 文件2 的内容

{

printf("File 1: Line %d: ", ct++);

if ((fgets(buf, BUFSIZE, fp1) != NULL))

{

fputs(buf, stdout);

}

else

{

printf("\n\tThe first file has done.\n");

flag1 = 0;

}

}

if (flag2 != 0)

{

printf("File 2: Line %d: ", time++);

if ((fgets(buf, BUFSIZE, fp2) != NULL))

{

fputs(buf, stdout);

}

else

{

printf("\n\tThe second file has done.\n");

flag2 = 0;

}

}

}

rewind(fp1);//回到文件开头

rewind(fp2);//如果没有,则无法读取文件

printf("\nthe task a: Done!\n\n");

return 0;

}

int Pe13_7_b(FILE * fp1, FILE * fp2)

{

char buf[BUFSIZE];//创建缓冲区

int ct = 1;

int flag1 = 1,

flag2 = 1;//标记文件是否结束

int ret_val = 1;//返回值默认为1,返回0 表示成功调用函数

char * find;//使用strchr() 函数

printf("Here are the 'b'(make for the whole line): \n");

while (flag1 != 0 || flag2 != 0)

{

printf("The whole line %d: ", ct++);

if (flag1 != 0)

{

if ((fgets(buf, BUFSIZE, fp1) != NULL))

{

find = strchr(buf, '\n');//查找换行符

if (find != NULL)

{

*find = '\0';//删去换行符

}

fputs(buf, stdout);//打印一行

}

else

{

printf("(The first file has done.)");

flag1 = 0;

}

}

if (flag2 != 0)

{

if ((fgets(buf, BUFSIZE, fp2) != NULL))

{

find = strchr(buf, '\n');//查找换行符

if (find != NULL)

{

*find = '\0';//删去换行符

}

fputs(buf, stdout);//打印一行

}

else

{

printf("(The second file has done.)");

flag2 = 0;

}

}

putchar('\n');//每次打印结束后,插入换行符

}

printf("\nthe task b: Done!\n\n");

return 0;

}

char * Getfname(char * fname, int Maxlen)//获取文件名

{

do

{

gets_s(fname, Maxlen);

} while (fname[0] == '\0');//如果是空行输入, 则重新输入

return fname;

}

源文件:

27530deee8e0bc27aac19dc2ea3ab298.png

运行:

c259b1c16fe358914e420c5e8df177e9.png

Pe13-8:

/*

13-8------编写一个程序,以一个字符和任意文件名作为命令行参数。

如果字符后面没有参数,该程序读取标准输入;否则,程序依次打开每个文件

并报告每个文件中该字符出现的次数。文件名和字符本身也要一同报告。

程序应包含错误检查,已确定参数数量是否正确和是否能打开文件。如果无法打开文件,

程序应该报告这一情况,然后继续处理下一个文件。

*/

#include

#include

//在缓存区内查找ch,返回ch出现的次数

int ch_in_buf(const char * buf, int ch);

int main(int argc, char * argv[])

{

int ch;

FILE * fp;

errno_t err;

int ct = 0;//储存字符出现的次数

int time;

char buf[256] = {'\0'};

if (argc < 2)

{

fprintf(stderr, "Usage: [character] [filename]......\n");

exit(EXIT_FAILURE);

}

else if (argc == 2)//命令行参数为一个字符

{

ch = argv[1][0];//获取传入的字符

printf("Enter some text, press the # key at"

"the beginning of a line to terminate.\n");

while ((fgets(buf, 256, stdin)) != NULL && buf[0] != '#')

{

ct += ch_in_buf(buf, ch);

printf("Next line: \n");

}

printf("The character %c has appeared %d times"

"in your input.", ch, ct);

}

else

{

ch = argv[1][0];//获取传入的字符

//分别打开每个文件

for (time = 2; time < argc; time++)

{

if ((err = fopen_s(&fp, argv[time], "r")) != 0)

{

fprintf(stderr, "Can't open file %s.\n", argv[time]);

continue;

}

//查找字符

while ((fgets(buf, 256, fp)) != NULL)

{

ct += ch_in_buf(buf, ch);

}

printf("The character %c has appeared %d times"

"in file %s\n" , ch, ct, argv[time]);

fclose(fp);

}

}

printf("BYE!\n");

return 0;

}

//在缓存区内查找ch,返回ch出现的次数

int ch_in_buf(const char * buf, int ch)

{

int count = 0;

while (*buf)

{

if (*buf == ch)

{

count++;

}

buf++;

}

return count;

}

f957e244f0ec629099e8171a964a9fbf.png

791f0364e239c135066a65e572b5187c.png

Pe13-9:

/*

13-9------修改程序清单 13.3 中的程序,从 1 开始, 根据加入列表的顺序为每个单词编号。

当长序下次运行时 ,确保新的单词编号接着上次的编号开始。

*/

#include

#include

#define MAX 41

int main(void)

{

FILE * fp;

errno_t err;

char words[MAX] = { '\0' };

int ct = 1;

//1.打开文件

if ((err = fopen_s(&fp, "text.txt", "a+")) != 0)

{

fprintf_s(stderr, "Can't open \"text.txt\" file.\n");

exit(EXIT_FAILURE);

}

//2.提示输入

puts("Enter words to add to the file; press the #");

puts("key at the beginning of a line to terminate.\n");

//3.获取输入 并写入文件

while ((fscanf_s(stdin, "%40s", words, 40)) == 1 && (words[0] != '#'))

fprintf(fp, "%s\n", words);

//4.打印文件内的所有单词

puts("File contents:");

rewind(fp);//回到文件结尾

while (fscanf_s(fp, "%s", words, 40) == 1)

{

printf("%d) %s\n", ct, words);

ct++;

}

puts("Done!");

//5.关闭文件

if (fclose(fp) != 0)

{

fprintf(stderr, "Error closing file.\n");

}

return 0;

}

3ee254f1adcea6a590239aa6b599adc4.png

de0ff3341b063e194944a9e1be885a15.png

Pe13-10:

/*

13-10------编写一个程序打开一个文本文件,通过交互方式获取文件名。通过一个循环,

提示用户输入一个文件位置。然后该程序打印从该位置开始到下一个换行符之前的内容,

用户输入负值或非数值字符可以结束循环。

*/

行云流水般一气呵成!

#include

#include

#define BUFSIZE 256

int main(void)

{

FILE * fp;//文件指针

errno_t err;//fopen_s()返回该类型(int)

char buf[BUFSIZE] = { '\0' };

char fname[41] = { '\0' };

int num = 0;//用户指定的文件位置

long last;//fseek()函数和ftell()函数使用

/* 这里我使用了fseek()函数 和 ftell()函数,函数作用和原型书上有 */

//1.获取文件名

printf("Enter the name of the file to open:");

while (gets_s(fname, 40) == NULL)

continue;

//2.打开文件

if ((err = fopen_s(&fp, fname, "r")) != 0)

{

fprintf_s(stderr, "Can't open file %s.\n", fname);

exit(EXIT_FAILURE);

}

//3.获取文件长度(从文件开头到文件结尾的字符数)

fseek(fp, 0L, SEEK_END);

last = ftell(fp);

//4.获取用户输入的文件位置

printf("Enter the location of the file to query(q to quit): ");

while ((scanf_s("%d", &num) == 1) && num >= 0)

{

if (num > last)//超出文本字符数

{

fprintf_s(stderr, "%d exceeds the number of"

"text characters.\nEnter one again?\n:", num);

continue;

}

//5.定位文件并获取文件内容

fseek(fp, (long)num, SEEK_SET);

fgets(buf, BUFSIZE, fp);

puts("The text in that line:");

fputs(buf, stdout);

rewind(fp);//回到文件开头

printf("Enter the location of the file to query(q to quit): ");

}

//6.收尾工作

fclose(fp);

return 0;

}

1781fe0671d459b8cf12c175d3f03197.png

1a357d375d7239c518394a239897acd2.png

Pe13-11:

/*

13-11------编写一个程序,接收两个命令行参数。第 1 个参数是一个字符串,第2个参数是一个

文件名。然后该程序查找该文件,打印文件中包含该字符串的所有行。因为该任务是面向行而不是面向

字符的,所有要使用 fgets() 而不是 getc()。使用标准 C 库函数 strstr(),

在每一行中查找指定字符串。假定文件中的所有行都不超过255个字符。

*/

#include

#include

#include

#define BUFSIZE 256

//查找并打印包含字符串 st 文件行

char * ChrStrIn_Buf(const char * buf, const char * st);

int main(int argc, char * argv[])

{

FILE * fp;

errno_t err;

char buf[BUFSIZE] = { '\0' };

int flag = 0;

//检查参数

if (argc != 3)

{

fprintf_s(stderr, "Usage:[string] [file name].\n");

exit(EXIT_FAILURE);

}

//打开文件

if ((err = fopen_s(&fp, argv[2], "r")) != 0)

{

fprintf_s(stderr, "Can't open file %s.\n", argv[2]);

exit(EXIT_FAILURE);

}

//查找字符串

while (fgets(buf, BUFSIZE, fp) != NULL)

{

if (ChrStrIn_Buf(buf, argv[1]) != NULL)

flag = 1;

}

if (flag == 0)

{

printf("Didn't find %s in file %s.\n", argv[1], argv[2]);

}

//收尾工作

fclose(fp);

return 0;

}

//查找并打印包含字符串 st 文件行

char * ChrStrIn_Buf(const char * buf, const char * st)

{

char *find;

//查找字符串

if ((find = strstr(buf, st)) != NULL)

{

printf("Find %s in:\n", st);

fputs(buf, stdout);

printf("\nThat is:\n");

fputs(find, stdout);

}

return find;

}

7750efe8fdf7e00648fb8002f9f17b2d.png

c048ff728fbf3e2117bdd75bc877d0c1.png

别问我为什么那么喜欢用 10086 ......噗哈哈

Pe13-12:

/*

13-12-----创建一个文本文件,内含20 行, 每行30 个整数。这些证书都在0~9 之间,

用空格分开。该文件是用数字表示一张图片,0~9表示逐渐增加的灰度。

呸,这么长的题目.......好吧,各位大佬自己看书上哈。

*/

程序中需要使用到的文本文件:

链接:https://pan.baidu.com/s/1Kmj2FJoaxQYcHp5EYqWXtQ 密码:tula

#include

#include

#define ROWS 20

#define INTLENTH 30

#define FNAME "text.txt"//这里为了方便,我直接设置了:

#define OUTFILE "out.txt"//文本文件名和输出文件名

//从文件中获取数字int数组

void GetStringFromFile(FILE * fp, int arr[][INTLENTH], int rows);

int main(void)

{

FILE * fp1, *fp2; //fp1 表示源文件,fp2表示输出文件

errno_t err;

int arr[ROWS][INTLENTH] = { 0 };

int time, ct;

//打开源文件

if ((err = fopen_s(&fp1, FNAME, "r")) != 0)

{

fprintf_s(stderr, "Can't open file %s.\n", FNAME);

exit(EXIT_FAILURE);

}

//打开输入文件

if ((err = fopen_s(&fp2, OUTFILE, "w+")) != 0)

{

fprintf_s(stderr, "Can't open file %s.\n", OUTFILE);

fclose(fp1);

exit(EXIT_FAILURE);

}

//从文件中获取数字int数组

GetStringFromFile(fp1, arr, ROWS);

printf("Here is the file:\n\n\n");

//打印结果并写入文件

for (time = 0; time < ROWS; time++)

{

for (ct = 0; ct < INTLENTH; ct++)

{

switch (arr[time][ct])

{

case 0:

putchar(' ');

fputc(' ', fp2);

break;

case 1:

putchar('.');

fputc('.', fp2);

break;

case 2:

putchar('\'');//输出 ' 要使用 \'

fputc('\'', fp2);

break;

case 3:

putchar(':');

fputc(':', fp2);

break;

case 4:

putchar('~');

fputc('~', fp2);

break;

case 5:

putchar('*');

fputc('*', fp2);

break;

case 6:

putchar('=');

fputc('=', fp2);

break;

case 7:

putchar('$');//这个 $ 是我自己选的

fputc('$', fp2);

break;

case 8:

putchar('%');

fputc('%', fp2);

break;

case 9:

putchar('#');

fputc('#', fp2);

break;

default:

break;

}

}

fputc('\n', fp2);

fputc('\0', fp2);

printf("\n");

}

return 0;

}

//从文件中获取数字int数组

void GetStringFromFile(FILE * fp, int arr[][INTLENTH], int rows)

{

int ct, time;

for (time = 0; time < rows; time++)

{

for(ct = 0; ct < INTLENTH; ct++)

{

//获取文件中的每一个(数字字符)

//使用scanf_s()函数会自动将char类型字符转换成int类型

fscanf_s(fp, "%d", &arr[time][ct]);

}

}

}

运行:

fdd6a0c5543e5575e1d9a149c39a4877.png

aca7ff9b6ae3b9b958977b037216e108.png

34b88ed6f485f0bdfb3c5da5c950fd6b.png

P13-13:假的!VS不支持变长数组

P13-14:

许久未见了,继续发:

/*

13-14-----数字图像,尤其是从宇宙飞船发回的数字图像,可能会包含一些失真。为编程练习12添加消除失真的函数。

该函数把每个值与它上下左右相邻的值作比较,如果该值与其周围相邻值的差都大于1,

则用所有相邻值的平均值(四舍五入为整数)代替该值。

注意,与边界上的点相邻的点小于 4 个,所以做特殊处理。

*/

因为如果要再重新把所有代码都发出来会很麻烦,而且看着很不舒服,

所以这里直接写了一个函数来完成这个步骤:

只需要在 GetSringFromFile()函数后面调用即可,像下面那样

//从文件中获取数字int数组

GetStringFromFile(fp1, arr, ROWS);

//处理数字图像的失真

DealDistortion(arr, ROWS);

void DealDistortion(int image[][INTLENTH], int rows)

{

int time, ct;//循环计数变量

//遍历所有元素

for (time = 0; time < rows; time++)

{

for (ct = 0; ct < INTLENTH; ct++)

{

int count = 0;//记录已经遍历过几个方向

int number = 0;//储存每次获取到的各个方向的值

int sum = 0;//储存相邻值的点数和

//储存inamg[time][ct]的值

int localnum = image[time][ct];

//标记相邻值的差值,如果大于1,该值为1,反之,该值为0

//如果某方向没有数据,也标记为1

int flag[4] = { 0,0,0,0 };

//值的上方有数据

if (time != 0)

{

number = image[time - 1][ct]; //获取上方的值

//比较上方的值和原值

if (number - localnum > 1 || number - localnum < -1)

{

sum += number;

flag[0] = 1;//差值大于1

count++;//记录1个方向

}

}

else

flag[0] = 1;//如果上方没有数据

//值的左方有数据

if (ct != 0)

{

number = image[time][ct - 1]; //获取左方的值

if (number - localnum > 1 || number - localnum < -1)

{

sum += number;

flag[1] = 1;//差值大于1

count++;//记录1个方向

}

}

else

flag[1] = 1;//如果左方没有数据

//值的右方有数据

if (time != 19)

{

number = image[time][ct + 1]; //获取右方的值

if (number - localnum > 1 || number - localnum < -1)

{

sum += number;

flag[2] = 1;//差值大于1

count++;//记录1个方向

}

}

else

flag[2] = 1;//如果右方没有数据

//值的下方有数据

if (ct != 29)

{

number = image[time + 1][ct]; //获取下方的值

if (number - localnum > 1 || number - localnum < -1)

{

sum += number;

flag[3] = 1;//差值大于1

count++;//记录1个方向

}

}

else

flag[3] = 1; //如果下方没有数据

//四周的差值都大于1,刷新原值。只要有1个差值小于1,则不刷新

if (flag[0] != 1 || flag[1] != 1 || flag[2] != 1 || flag[3] != 1)

{

flag[0] = 2;//标记不刷新

}

//刷新原值,注意,最后的除数不能为0

if (flag[0] != 2 && count != 0)

{

image[time][ct] = (int)(sum / count);

}

}

}

}

来看看效果哈!

f5a22d8c70810d5f8da9333c0b7181f9.png

不过要我说,命令行下的好看多了,更简洁大方!

(吐槽记事本......)

OK!到这里,整个第13章就over了。

关于第14章的,这里先说:

第十四章的内容估计不会很快出来,跟大家道句遗憾。

因为博主我自己也观察了一番,

1.这样一个练习一个练习的发,不说它效果慢吧,而且对于有需要的人而言,等得很急!

2.博主本人也是个学生,暑假结束了,时间也真的不多,一周最多就是1个编程练习,甚至没有这么多。

3.粉丝和浏览数也涨得慢(嘿嘿,主要原因)

所以我打算,等我学完第十四章后,用可能1,2个月的时间完成所有的练习,再一口气发出来。

很舒服!      但,读者们可能需要等到10或11月才会有下一个博客出来,时间会很长,很久......

好啦,好在博主是打算坚持写博客的,决不放弃!

OK,咱们,第14章再见吧!

Alex Mercer (boy) 鸣谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值