Linux C程序设计

Linux C 程序设计

第一章 C语言核心知识回顾

C语言的定义

  1. 什么是C语言

    • C程序是由C语言数据类型与算法构成的程序。
  2. C程序的组成
    C程序由一个或多个翻译单元(translation unit)组成。预处理后,程序被规约为一个记号序列。

  3. C程序的记号序列

    • 由记号(token)和空白符(white space)组成。

运算符和表达式

在这里插入图片描述

  1. 存储类限定符

    • 存储类(storage class)分为两类:自动存储类(automatic)、静态存储类(static)。
      存储类是对程序块(翻译单元)来说的。

    • 声明使用限定符(specifier)指明存储类,若无限定符,变量默认为自动存储类。

    • 自动存储类即为局部变量。所谓“自动”,是指“自动消失”。何时消失?退出程序块时。

    • 声明为register的对象也是自动存储类,并被存储在快速寄存器中。例如:

      register int c;
      
    • 静态对象可以是程序块的局部对象,也可以是所有程序块的外部对象。

  2. 限定符

    • 限定符既不影响对象的取值范围,也不影响其算术属性。(K&R p196)

    • const

      • 任何变量的声明都可以使用const限定符限定。该限定符制定变量的值不能被改变。

      • 对数组而言,const限定符制定数组所有元素的值都不能被修改。

      • (更广义的可以概括为)声明为const的对象表明此对象的值不可修改。

      • const用于声明可以保存在制度存储器中的对象,并可能提高优化的可能性。

        const double e = 2.71828182845905;
        const char msg[] = “warning:;
        
      • const限定符也可以配合数组参数使用,它表明函数不能修改数组元素的值。

        int strlen(const char[]);
        
  3. volatile

  • 声明为volatile的对象表明它具有与优化相关的特殊属性。
    volatile没有与实现无关的语义。
  • volatile用于强制某个实现屏蔽可能的优化。例如,对于具有内存映像输入/输出的机器,指向设备寄存器的指针可以声明为指向volatile的指针。目的是防止编译器通过指针删除明显多于的引用。编译器可能会忽略这些限定符。

C语言的数据类型

在这里插入图片描述1. 数组

  • 声明为数组的变量代表了内存中的一段连续区域,其中保存了数组元素。

    int x[5]; 	//5个4字节整型
    
  • 所有数组都以下标0开始。

  • 数组名与指向该数组第一个元素的指针等价。

    int x[5], *ptr;
    ptr = &x[0];	// 相当于 ptr = x;
    
  • 指针算术和数组

    int x[5];	//x[2]等价于*(x + 2),编译器会认为这是元素x向前2个对象
    
  1. 指针

    • 对任何类型T,可以有指向该类型的指针。

      • 指针可以引用一个函数或对象。
      • 指针的值是对应对象或函数的地址。
      • 例如: int *i; char *x; int (*myfunc)();
    • 指针运算符: * 间接引用指针, & 创建一个指针(引用)

      int i = 3; 
      int *j = &i;
      *j = 4;
      printf(“i = %d\n”, i); // prints i = 4
      
      int myfunc (int arg);
      int (*fptr)(int) = myfunc; 
      i = fptr(4); // 相当于调用myfunc(4);
      
    • 通用指针:

      • 传统C使用(char *)
      • 标准C使用(void *)
      • 通用指针无法被间接引用,也不能用来做指针算术运算,从而可以减少error。
    • Null指针: 使用 NULL 或 0. 指针一般初始化为NULL.

  2. 结构

    struct MyPoint {int x, int y};
    typedef struct MyPoint MyPoint_t;
    MyPoint_t point, *ptr;
    point.x = 0;
    point.y = 10;
    ptr = &point;
    ptr->x = 12;
    ptr->y = 40;
    
  3. 联合

    union MyUnion {
        int x;
        MyPoint_t pt;
        struct {int 3; char c[4]}
        S;
    };
    union MyUnion x;
    

算术运算符

在这里插入图片描述

C程序的结构

在这里插入图片描述

  1. 命令行参数
    • 参数向量是指向字符串指针的数组。
    • 字符串是由一个二进制0 ( NULL or ‘\0’ ) 结尾的字符数组。
    • argv[0] 总是程序名,因此 argc 至少为1。
  2. 源代码和头文件
    • 将相关代码写在同一个模块(文件)中。
    • 头文件 (*.h)导出接口定义
      • 函数原型、数据结构、宏、内联函数和其他常用声明
    • 不要将源码(即各种定义)写在头文件中,但有少数几个例外:
      • 内联函数代码
      • 类定义
      • const定义
    • C预处理器(preprocessor )(cpp)会把常用定义插入到源文件中

第二章 Linux C语言开发工具

GNU C 编译器

  1. 基本用法

     gcc [options] [filenames]
    

    【说明】

    • 在gcc后面可以有多个编译选项,同时进行多个编译操作。
    • 当你不用任何选项编译一个程序时,GCC将会建立(假定编译成功)一个名为a.out的可执行文件。
  2. 基本编译选项

    • -o选项

      • 你能用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out。

        gcc –o count count.c
        
    • -c选项:

      • 告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤。这个选项使用的非常频繁,因为它使得编译多个C程序时速度更快并且更易于管理。缺省时GCC建立的目标代码文件有一个.o的扩展名。

        gcc  –c  test2.c
        

    【说明】gcc一般使用默认路径查找头文件和库文件。如果文件所用的头文件或库文件不在缺省目录下,则编译时要指定它们的查找路径。

    • -I选项:指定头文件的搜索目录

      gcc –I/export/home/st –o test1 test1.c
      
    • -L选项:指定库文件的搜索目录

      gcc –L/usr/X11/R6/lib –o test1 test1.c
      
    • 优化选项:优化选项可以使GCC在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件。这些选项中最典型的是-O和-O2选项。

      • -O选项:告诉GCC对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。
      • -O2选项:告诉GCC 产生尽可能小和尽可能快的代码。-O2选项将使编译的速度比使用-O时慢。但通常产生的代码执行速度会更快。

GDB调试程序

  1. 作用:寻找程序执行时错误。

  2. 调试:可执行文件

  3. 除错程序执行的流程:

    • 进入除错程序并指定可执行文件;
    • 设定断点后执行程序;
    • 检视程序执行状态,检查变量值或变更变量值;
    • 逐步执行程序或全速执行程序到下一个断点或程序结束为止。
    • 离开除错程序。
  4. gdb所提供的一些功能:

    • 监视程序中变量的值。
    • 设置断点以使程序在指定的代码行上停止执行。
    • 逐行执行代码。
    • 分析崩溃程序的产生的core文件
  5. gdb基本用法

    [root@lhb ~]# gdb [filename]
    
  6. 基本gdb命令

    命令作用
    file装入想要调试的可执行文件。
    kill终止正在调试的程序。
    list列示源代码。
    next执行一行源代码但不进入函数内部。
    step执行一行源代码而且进入函数内部。
    run执行当前被调试的程序。
    quit终止 gdb
    watch使你能监视一个变量的值而不管它何时被改变。
    break在代码里设置断点, 这将使程序执行到这里时被挂起。
    make使你能不退出 gdb 就可以重新产生可执行文件。
    shell使你能不离开 gdb 就执行 UNIX shell 命令。

第三章 文件操作

