《C Primer Plus》第6版 编程练习 第十三章
目录(如果无法使用,可以选用右侧的目录选项)教程连接
先看这里(很重要!):
本书中所有使用的 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,失败则返回相应的错误代码。
开个玩笑哈!这是我测试的时候会这样(已经解决),下面是实际情况(我在 exit() 前加了 system("pause");)
一般情况下是一闪而过,直接退出的
还有就是传入的第一个参数 取文件指针的地址,
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 <stdio.h>
#include <stdlib.h> //提供 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;
}
这里的49 个字符是包括换行符的(不包括文件结尾)
Pe13-2:
这里我(终于)使用了命令行参数
VS使用命令行参数的方法: 任意门
/*
13-2----编写一个文件拷贝程序,该程序通过命令行获取原始文件名。
尽量使用标准I/O 和二进制模式。
*/
#include <stdio.h>
#include <stdlib.h> //提供 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() 函数
如果注释看不清,可以在 函数原型 里找到这两个函数。
命令行参数:
源文件:
目标文件:
程序执行: