Unix/Linux编程实践教程----cp1.c详解

时间:2021-12-04 04:41:30
 

程序代码:

/** 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 大小的缓冲区;然后在判断输入文件未完的循环中,每次读入多少就向输出文件中写入多少,直到输入文件结束。

帮助理解的例子:

例一:

程序:

Unix/Linux编程实践教程----cp1.c详解

 

执行结果:

Unix/Linux编程实践教程----cp1.c详解

 

例二: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 轮换成对应的错误信息打印出来。