文件与流

  1. fileno(返回文件流所使用的文件描述词)

    相关函数open,fopen
    表头文件#include <stdio.h>
    定义函数int fileno(FILE * stream);
    函数说明fileno()用来取得参数stream指定的文件流所使用的文件描述词。
    返回值返回文件描述词。
    #include<stdio.h>
    int main()
    { 
      FILE *fp;
      int fd;
      fp = fopen("/etc/passwd","r");
      fd = fileno(fp);
      printf("d = %d \n",fd);
      fclose(fp);
      return 0;
    }
    
  2. fdopen(将文件描述词转为文件指针)

    相关函数fopen,open,fclose
    表头文件#include<stdio.h>
    定义函数FILE * fdopen(int fildes,const char * mode);
    函数说明fdopen()会将参数fildes的文件描述词,转换为对应的文件指针后返回。参数mode字符串则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。关于mode字符串格式请参考fopen()。
    返回值转换成功时返回指向该流的文件指针。失败则返回NULL,并把错误代码存在errno中。
    #include<stdio.h>
    int main()
    {
      FILE * fp =fdopen(0,"w+);
      fprintf(fp,"%s\n","hello!");
      fclose(fp);
      return 0;
    }
    

顺序存取文件、随机存取文件

  1. fopen(打开文件)

    相关函数open,fclose
    表头文件#include<stdio.h>
    定义函数FILE *fopen(const char * path,const char * mode);
    返回值文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno中。
    附加说明一般而言,开文件后会作一些文件读取或写入的动作,若开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。

    【函数说明】参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。mode有下列几种形态字符串:

    相关选项作用
    r打开只读文件,该文件必须存在。
    r+打开可读写的文件,该文件必须存在。
    w打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
    a以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
    a+以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。
    #include<stdio.h>
    int main()
    {
        FILE * fp;
        fp=fopen("noexist","a+");
        if(fp == null) 
            return 0;
        fclose(fp);
    }
    
  2. fclose(关闭文件)

    相关函数close,fflush,fopen,setbuf
    表头文件#include<stdio.h>
    定义函数int fclose(FILE * stream);
    函数说明fclose()用来关闭先前fopen()打开的文件。此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。
    返回值若关文件动作成功则返回0,有错误发生时则返回EOF并把错误代码存到errno。
    错误代码EBADF表示参数stream非已打开的文件。
  3. fread(从文件流读取数据)

    相关函数fopen,fwrite,fseek,fscanf
    表头文件#include<stdio.h>
    定义函数size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream);
    函数说明fread()用来从文件流中读取数据。参数stream为已打开的文件指针,参数ptr指向欲存放读取进来的数据空间,读取的字符数以参数size*nmemb来决定。fread()会返回实际读取到的nmemb数目,如果此值比参数nmemb来得小,则代表可能读到了文件尾或有错误发生,这时必须用feof()或ferror()来决定发生什么情况。
    返回值返回实际读取到的nmemb数目。
    #include<stdio.h>
    #define nmemb 3
    struct test
    {
        char name[20];
        int size;
    }s[nmemb];
    void main()
    {
        FILE * stream;
        int i;
        stream = fopen("/tmp/fwrite","r");
        fread(s,sizeof(struct test),nmemb,stream);
        fclose(stream);
        for(i=0;i<nmemb;i++)
            printf("name[%d]=%-20s:size[%d]=%d\n",i,s[i].name,i,s[i].size);
    }
    
  4. fwrite (将数据写至文件流)

    相关函数fopen,fread,fseek,fscanf
    表头文件#include<stdio.h>
    定义函数size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream);
    函数说明fwrite()用来将数据写入文件流中。参数stream为已打开的文件指针,参数ptr指向欲写入的数据地址,总共写入的字符数以参数size*nmemb来决定。fwrite()会返回实际写入的nmemb数目。
    返回值返回实际写入的nmemb数目。
    #include<stdio.h>
    #define set_s (x,y) {
    strcoy(s[x].name,y);
    s[x].size=strlen(y);
    }
    #define nmemb 3
    struct test
    {
        char name[20];
        int size;
    }s[nmemb];
    void main()
    {
        FILE * stream;
        set_s(0,"Linux!");
        set_s(1,"FreeBSD!");
        set_s(2,"Windows2000.");
        stream=fopen("/tmp/fwrite","w");
        fwrite(s,sizeof(struct test),nmemb,stream);
        fclose(stream);
    }
    

