程序代码:
/** cp1.c
* version 1 of cp - uses read and write with tunable buffer size
* usage: cp1 src dest
*/
#include <stdio.h>//输入输出库函数
#include <unistd.h>//包含了服务的函数原型,eg:read(),write()等
#include <fcntl.h>//定义了很多宏和fcntl函数原型
#define BUFFERSIZE 4096//BUFFERSIZE 用来表示缓冲区的大小
#define COPYMODE 0644//COPYMODE 用来定义创建文件的权限。
void oops(char *, char *);//用来输出出错信息到 stderr,也就是标准错误输出的文件流。
main(int ac, char *av[])//ac表示输入命令的字符串个数,argv表示输入的字符串数组,见例一
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
/* check args */
if ( ac != 3 )
{
fprintf(stderr,"usage:%s source destination\n", *av);//stderr:标准错误
exit(1);//非正常运行导致退出程序。相关知识点请看例二
}
/* open files */
if ((in_fd=open(av[1],O_RDONLY))==-1)//in_fd=open(av[1], O_RDONLY)遇到错误-1 oops("Cannot open ", av[1]);
if ( (out_fd=creat( av[2], COPYMODE)) == -1 )
oops( "Cannot creat", av[2]);
/* copy files */
/* 此while循环是拷贝的主要过程。它从输入文件描述符 in_fd 中,读入 BUFFERSIZE 字节的数据,存放到 buf 字符数组中。在正常读入的情况下,read 函数返回实际读入的字节数,也就是说只要没有异常情况和文件没有读到结尾,那么 n_chars 中存放的就是实际读出的字节的数字。然后 write 函数将从 buf 缓冲区中,读出 n_chars 个字符,写入 in_out 输出文件描述符。由于 write 系统调用返回的是实际写入成功的字节数。所以当读出 N 个字符,成功写入 N 个字符到输出文件描述符中去的时候,就表示写成功了,否则就报告写入错误。*/
while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )//定义了 2 个文件描述符、一个存放读出字节数的变量 n_chars、和一个 BUFFERSIZE 大小的字符数组用来作为拷贝文件的缓冲区。
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", av[2]);
if ( n_chars == -1 )
oops("Read error from ", av[1]);
/* close files */
if ( close(in_fd) == -1 || close(out_fd) == -1 )
oops("Error closing files","");
}
void oops(char *s1, char *s2)
{
fprintf(stderr,"Error: %s ", s1);
perror(s2);//例三
exit(1);
}
该程序的主要实现思想是:打开一个输入文件,创建一个输出文件,建立一个 BUFFERSIZE 大小的缓冲区;然后在判断输入文件未完的循环中,每次读入多少就向输出文件中写入多少,直到输入文件结束。
帮助理解的例子:
例一:
程序:
执行结果:
例二:exit(0)与exit(1)、return区别
exit(0):正常运行程序并退出程序;
exit(1):非正常运行导致退出程序;
return():返回函数,若在主函数中,则会退出函数并返回一值。
详细说:
1. return返回函数值,是关键字; exit 是一个函数。
2. return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。
3. return是函数的退出(返回);exit是进程的退出。
4. return是C语言提供的,exit是操作系统提供的(或者函数库中给出的)。
5. return用于结束一个函数的执行,将函数的执行信息传出个其他调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS,这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是 0 为正常退出, 非0 为非正常退出。
6. 非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。
例三:errno perror strerror的区别
#include <stdio.h> // void perror(const char *msg);
#include <string.h> // char *strerror(int errnum);
#include <errno.h> //errno
errno 是错误代码,在 errno.h头文件中;
perror是错误输出函数,输出格式为:msg:errno对应的错误信息(加上一个换行符);
strerror 是通过参数 errnum (就是errno),返回对应的错误信息。
以下是测试程序:
--------------------------------------------------------------------
// p_str_error.c
// perror , strerror 函数 , errno 测试
#include <stdio.h>
#include <stdlib.h>//stdlib.h里面定义了五种类型、一些宏和通用工具函数。类型例如size_t,宏例如atol()、rand()、 srand()、exit()等等。
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
FILE *fp;
char *buf;
if( (fp = fopen(argv[1], "r")) == NULL)
{
perror("perror"); // 好方便
errno = 12;
printf("strerror: %s\n", strerror(errno)); //转换错误码为对应的错误信息
exit(1);
}
errno = 13;printf("strerror: %s\n", strerror(errno));
perror("perror");
//void perror(const char *s);
//它先打印s指向的字符串,然后输出当前errno值所对应的错误提示信息,例如当前errno若为12,调用perror("ABC"),会输出"ABC: //Cannot allocate memory"。
fclose(fp);
return 0;
}
--------------------------------------------------------------------
输入一个存在的文件名,如:./a.out 111
open失败则会输出:
perror: No such file or directory
strerror: Cannot allocate memory
open成功则会输出:
perror: Success
strerror: Permission denied
很明显,perror信息是由 perror函数输出的了,第二行是 strerror通过将 errno 轮换成对应的错误信息打印出来。