文件及目录维护

  1. chmod(改变文件的权限)

    函数名称chmod
    函数原型int chmod( const char *filename, int pmode);
    所属库#include <sys/types.h> #include <sys/stat.h>
    函数功能改变文件的读写许可设置,如果改变成功返回0,否则返回-1
    #include <sys/types.h>
    #include <sys/stat.h>
    int main()
    {
    	chmod("/etc/passwd", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    	return 0;
    }
    
  2. chown(改变文件的拥有者)

    相关函数fchown, lchown, chmod
    头文件#include <sys/types.h>
    #include <unistd.h>
    定义函数int chown(const char *path, uid_t owner, gid_t group);
    函数说明chown()会将参数path 指定文件的所有者变更为参数owner 代表的用户,而将该文件的组变更为参数group组。如果参数owner 或group 为-1,对应的所有者或组不会有所改变。root 与文件所有者皆可改变文件组,但所有者必须是参数group 组的成员。当root 用chown()改变文件所有者或组时,该文件若具有S_ISUID或S_ISGID 权限,则会清除此权限位,此外如果具有S_ISGID 权限但不具S_IXGRP 位,则该文件会被强制锁定,文件模式会保留。
    返回值成功则返回0, 失败返回-1, 错误原因存于errno.
    /* 将/etc/passwd 的所有者和组都设为root */
    #include <sys/types.h>
    #include <unistd.h>
    int main(){
        chown("/etc/passwd", 0, 0);
    } 
    
  3. unlink(删除文件)

    相关函数link,rename,remove
    表头文件#include<unistd.h>
    定义函数int unlink(const char * pathname);
    函数说明unlink()会删除参数pathname指定的文件。如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。如果参数pathname为一符号连接,则此连接会被删除。
    返回值成功则返回0,失败返回-1,错误原因存于errno
    错误代码EROFS 文件存在于只读文件系统内。 EFAULT 参数pathname指针超出可存取内存空间 ENAMETOOLONG 参数pathname太长 ENOMEM 核心内存不足 ELOOP 参数pathname有过多符号连接问题 EIO I/O存取错误
    #include<unistd.h>
    #include<stdio.h>
    int main(void)
    {
        FILE *fp = fopen("junk.jnk","w");
        int status;
        fprintf(fp,"junk");
        status = access("junk.jnk",0);
        if (status == 0)
            printf("File exists\n");
        else
            printf("File doesn't exist\n");
        fclose(fp);
        unlink("junk.jnk");
        status = access("junk.jnk",0);
        if (status == 0)
            printf("File exists\n");
        else
            printf("File doesn't exist\n");
        return 0;
    }
    
  4. link(建立文件连接)

    相关函数symlink,unlink
    表头文件#include<unistd.h>
    定义函数int link (const char * oldpath,const char * newpath);
    函数说明link()以参数newpath指定的名称来建立一个新的连接(硬连接)到参数oldpath所指定的已存在文件。如果参数newpath指定的名称为一已存在的文件则不会建立连接。
    返回值成功则返回0,失败返回-1,错误原因存于errno。
    附加说明link()所建立的硬连接无法跨越不同文件系统,如果需要请改用symlink()。
    错误代码EXDEV 参数oldpath与newpath不是建立在同一文件系统。 EPERM 参数oldpath与newpath所指的文件系统不支持硬连接 EROFS 文件存在于只读文件系统内 EFAULT 参数oldpath或newpath指针超出可存取内存空间。 ENAMETOLLONG 参数oldpath或newpath太长 ENOMEM 核心内存不足 EEXIST 参数newpath所指的文件名已存在。 EMLINK 参数oldpath所指的文件已达最大连接数目。 ELOOP 参数pathname有过多符号连接问题 ENOSPC 文件系统的剩余空间不足。 EIO I/O存取错误。
    /* 建立/etc/passwd的硬连接为pass */
    #include<unistd.h>
    int main()
    {
        link("/etc/passwd","pass");
    }
    
  5. symlink(建立文件符号连接)

    相关函数link,unlink
    表头文件#include<unistd.h>
    定义函数int symlink( const char * oldpath,const char * newpath);
    函数说明symlink()以参数newpath指定的名称来建立一个新的连接(符号连接)到参数oldpath所指定的已存在文件。参数oldpath指定的文件不一定要存在,如果参数newpath指定的名称为一已存在的文件则不会建立连接。
    返回值成功则返回0,失败返回-1,错误原因存于errno
    错误代码EPERM 参数oldpath与newpath所指的文件系统不支持符号连接 EROFS 欲测试写入权限的文件存在于只读文件系统内 EFAULT 参数oldpath或newpath指针超出可存取内存空间。 ENAMETOOLONG 参数oldpath或newpath太长 ENOMEM 核心内存不足 EEXIST 参数newpath所指的文件名已存在。 EMLINK 参数oldpath所指的文件已达到最大连接数目 ELOOP 参数pathname有过多符号连接问题 ENOSPC 文件系统的剩余空间不足 EIO I/O存取错误
    #include<unistd.h>
    int main()
    {
    	 symlink("/etc/passwd","pass");
    }
    
  6. mkdir(建立目录)

    表头文件#include <sys/stat.h> #include <sys/types.h>
    定义函数int mkdir(const char *pathname, mode_t mode);
    函数说明mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
    返回值若目录创建成功,则返回0;否则返回-1,并将错误记录到全局变量errno中.
    附加说明mode方式:可多个权限相或,如0755表示S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH. 该文件所有者拥有读,写和执行操作的权限,该文件用户组拥有可读、可执行的权限,其他用户拥有可读、可执行的权限。
  7. rmdir(删除目录)

    • 函数名称:_rmdir(TC下为rmdir)
    • 函数原型:int _rmdir( const char *dirname );
    • 函数功能: 删除一个目录,若成功则返回0,否则返回-1
    //这个例子中先创建了一个目录D:\\myd,然后再把它给删除
    #include <dirent.h>
    #include <stdio.h>
    #include <stdlib.h>//for system()函数
    int main(void)
    {
        _mkdir("D:\\myd");
        system("dir D:\\myd");
        system("start D:");
        getchar();
        _rmdir("D:\\myd");
        return 0;
    }
    
  8. chdir(改变当前的工作目录)

    相关函数getcwd,chroot
    表头文件#include<unistd.h>
    定义函数int chdir(const char * path);
    函数说明chdir()用来将当前的工作目录改变成以参数path所指的目录。
    返回值执行成功则返回0,失败返回-1,errno为错误代码。
    #include<unistd.h>
    int main()
    {
     chdir("/tmp");
     printf("current working directory: %s\n",getcwd(null,null));
    }
    
  9. getcwd(保存当前目录的绝对地址)

    • #include <unistd.h>
    • char *getcwd(char *buf, size_t size);
    • 作用:把当前目录的绝对地址保存到 buf 中,buf 的大小为 size。如果 size太小无法保存该地址,返回 NULL 并设置 errno 为 ERANGE。可以采取令 buf 为 NULL并使 size 为负值来使 getcwd 调用 malloc 动态给 buf 分配,但是这种情况要特别注意使用后释放缓冲以防止内存泄漏。
    • 程序例如果在程序运行的过程中,目录被删除(EINVAL错误)或者有关权限发生了变化(EACCESS错误),getcwd也可能会返回NULL。
    #include<unistd.h>
    main()
    {
      char buf[80];
      getcwd(buf,sizeof(buf));
      printf("current working directory : %s\n",buf);
    }
    

搜索目录

  1. opendir(打开目录)

    相关函数open,readdir,closedir,rewinddir,seekdir,telldir,scandir
    表头文件#include<sys/types.h> #include<dirent.h>
    定义函数DIR * opendir(const char * name);
    函数说明opendir()用来打开参数name指定的目录,并返回DIR* 形态的目录流,和open()类似,接下来对目录的读取和搜索都要使用此返回值
    返回值成功则返回DIR* 型态的目录流,打开失败则返回NULL
    错误代码EACCESS 权限不足 EMFILE 已达到进程可同时打开的文件数上限。 ENFILE 已达到系统可同时打开的文件数上限。 ENOTDIR 参数name非真正的目录 ENOENT 参数name指定的目录不存在,或是参数name为一空字符串。 ENOMEM 核心内存不足。
  2. closedir(关闭目录)

    相关函数opendir
    表头文件#include<sys/types.h> #include<dirent.h>
    定义函数int closedir(DIR *dir);
    函数说明closedir()关闭参数dir所指的目录流。
    返回值关闭成功则返回0,失败返回-1,错误原因存于errno中。
    错误代码EBADF 参数dir为无效的目录流
  3. readdir(读取目录)

    相关函数open,opendir,closedir,rewinddir,seekdir,telldir,scandir
    表头文件#include<sys/types.h> #include<dirent.h>
    定义函数struct dirent * readdir(DIR * dir);
    函数说明readdir()返回参数dir目录流的下个目录进入点。结构dirent定义如下: struct dirent { ino_t d_ino; ff_t d_off; signed short int d_reclen; unsigned char d_type; har d_name[256; }; d_ino 此目录进入点的inode d_off 目录文件开头至此目录进入点的位移 d_reclen _name的长度,不包含NULL字符 d_type d_name所指的文件类型 d_name 文件名
    返回值成功则返回下个目录进入点。有错误发生或读取到目录文件尾则返回NULL。
    附加说明EBADF参数dir为无效的目录流。
    #include<sys/types.h>
    #include<dirent.h>
    #include<unistd.h>
    main(){
        DIR * dir;
        struct dirent * ptr;
        int i;
        dir =opendir("/etc/rc.d");
        while((ptr = readdir(dir))!=null)
        {
            printf("d_name: %s\n",ptr->d_name);
         }
        closedir(dir);
    }
    
  4. telldir(取得目录流的读取位置)

    相关函数open,opendir,closedir,rewinddir,seekdir,readdir,scandir
    表头文件#include<dirent.h>
    定义函数off_t telldir(DIR *dir);
    函数说明telldir()返回参数dir目录流目前的读取位置。此返回值代表距离目录文件开头的偏移量
    返回值返回下个读取位置,有错误发生时返回-1。
    错误代码EBADF 参数dir为无效的目录流。
    #include<sys/types.h>
    #include<dirent.h>
    #include<unistd.h>
    main()
    {
        DIR *dir;
        struct dirent *ptr;
        int offset;
        dir = opendir("/etc/rc.d");
        while((ptr = readdir(dir))!=null)
        {  
            offset = telldir (dir);
            printf("d_name : %s offset :%d\n", ptr->d_name,offset);
        }
        closedir(dir);
    }
    
  5. seekdir(设置下回读取目录的位置)

    相关函数open,opendir,closedir,rewinddir,telldir,readdir,scandir
    表头文件#include<dirent.h>
    定义函数void seekdir(DIR * dir,off_t offset);
    函数说明seekdir()用来设置参数dir目录流目前的读取位置,在调用readdir()时便从此新位置开始读取。参数offset代表距离目录文件开头的偏移量。
    返回值
    错误代码EBADF 参数dir为无效的目录流
    #include<sys/types.h>
    #include<dirent.h>
    #include<unistd.h>
    main()
    {
        DIR * dir;
        struct dirent * ptr;
        int offset,offset_5,i=0;
        dir=opendir("/etc/rc.d");
        while((ptr = readdir(dir))!=NULL)
        {
            offset = telldir(dir);
            if(++i = =5) offset_5 =offset;
            printf("d_name :%s offset :%d \n",ptr->d_name,offset);
        }
        seekdir(dir offset_5);
        printf("Readdir again!\n");
        while((ptr = readdir(dir))!=NULL)
        {
            offset = telldir(dir);
            printf("d_name :%s offset :%d\n",ptr->d_name.offset);
        }
        closedir(dir);
    }
    

文件结束

  1. feof(检查文件流是否读到了文件尾)

    相关函数fopen,fgetc,fgets,fread
    表头文件#include<stdio.h>
    定义函数int feof(FILE * stream);
    函数说明feof()用来侦测是否读取到了文件尾,尾数stream为fopen()所返回之文件指针。如果已到文件尾则返回非零值,其他情况返回0。
    返回值返回非零值代表已到达文件尾。

初始权限和umask设置

  • 通常,指定“当前用户在建立文件或目录时的属性默认值”,linux用umask。

  • 以数字类型显示权限设置分数

    [root@lhb ~]# umask
    0022
    
  • 加入参数-S,以符号类型方式显示

    [root@lhb ~]# umask -S
    u=rwx,g=rx,o=rx
    

    【说明】在默认情况下:

    • 文件只有rw,而没有x权限,即-rw-rw-rw- (数字为666)
    • 目录是全开放的,即 drwxrwxrwx (数字为777)
  • umask除了可以查看权限外还可以指定:该默认权限需要减掉的权限。

    • 查看当前用户指定权限

      [root@lhb ~]# umask
      0022
      
    • 建立空白文件

      [root@lhb ~]# touch test1
      
    • 建立文件夹

      [root@lhb ~]# mkdir test2
      

错误处理

  1. ferror(检查文件流是否有错误发生)

    相关函数clearerr,perror
    表头文件#include<stdio.h>
    定义函数int ferror(FILE *stream);
    函数说明ferror()用来检查参数stream所指定的文件流是否发生了错误情况,如有错误发生则返回非0值。
    返回值如果文件流有错误发生则返回非0值。
  2. clearer(清除文件流的错误旗标)

    相关函数feof
    表头文件#include<stdio.h>
    定义函数void clearerr(FILE * stream);
    函数说明clearerr()清除参数stream指定的文件流所使用的错误旗标。
    返回值
  3. strerror(返回错误原因的描述字符串)

    相关函数perror
    表头文件#include<string.h>
    定义函数char * strerror(int errnum);
    函数说明strerror()用来依参数errnum的错误代码来查询其错误原因的描述字符串,然后将该字符串指针返回。
    返回值返回描述错误原因的字符串指针。
    /* 显示错误代码0至9的错误原因描述 */
    #include<string.h>
    main()
    {
     	int i;
     	for(i=0;i<10;i++)
      	printf("%d : %s\n",i,strerror(i));
    }
    
    
  4. perror(打印出错误原因信息字符串)

    相关函数strerror
    表头文件#include<stdio.h>
    定义函数void perror(const char *s);
    函数说明perror()用来将上一个函数发生错误的原因输出到标准错误(stderr)。参数s所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
    返回值
    #include<stdio.h>
    main()
    {
        FILE *fp;
        fp = fopen("/tmp/noexist","r+");
        if(fp = =NULL)
            perror("fopen");
    }
    

第四章 输入输出

标准输入/输出

  1. fgetc(由文件中读取一个字符)

    相关函数fopen,fread,fscanf,getc
    表头文件#include<stdio.h>
    定义函数int fgetc(FILE * stream);
    函数说明fgetc()用来从参数stream所指的文件中读取一个字符。若读到文件尾而无数据时便返回EOF。
    返回值fgetc()会返回读取到的字符,若返回EOF则表示到了文件尾。
    #include<stdio.h> 
    void main() 
    { 
        FILE *fp; 
        int c; 
        fp=fopen("exist","r"); 
        while((c=fgetc(fp))!=EOF) 
            printf("%c",c); 
        fclose(fp); 
    }
    
  2. getc(由文件中读取一个字符)

    相关函数read,fopen,fread,fgetc
    表头文件#include<stdio.h>
    定义函数int getc(FILE * stream);
    函数说明getc()用来从参数stream所指的文件中读取一个字符。若读到文件尾而无数据时便返回EOF。虽然getc()与fgetc()作用相同,但getc()为宏定义,非真正的函数调用。
    返回值getc()会返回读取到的字符,若返回EOF则表示到了文件尾。
    #include <stdio.h> 
    int main(void) 
    { 
    char ch; 
    printf("Input a character:"); 
    /* read a character from the 
    standard input stream */
    ch = getc(stdin); 
    printf("The character input was: '%c'\n", 
    ch); 
    return 0; 
    }
    
  3. putc(将一指定字符写入文件中)

    相关函数fopen,fwrite,fscanf,fputc
    表头文件#include<stdio.h>
    定义函数int putc(int c,FILE * stream);
    函数说明putc()会将参数c转为unsigned char后写入 参数stream指定的文件中。虽然putc()与fputc()作用相同,但putc()为宏定义,非真正的函数调用。
    返回值putc()会返回写入成功的字符,即参数c。若返回EOF则代表写入失败。
    #include <stdio.h> 
    int main(void) 
    { 
    char msg[] = "Hello world\n"; 
    int i = 0; 
    while (msg[i]) 
    putc(msg[i++],stdout); 
    return 0; 
    }
    
  4. getchar(由标准输入设备内读进一字符)

    相关函数fopen,fread,fscanf,getc
    表头文件#include<stdio.h>
    定义函数int getchar(void);
    函数说明getchar()用来从标准输入设备中读取一个字符。然后将该字符从unsigned char转换成int后返回。
    返回值getchar()会返回读取到的字符,若返回EOF则表示有错误发生。
    附加说明getchar()非真正函数,而是getc(stdin)宏定义。
  5. putchar(将指定的字符写到标准输出设备)

    相关函数fopen,fwrite,fscanf,fputc
    表头文件#include<stdio.h>
    定义函数int putchar (int c);
    函数说明putchar()用来将参数c字符写到标准输出设备。
    返回值putchar()会返回输出成功的字符,即参数c。若返回EOF则代表输出失败。
    附加说明putchar()非真正函数,而是putc(c,stdout)宏定义。
  6. fgets(由文件中读取一字符串)

    相关函数fopen,fread,fscanf,getc
    表头文件#include<stdio.h>
    定义函数char * fgets(char * s,int size,FILE * stream);
    函数说明fgets()用来从参数stream所指的文件内读入字符并存到参数s所指的内存空间,直到出现换行字符、读到文件尾或是已读了size-1个字符为止,最后会加上NULL作为字符串结束。
    返回值fgets()若成功则返回s指针,返回NULL则表示有错误发生。
    #include <string.h> 
    #include <stdio.h> 
    int main(void) 
    { 
        FILE *stream; 
        char string[] = "This is a test"; 
        char msg[20]; /* open a file for update */
        stream = fopen("DUMMY.FIL", "w+"); /* write a string into the file */
        fwrite(string, strlen(string), 1, stream); /* seek to the start of the file */
        fseek(stream, 0, SEEK_SET); //read a string from the file */
        fgets(msg, strlen(string)+1, stream); // display the string     printf("%s", msg); 
        fclose(stream); 
        return 0; 
    }
    
  7. fputs(将一指定的字符串写入文件内)

    相关函数fopen,fwrite,fscanf,fputc,putc
    表头文件#include<stdio.h>
    定义函数int fputs(const char * s,FILE * stream);
    函数说明fputs()用来将参数s所指的字符串写入到参数stream所指的文件内。
    返回值若成功则返回写出的字符个数,返回EOF则表示有错误发生。
    #include <stdio.h> 
    main() 
    { 
    char str[80]="I/O system."; / *字符串常量存入字符数组*/ 
    FILE *fp;  /*定义文件指针fp*/
    if((fp=fopen("strfile","w"))==NULL) /*打开文件写模式*/
    { 
    printf("cannot open the file.\n") /*判断文件是否正常打开*/
    exit(0); 
    } 
    fputs(str,fp); /*将字符串写入文件*/
    fclose(fp); /*关闭文件*/
    return ; 
    }
    
  8. gets(由标准输入设备内读进一字符串)

    相关函数fopen,fwrite,fscanf,fputc,putc
    表头文件#include<stdio.h>
    定义函数int fputs(const char * s,FILE * stream);
    函数说明fputs()用来将参数s所指的字符串写入到参数stream所指的文件内。
    返回值若成功则返回写出的字符个数,返回EOF则表示有错误发生。
    #include <stdio.h> //这个头文件包含gets()函数 
    int main(void) 
    { 
        char str1[5]; 
        gets(str1); 
        printf("%s\n", str1); 
        return 0; 
    }
    

格式化输入/输出

  1. printf(格式化输出数据)

    相关函数scanf,snprintf
    表头文件#include<stdio.h>
    定义函数int printf(const char * format,…);
  2. scanf(格式化字符串输入)

    相关函数fscanf,snprintf
    表头文件#include<stdio.h>
    定义函数int scanf(const char * format,…);
    函数说明scanf()会将输入的数据根据参数format字符串来转换并格式化数据。scanf()格式转换的一般形式如下:
    %[ * ] [ size ] [ l ] [ h ]type。以中括号括起来的参数为选择性参数,而%与type则是必要的。* 代表该对应的参数数据忽略不保存。size 为允许参数输入的数据长度。
    输入的数据数值以long int 或double型保存。h 输入的数据数值以short int 型保存。 底下介绍type的几种形式:
    %d 输入的数据会被转成一有符号的十进制数字(int)。
    %i 输入的数据会被转成一有符号的十进制数字,若输入数据以“0x”或“0X”开头代表转换十六进制数字,若以“0”开头则转换八进制数字,其他情况代表十进制。
    %0 输入的数据会被转换成一无符号的八进制数字。
    %u 输入的数据会被转换成一无符号的正整数。
    %x 输入的数据为无符号的十六进制数字,转换后存于unsigned int型变量。
    %f 输入的数据为有符号的浮点型数,转换后存于float型变量。 %s 输入数据为以空格字符为终止的字符串。
    %c 输入数据为单一字符。
    [] 读取数据但只允许括号内的字符。如[a-z]。
    [^] 读取数据但不允许中括号的^符号后的字符出现,如[ ^0-9 ].
    返回值成功则返回参数数目,失败则返回-1,错误原因存于errno中。
  3. fprintf(格式化输出数据至文件)

    相关函数printf,fscanf,vfprintf
    表头文件#include<stdio.h>
    定义函数int fprintf(FILE * stream, const char * format,…);
    函数说明fprintf()会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的文件中,直到出现字符串结束(‘\0‘)为止。
    返回值关于参数format字符串的格式请参考printf()。成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。

错误处理

  1. exit(正常结束进程)

    相关函数_exit,atexit,on_exit
    表头文件#include<stdlib.h>
    定义函数void exit(int status);
    函数说明exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。
    返回值

其他流函数

  1. ftell(取得文件流的读取位置)

    相关函数fseek,rewind,fgetpos,fsetpos
    表头文件#include<stdio.h>
    定义函数long ftell(FILE * stream);
    函数说明ftell()用来取得文件流目前的读写位置。参数stream为已打开的文件指针。
    返回值当调用成功时则返回目前的读写位置,若有错误则返回-1,errno会存放错误代码。
    错误代码EBADF 参数stream无效或可移动读写位置的文件流。
    #include <stdio.h>
    main()
    {
    FILE *myf;
    long f1;
    myf=fopen("1.txt","rb");
    fseek(myf,0,SEEK_END);
    f1=ftell(myf);
    fclose(myf);
    printf(%d\n”,f1);
    }
    
  2. fseek(移动文件流的读写位置)

    相关函数rewind,ftell,fgetpos,fsetpos,lseek
    表头文件#include<stdio.h>
    定义函数int fseek(FILE * stream,long offset,int whence);
    函数说明fseek()用来移动文件流的读写位置。参数stream为已打开的文件指针,参数offset为根据参数whence来移动读写位置的位移数。参数whence为下列其中一种:SEEK_SET从距文件开头offset位移量为新的读写位置。SEEK_CUR以目前的读写位置往后增加offset个位移量。SEEK_END将读写位置指向文件尾后再增加offset个位移量。 当whence值为SEEK_CUR或SEEK_END时,参数offset允许负值的出现。下列是较特别的使用方式: 1)欲将读写位置移动到文件开头时:fseek(FILE * stream,0,SEEK_SET); 2)欲将读写位置移动到文件尾时:fseek(FILE * stream,0,0SEEK_END);
    返回值当调用成功时则返回0,若有错误则返回-1,errno会存放错误代码。
    附加说明fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置。
  3. rewind(重设文件流的读写位置为文件开头)

    相关函数fseek,ftell,fgetpos,fsetpos
    表头文件#include<stdio.h>
    定义函数void rewind(FILE * stream);
    函数说明rewind()用来把文件流的读写位置移至文件开头。参数stream为已打开的文件指针。此函数相当于调用fseek(stream,0,SEEK_SET)。
    返回值
    fp = fopen(newname,"w+");
    if(NULL==fp)
    return 1;
    fprintf(fp,"abcdefghijklmnopqrstuvwxyz");
    rewind(fp);
    fscanf(fp,"%c",&first);
    
  4. freopen(打开文件)

    相关函数fopen,fclose
    表头文件#include<stdio.h>
    定义函数FILE * freopen(const char * path,const char * mode,FILE * stream);
    函数说明参数path字符串包含欲打开的文件路径及文件名,参数mode请参考fopen()说明。参数stream为已打开的文件指针。freopen()会将原stream所打开的文件流关闭,然后打开参数path的文件。
    返回值文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
  5. setvbuf(设置文件流的缓冲区)

    相关函数setbuffer,setlinebuf,setbuf
    表头文件#include<stdio.h>
    定义函数int setvbuf(FILE * stream,char * buf,int mode,size_t size);
    函数说明在打开文件流后,读取内容之前,调用setvbuf()可以用来设置文件流的缓冲区。参数stream为指定的文件流,参数buf指向自定的缓冲区起始地址,参数size为缓冲区大小,参数mode有下列几种: _IONBF 无缓冲IO _IOLBF 以换行为依据的无缓冲IO _IOFBF 完全无缓冲IO。如果参数buf为NULL指针,则为无缓冲IO。
    返回值
    include <stdio.h>
    int main(void) 
    { 
        FILE *input, *output; 
        char bufr[512]; 
        input = fopen("file.in", "r+b"); 
        output = fopen("file.out", "w"); 
        /* set up input stream for minimal disk access, using our own character buffer */ 
        if (setvbuf(input, bufr, _IOFBF, 512) != 0) 
            printf("failed to set up buffer for input file\n"); 
        else 
            printf("buffer set up for input file\n"); 
        /* set up output stream for line buffering using space that will be obtained through an indirect call to malloc */ 
        if (setvbuf(output, NULL, _IOLBF, 132) != 0) 
            printf("failed to set up buffer for output file\n"); 
        else 
            printf("buffer set up for output file\n"); 
        /* perform file I/O here */ 
        /* close files */ 
        fclose(input); 
        fclose(output); 
        return 0; 
    }
    
  6. fflush(更新缓冲区)

    相关函数write,fopen,fclose,setbuf
    表头文件#include<stdio.h>
    定义函数int fflush(FILE* stream);
    函数说明fflush()会强迫将缓冲区内的数据写回参数stream指定的文件中。如果参数stream为NULL,fflush()会将所有打开的文件数据更新。
    返回值成功返回0,失败返回EOF,错误代码存于errno中。
    错误代码EBADF 参数stream指定的文件未被打开,或打开状态为只读。其它错误代码参考write()。
    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {		
        int i;		
        for(i = 0 ;i < 5 ;i++)		
        {		
            putchar('X');		
            fflush(NULL);		
            sleep(1);	
        }	
        putchar('\n');	
        exit(0);
    }
    
  7. remove(删除文件)

    相关函数link,rename,unlink
    表头文件#include<stdio.h>
    定义函数int remove(const char * pathname);
    函数说明remove()会删除参数pathname指定的文件。如果参数pathname为一文件,则调用unlink()处理,若参数pathname为一目录,则调用rmdir()来处理。请参考unlink()与rmdir()。
    返回值成功则返回0,失败则返回-1,错误原因存于errno
    错误代码EROFS 欲写入的文件存在于只读文件系统内 EFAULT 参数pathname指针超出可存取内存空间。 ENAMETOOLONG 参数pathname太长 ENOMEM 核心内存不足 ELOOP 参数pathname有过多符号连接问题 EIO I/O存取错误。

第五章 时间日期

当天时间

  • time(取得目前的时间)

    相关函数ctime,ftime,gettimeofday
    表头文件#include<time.h>
    定义函数time_t time(time_t *t);
    函数说明此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。如果t并非空指针的话,此函数也会将返回值存到t指针所指的内存。
    返回值成功则返回秒数,失败则返回((time_t)-1)值,错误原因存于errno中。

取得目前的时间

  1. gettimeofday(取得目前的时间)

    相关函数time,ctime,ftime,settimeofday
    表头文件#include <sys/time.h> ; #include <unistd.h>
    定义函数int gettimeofday ( struct timeval * tv , struct timezone * tz )
    函数说明gettimeofday () 会把目前的时间有tv 所指的结构返回,当地时区的信息则放到tz所指的结构中。timeval结构定义为: struct timeval{ long tv_sec; /* 秒 */ long tv_usec; / * 微秒 * / }; timezone 结构定义为: struct timezone{ int tz_minuteswest; / * 和Greenwich时间差了多少分钟 * / int tz_dsttime; / * 日光节约时间的状态 */ }; 上述两个结构都定义在 /usr/include/sys/time.h。
    返回值成功则返回0,失败返回-1,错误代码存于errno。
    附加说明EFAULT指针tv和tz所指的内存空间超出存取权限。

取得目前时间和日期

  1. gmtime(取得目前时间和日期)

    相关函数time,asctime,ctime,localtime
    表头文件#include<time.h>
    定义函数struct tmgmtime(const time_ttimep);
    函数说明gmtime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。结构tm的定义为: struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; };
    返回值返回结构tm代表目前UTC时间
  2. localtime(取得当地目前时间和日期)

    相关函数time, asctime, ctime, gmtime
    表头文件#include<time.h>
    定义函数struct tm *localtime(const time_t * timep);
    函数说明localtime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。结构tm的定义请参考gmtime()。此函数返回的时间日期已经转换成当地时区。
    返回值返回结构tm代表目前的当地时间。

将时间结构数据转换成经过的秒数

  1. mktime(将时间结构数据转换成经过的秒数)

    相关函数time,asctime,gmtime,localtime
    表头文件#include<time.h>
    定义函数time_t mktime(strcut tm * timeptr);
    函数说明mktime()用来将参数timeptr所指的tm结构数据转换成从公元1970年1月1日0时0分0秒算起至今的UTC时间所经过的秒数。
    返回值返回经过的秒数。

时间/日期的字符串表示

  1. asctime(将时间和日期以字符串格式表示)

    相关函数time,ctime,gmtime,localtime
    表头文件#include<time.h>
    定义函数char * asctime(const struct tm * timeptr);
    函数说明asctime()将参数timeptr所指的tm结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回。此函数已经由时区转换成当地时间,字符串格式为: “Wed Jun 30 21:49:08 1993\n”
    返回值若再调用相关的时间日期函数,此字符串可能会被破坏。此函数与ctime不同处在于传入的参数是不同的结构。
    附加说明返回一字符串表示目前当地的时间日期。
  2. ctime(将时间和日期以字符串格式表示)

    相关函数time,asctime,gmtime,localtime
    表头文件#include<time.h>
    定义函数char *ctime(const time_t *timep);
    函数说明ctime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回。此函数已经由时区转换成当地时间,字符串格式为“Wed Jun 30 21 :49 08 1993\n”。若再调用相关的时间日期函数,此字符串可能会被破坏。
    返回值返回一字符串表示目前当地的时间日期。

周期计数

  • difftime(计算时间间隔)

    相关函数time,asctime,gmtime,localtime
    表头文件#include<time.h>
    定义函数double difftime(time_t time2, time_t time1);
    函数说明返回两个time_t型变量之间的时间间隔,即 计算两个时刻之间的时间差。

自定义时间格式

  • strftime(自定义时间格式)

    相关函数time,asctime,gmtime,localtime
    表头文件#include<time.h>
    定义函数size_t strftime( char *strDest, size_t maxsize, const char *format, const struct tm *timeptr );
    函数说明我们可以根据format指向字符串中格式命令把timeptr中保存的时间信息放在strDest指向的字符串中,最多向strDest中存放maxsize个字符。该函数返回向strDest指向的字符串中放置的字符数。 函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明串strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大小写的。
    返回值返回值为处理结果字符串str中字符的个数,如果发生错误返回零。

在这里插入图片描述

第六章 字符串处理

C语言中的字符串

  1. C语言中没有专门的string类型,以字符数组的方式来表示字符串

  2. 字符数组和字符串区别在于字符串有结束符’\0’

  3. 字符串的定义

    • 常量字符串

       char *str = "hello";
      
    • 非常量字符串

      char str[] = "hello";
      
  4. 字符数组的定义

    char ch[5];
    

字符串长度

  • strlen(返回字符串长度)

    相关函数
    表头文件#include<string.h>
    定义函数size_t strlen ( const char *s);
    函数说明strlen()用来计算指定的字符串s的长度,不包括结束字符“\0”。
    返回值返回字符串s的字符数。

不受限制的字符串函数

  1. strcpy(拷贝字符串)

    相关函数bcopy,memcpy,memccpy,memmove
    表头文件#include<string.h>
    定义函数char *strcpy(char *dest,const char *src);
    函数说明strcpy()会将参数src字符串拷贝至参数dest所指的地址。
    返回值返回参数dest的字符串起始地址。
    附加说明如果参数dest所指的内存空间不够大,可能会造成缓冲溢出(buffer Overflow)的错误情况,在编写程序时请特别留意,或者用strncpy()来取代。
  2. strcat(连接两字符串)

    相关函数bcopy,memccpy,memcpy,strcpy,strncpy
    表头文件#include <string.h>
    定义函数char *strcat (char *dest,const char *src);
    函数说明strcat()会将参数src字符串拷贝到参数dest所指的字符串尾。第一个参数dest要有足够的空间来容纳要拷贝的字符串。
    返回值返回参数dest的字符串起始地址
  3. strcmp(比较字符串)

    相关函数bcmp,memcmp,strcasecmp,strncasecmp,strcoll
    表头文件#include<string.h>
    定义函数int strcmp(const char *s1,const char *s2);
    函数说明strcmp()用来比较参数s1和s2字符串。字符串大小的比较是以ASCII码表上的顺序来决定,此顺序亦为字符的值。strcmp()首先将s1第一个字符值减去s2第一个字符值,若差值为0则再继续比较下个字符,若差值不为0则将差值返回。例如字符串“Ac”和“ba”比较则会返回字符“A”(65)和‘b’(98)的差值(-33)。
    返回值若参数s1和s2字符串相同则返回0。s1若大于s2则返回大于0的值。s1若小于s2则返回小于0的值。

长度受限的字符串函数

  1. strncpy(拷贝字符串)

    相关函数bcopy,memccpy,memcpy,memmove
    表头文件#include<string.h>
    定义函数char * strncpy(char *dest,const char *src,size_t n);
    函数说明strncpy()会将参数src字符串拷贝前n个字符至参数dest所指的地址。
    返回值返回参数dest的字符串起始地址。
  2. strncat(连接两字符串)

    相关函数bcopy,memccpy,memecpy,strcpy,strncpy
    表头文件#inclue <string.h>
    定义函数char * strncat(char *dest,const char *src,size_t n);
    函数说明strncat()会将参数src字符串拷贝n个字符到参数dest所指的字符串尾。第一个参数dest要有足够的空间来容纳要拷贝的字符串。
    返回值返回参数dest的字符串起始地址。

字符串查找基础

  1. strcspn(返回字符串中连续不含指定字符串内容的字符数)

    相关函数strspn
    表头文件#inclued<string.h>
    定义函数size_t strcspn ( const char *s,const char * reject);
    函数说明strcspn()从参数s字符串的开头计算连续的字符,而这些字符都完全不在参数reject所指的字符串中。简单地说,若strcspn()返回的数值为n,则代表字符串s开头连续有n个字符都不含字符串reject内的字符。
    返回值返回字符串s开头连续不含字符串reject内的字符数目。
  2. strchr(查找字符串中第一个出现的指定字符)

    相关函数index,memchr,rinex,strbrk,strsep,strspn,strstr,strtok
    表头文件#include<string.h>
    定义函数char * strchr (const char *s,int c);
    函数说明strchr()用来找出参数s字符串中第一个出现的参数c地址,然后将该字符出现的地址返回。
    返回值如果找到指定的字符则返回该字符所在地址,否则返回0。
  3. strrchr(查找字符串中最后出现的指定字符)

    相关函数index,memchr,rindex,strpbrk,strsep,strspn,strstr,strtok
    表头文件#include<string.h>
    定义函数char * strrchr(const char *s, int c);
    函数说明strrchr()用来找出参数s字符串中最后一个出现的参数c地址,然后将该字符出现的地址返回。
    返回值如果找到指定的字符则返回该字符所在地址,否则返回0。
  4. strpbrk(查找字符串中第一个出现的指定字符)

    相关函数index,memchr,rindex,strpbrk,strsep,strspn,strstr,strtok
    表头文件#include <include.h>
    定义函数char *strpbrk(const char *s,const char *accept);
    函数说明strpbrk()用来找出参数s字符串中最先出现存在参数accept字符串中的任意字符。
    返回值如果找到指定的字符则返回该字符所在地址,否则返回0。
  5. strstr(在一字符串中查找指定的字符串)

    相关函数index,memchr,rindex,strchr,strpbrk,strsep,strspn,strtok
    表头文件#include<string.h>
    定义函数char *strstr(const char *haystack,const char *needle);
    函数说明strstr()会从字符串haystack中搜寻字符串needle,并将第一次出现的地址返回。
    返回值返回指定字符串第一次出现的地址,否则返回0。

高级字符串查找

  1. strspn(返回字符串中连续不含指定字符串内容的字符数)

    相关函数strcspn,strchr,strpbrk,strsep,strstr
    表头文件#include<string.h>
    定义函数size_t strspn (const char *s,const char * accept);
    函数说明strspn()从参数s字符串的开头计算连续的字符,而这些字符都完全是accept所指字符串中的字符。简单的说,若strspn()返回的数值为n,则代表字符串s开头连续有n个字符都是属于字符串accept内的字符。
    返回值返回字符串s开头连续包含字符串accept内的字符数目。
  2. strcspn(返回字符串中连续不含指定字符串内容的字符数)

    相关函数strspn
    表头文件#inclued<string.h>
    定义函数size_t strcspn ( const char *s,const char * reject);
    函数说明strcspn()从参数s字符串的开头计算连续的字符,而这些字符都完全不在参数reject所指的字符串中。简单地说,若strcspn()返回的数值为n,则代表字符串s开头连续有n个字符都不含字符串reject内的字符。
    返回值返回字符串s开头连续不含字符串reject内的字符数目。
  3. strtok(分割字符串)

    相关函数index,memchr,rindex,strpbrk,strsep,strspn,strstr
    表头文件#include<string.h>
    定义函数char * strtok(char *s,const char *delim);
    函数说明strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为\0字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
    返回值返回下一个分割后的字符串指针,如果已无从分割则返回NULL。

报错信息

  • strerror(返回错误原因的描述字符串)

    相关函数perror
    表头文件#include<string.h>
    定义函数char * strerror(int errnum);
    函数说明strerror()用来依参数errnum的错误代码来查询其错误原因的描述字符串,然后将该字符串指针返回。
    返回值返回描述错误原因的字符串指针。

字符转换函数

  1. tolower(将大写字母转换成小写字母)

    相关函数isalpha,toupper
    表头文件#include<stdlib.h>
    定义函数int tolower(int c);
    函数说明若参数c为大写字母则将该对应的小写字母返回。
    返回值返回转换后的小写字母,若不须转换则将参数c值返回。
  2. toupper(将小写字母转换成大写字母)

    相关函数isalpha,tolower
    表头文件#include<ctype.h>
    定义函数int toupper(int c);
    函数说明若参数c为小写字母则将该对映的大写字母返回。
    返回值返回转换后的大写字母,若不须转换则将参数c值返回。

内存操作,任意字节序列的处理

  1. memcpy(拷贝内存内容)

    相关函数bcopy,memccpy,memcpy,memmove,strcpy,strncpy
    表头文件#include<string.h>
    定义函数void * memcpy (void * dest ,const void *src, size_t n);
    函数说明memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束‘\0‘而结束。
    返回值返回指向dest的指针。
    附加说明指针src和dest所指的内存区域不可重叠。
  2. memmove(拷贝内存内容)

    相关函数bcopy,memccpy,memcpy,strcpy,strncpy
    表头文件#include<string.h>
    定义函数void * memmove(void *dest,const void *src,size_t n);
    函数说明memmove()与memcpy()一样都是用来拷贝src所指的内存内容前n个字节到dest所指的地址上。不同的是,当src和dest所指的内存区域重叠时,memmove()仍然可以正确的处理,不过执行效率上会比使用memcpy()略慢些。
    返回值返回指向dest的指针。
    附加说明指针src和dest所指的内存区域可以重叠。
  3. memcmp(比较内存内容)

    相关函数bcmp,strcasecmp,strcmp,strcoll,strncmp,strncasecmp
    表头文件#include<string.h>
    定义函数int memcmp (const void *s1,const void *s2,size_t n);
    函数说明memcmp()用来比较s1和s2所指的内存区间前n个字符。字符串大小的比较是以ASCII码表上的顺序来决定,次顺序亦为字符的值。memcmp()首先将s1第一个字符值减去s2第一个字符的值,若差为0则再继续比较下个字符,若差值不为0则将差值返回。例如,字符串“Ac”和“ba”比较则会返回字符‘A’(65)和‘b’(98)的差值(-33)。
    返回值若参数s1和s2所指的内存内容都完全相同则返回0值。s1若大于s2则返回大于0的值。s1若小于s2则返回小于0的值。
  4. memchr(在某一内存范围中查找一特定字符)

    相关函数index,rindex,strchr,strpbrk,strrchr,strsep,strspn,strstr
    表头文件#include<string.h>
    定义函数void * memchr(const void *s,int c,size_t n);
    函数说明memchr()从头开始搜寻s所指的内存内容前n个字节,直到发现第一个值为c的字节,则返回指向该字节的指针。
    返回值如果找到指定的字节则返回该字节的指针,否则返回0。
  5. memset(将一段内存空间填入某值)

    相关函数bzero,swab
    表头文件#include<string.h>
    定义函数void * memset (void *s ,int c, size_t n);
    函数说明memset()会将参数s所指的内存区域前n个字节以参数c填入,然后返回指向s的指针。在编写程序时,若需要将某一数组作初始化,memset()会相当方便。
    返回值返回指向s的指针。
    附加说明参数c虽声明为int, 但必须是unsigned char ,所以范围在0到255之间。

第七章 类型转换

字符串转换为双精度型

  1. atof(将字符串转换成浮点型数)

    相关函数atoi,atol,strtod,strtol,strtoul
    表头文件#include <stdlib.h>
    定义函数double atof(const char *nptr);
    函数说明atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(’\0’)才结束转换,并将结果返回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分,如123.456或123e-2。
    返回值返回转换后的浮点型数。
    附加说明atof()与使用strtod(nptr,(char**)NULL);结果相同。

字符串转换为整型

  1. atoi(将字符串转换成整型数)

    相关函数atof,atol,atrtod,strtol,strtoul
    表头文件#include<stdlib.h>
    定义函数int atoi(const char *nptr);
    函数说明atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(’\0’)才结束转换,并将结果返回。
    返回值返回转换后的整型数。
    附加说明atoi()与使用strtol(nptr,(char**)NULL,10);结果相同。

字符串转换为长整型

  1. atol(将字符串转换成长整型数)

    相关函数atof,atoi,strtod,strtol,strtoul
    表头文件#include<stdlib.h>
    定义函数long atol(const char *nptr);
    函数说明atol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(’\0’)才结束转换,并将结果返回。
    返回值返回转换后的长整型数。
    附加说明atol()与使用strtol(nptr,(char**)NULL,10);结果相同。

高级类型转换

  1. strtod(将字符串转换成浮点数)

    相关函数atoi,atol,strtod,strtol,strtoul
    表头文件#include<stdlib.h>
    定义函数double strtod(const char *nptr,char **endptr);
    函数说明strtod()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,直到出现非数字或字符串结束时(’\0’)才结束转换,并将结果返回。若endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr传回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分。如123.456或123e-2。
    返回值返回转换后的浮点型数。
    附加说明参考atof()。
  2. strtol(将字符串转换成长整型数)

    相关函数atof,atoi,atol,strtod,strtoul
    表头文件#include<stdlib.h>
    定义函数long int strtol(const char *nptr,char **endptr,int base);
    函数说明strtol()会将参数nptr字符串根据参数base来转换成长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制等。当base值为0时则是采用10进制做转换,但遇到如’0x’前置字符则会使用16进制做转换。一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时(‘\0’)结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
    返回值返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中。
    附加说明ERANGE指定的转换字符串超出合法范围。
  3. strtoul(将字符串转换成无符号长整型数)

    相关函数atof,atoi,atol,strtod,strtol
    表头文件#include<stdlib.h>
    定义函数unsigned long int strtoul(const char *nptr,char **endptr,int base);
    函数说明strtoul()会将参数nptr字符串根据参数base来转换成无符号的长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制数等。当base值为0时则是采用10进制做转换,但遇到如’0x’前置字符则会使用16进制做转换。一开始strtoul()会扫描参数nptr字符串,跳过前面的空格字符串,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时(’\0’)结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
    返回值返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中。
    附加说明ERANGE指定的转换字符串超出合法范围。

将整型数转换成合法的ASCII码字符

  1. toascii(将整型数转换成合法的ASCII码字符)

    相关函数isascii,toupper,tolower
    表头文件#include<ctype.h>
    定义函数int toascii(int c)
    函数说明toascii()会将参数c转换成7位的unsigned char值,第八位则会被清除,此字符即会被转成ASCII码字符。
    返回值将转换成功的ASCII码字符值返回。

第八章 内存管理

动态内存分配

函数任务
malloc分配请求的字节数并返回首字节地址
calloc与malloc相同,但增加了初始化内存空间(为0)的功能
free释放先前分配的空间
realloc修改之前分配的空间大小

利用malloc来进行动态内存分配(堆)

  1. malloc(配置内存空间)

    相关函数calloc,free,realloc,brk
    表头文件#include<stdlib.h>
    定义函数void * malloc(size_t size);
    函数说明malloc()用来配置内存空间,其大小由指定的size决定。
    返回值若配置成功则返回一指针,失败则返回NULL。
    • 函数malloc声明一个指定大小的内存块,并返回一个指针,该指针类型为 void.

      ptr = (cast-type *) malloc(byte-size);
      x = (int *) malloc(100 * sizeof(int));
      cptr = (char *) malloc(10);
      //成功执行后,内存空间完成分配。
      

free释放内存

  1. free(释放原先配置的内存)

    相关函数malloc,calloc,realloc,brk
    表头文件#include<stdlib.h>
    定义函数void free(void *ptr);
    函数说明参数ptr为指向先前由malloc()、calloc()或realloc()所返回的内存指针。调用free()后ptr所指的内存空间便会被收回。假若参数ptr所指的内存空间已被收回或是未知的内存地址,则调用free()可能会有无法预期的情况发生。若参数ptr为NULL,则free()不会有任何作用。

calloc和realloc

  1. Calloc(配置内存空间)

    相关函数malloc,free,realloc,brk
    表头文件#include <stdlib.h>
    定义函数void *calloc(size_t nmemb,size_t size);
    函数说明calloc()用来配置nmemb个相邻的内存单位,每一单位的大小为size,并返回指向第一个元素的指针。这和使用下列的方式效果相同:malloc(nmemb* size);不过,在利用calloc()配置内存时会将内存内容初始化为0。
    返回值若配置成功则返回一指针,失败则返回NULL。
    • calloc allocates分配多个存储块,每个块的大小相同,之后设定所分配的自己为0。

    • 函数calloc的通用形式为

      ptr = (cast-type *) calloc (n, elem-size);
      
    • 如果没有足够空间可以分配,会返回一个NULL指针。

  2. 更改内存块的大小: realloc

    • 分配空间后,可能遇到这种问题:

      • 之前分配的内存不足(需增加空间)
      • 之前分配的内存过多(需减少空间)
    • 可以通过函数realloc更改内存空间。

      ptr = malloc(size);
      ptr = realloc(ptr, newsize);
      

      newsize表示新的大小,可以比原先分配的数量大或者小

使用动态分配的内存

  1. getpagesize(取得内存分页大小)

    相关函数sbrk
    表头文件#include<unistd.h>
    定义函数size_t getpagesize(void);
    函数说明返回一分页的大小,单位为字节(byte)。此为系统的分页大小,不一定会和硬件分页大小相同。
    返回值内存分页大小。
    附加说明在Intel x86上其返回值应为4096bytes。
  2. 动态分配多维数组

    • 可以直接通过调用malloc分配内存块来模拟数组。但通过得到的大小size在运行时指定大小。

    • 能否用同样的方法来模拟多维数组?

    • 我们希望模拟多维数组,但并不知道有多少行,因此我们只能用另一个指针模拟那个(指针的)数组,这样就形成了一个指向指针的指针。

    • 如果一个程序使用了模拟的动态分配多维数组,就可以编写混合函数,混合函数(在编译时)不需要知道“数组”的大小。一个函数就可以对多种大小的“数组”进行操作

      func(int **array, int nrows, int ncolumns){}
      
    • 例如
      在这里插入图片描述

    • 要释放这种动态分配的多维数组,需要对分配的每个大块的内存予以释放在这里插入图片描述

第九章 进程/线程编程

进程

  1. 进程概念

    • 进程是一个程序的一次执行过程。进程是申请系统资源的基本的单位。
  2. 三个重要特性:

    • 独立性
      • 进程是系统中独立存在的实体,它可以拥有自己独立的资源,比如文件和设备描述符等。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。
    • 动态性
      • 进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。
    • 并发性
      • 若干个进程可以在单处理机状态上并发执行
  3. 进程的结构

    • 进程运行的环境称为进程上下文(context)。

    • Linux中进程的上下文由进程控制块PCB(process control block)、代码段(text segment)、数据段(data segment)以及用户堆栈(stack)组成。

      • 代码段存放该进程的可执行代码;
      • 数据段存放进程中静态产生的数据结构;
      • PCB包括进程的编号、状态、优先级以及正文段和数据段中数据分布的大概情况。
  4. 进程状态

    • 就绪(ready)态
    • 阻塞(blocked)态
    • 运行(runing)态

进程的管理

  1. 进程调度
    • 函数schedule()用来实现进程的调度。它的任务是从运行队列中找到一个进程,并随后将CPU分配给这个进程。schedule()是一个怪异的函数,它与一般C语言函数不同,因为它的调用和返回不在同一个进程中。
  2. 进程创建
    • fork()创建一个新的进程,继承父进程的现有资源,初始化进程时钟、信号、时间等数据。完成子进程初始化后,父进程将它挂到就绪队列,返回子进程的PID。
    • 进程创建时的状态为UNINTERRUPTIBLE,在fork()结束前被父进程唤醒后,变为RUNNING。
    • 处于RUNNING状态的进程被移到就绪队列中,在适当时候由schedule()按处理机调度算法选中,获得处理机。
  3. 进程的休眠和结束
    • 休眠:获得处理机而正在运行的进程若申请不到某个资源,则调用sleep()进行休眠,其PCB挂到相应的等待队列,状态变为UNINTERRUPTIBLE或者 INTERRUPTIBLE。
    • 结束:进程执行系统调用exit()或收到外部的杀死进程信号SIG_KILL时,进程状态变为ZOMBIE,释放所申请资源。同时启动schedule()把处理机分配给就绪队列中其他进程。

进程通讯

  1. 常见的进程间通信方法
    • 管道机制
    • 先进先出(FIFO)机制
    • IPC机制。

线程概念及分类

  1. 线程的基本概念
    • 线程是包含在进程中的一种实体.

    • 它有自己的运行线索,可以完成一定的任务,可与其他线程共享进程中的共享变量及部分环境、相互之间协同来完成进程所要完成的任务。
      方法来模拟多维数组?

    • 我们希望模拟多维数组,但并不知道有多少行,因此我们只能用另一个指针模拟那个(指针的)数组,这样就形成了一个指向指针的指针。

    • 如果一个程序使用了模拟的动态分配多维数组,就可以编写混合函数,混合函数(在编译时)不需要知道“数组”的大小。一个函数就可以对多种大小的“数组”进行操作

      func(int **array, int nrows, int ncolumns){}
      
    • 例如

      [外链图片转存中…(img-NATUktaS-1562652366045)]

    • 要释放这种动态分配的多维数组,需要对分配的每个大块的内存予以释放

      [外链图片转存中…(img-xnbOgUf5-1562652366045)]

第九章 进程/线程编程

进程

  1. 进程概念

    • 进程是一个程序的一次执行过程。进程是申请系统资源的基本的单位。
  2. 三个重要特性:

    • 独立性
      • 进程是系统中独立存在的实体,它可以拥有自己独立的资源,比如文件和设备描述符等。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。
    • 动态性
      • 进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。
    • 并发性
      • 若干个进程可以在单处理机状态上并发执行
  3. 进程的结构

    • 进程运行的环境称为进程上下文(context)。

    • Linux中进程的上下文由进程控制块PCB(process control block)、代码段(text segment)、数据段(data segment)以及用户堆栈(stack)组成。

      • 代码段存放该进程的可执行代码;
      • 数据段存放进程中静态产生的数据结构;
      • PCB包括进程的编号、状态、优先级以及正文段和数据段中数据分布的大概情况。
  4. 进程状态

    • 就绪(ready)态
    • 阻塞(blocked)态
    • 运行(runing)态

进程的管理

  1. 进程调度
    • 函数schedule()用来实现进程的调度。它的任务是从运行队列中找到一个进程,并随后将CPU分配给这个进程。schedule()是一个怪异的函数,它与一般C语言函数不同,因为它的调用和返回不在同一个进程中。
  2. 进程创建
    • fork()创建一个新的进程,继承父进程的现有资源,初始化进程时钟、信号、时间等数据。完成子进程初始化后,父进程将它挂到就绪队列,返回子进程的PID。
    • 进程创建时的状态为UNINTERRUPTIBLE,在fork()结束前被父进程唤醒后,变为RUNNING。
    • 处于RUNNING状态的进程被移到就绪队列中,在适当时候由schedule()按处理机调度算法选中,获得处理机。
  3. 进程的休眠和结束
    • 休眠:获得处理机而正在运行的进程若申请不到某个资源,则调用sleep()进行休眠,其PCB挂到相应的等待队列,状态变为UNINTERRUPTIBLE或者 INTERRUPTIBLE。
    • 结束:进程执行系统调用exit()或收到外部的杀死进程信号SIG_KILL时,进程状态变为ZOMBIE,释放所申请资源。同时启动schedule()把处理机分配给就绪队列中其他进程。

进程通讯

  1. 常见的进程间通信方法
    • 管道机制
    • 先进先出(FIFO)机制
    • IPC机制。

线程概念及分类

  1. 线程的基本概念
    • 线程是包含在进程中的一种实体.
    • 它有自己的运行线索,可以完成一定的任务,可与其他线程共享进程中的共享变量及部分环境、相互之间协同来完成进程所要完成的任务。
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值