• 第5章 C语言高级的库函数


    文档配套视频讲解链接地址

    1. 腾讯课堂视频链接地址 : 21_库函数_assert与math库
    2. 腾讯课堂视频链接地址 : 22_库函数_stdlib库
    3. 腾讯课堂视频链接地址 : 23_库函数_string库1
    4. 腾讯课堂视频链接地址 : 24_库函数_string库2
    5. 腾讯课堂视频链接地址 : 25_库函数_time库
    6. 腾讯课堂视频链接地址 : 26_库函数_qsort排序
    7. 腾讯课堂视频链接地址 : 27_库函数_内存申请与释放

    第05章 C库函数

    5.1 assert.h 断言

    • C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息。

    assert 宏的定义如下:

    #define assert(ignore) ((void)0)
    
    //函数原型:
    void assert(int expression)
    //这实际上是一个宏,不是一个函数,可用于在 C 程序中添加诊断。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 例如 ,代码参考
    /**
      * @brief  Reads the specified output data port bit.
      * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
      * @param  GPIO_Pin:  specifies the port bit to read.
      *   This parameter can be GPIO_Pin_x where x can be (0..15).
      * @retval The output port pin value.
      */
    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      uint8_t bitstatus = 0x00;
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));   // 检查参数
      assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); 
      
      if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET)
      {
        bitstatus = (uint8_t)Bit_SET;
      }
      else
      {
        bitstatus = (uint8_t)Bit_RESET;
      }
      return bitstatus;
    }
    
    // 函数定义如下:
    #define assert_param(expr) ((void)0)   // 宏函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    5.2 ctype.h 测试和映射字符

    • C 标准库的 ctype.h 头文件提供了一些函数,可用于测试和映射字符。

    • 这些函数接受 int 作为参数,它的值必须是 EOF 或表示为一个无符号字符。

    • 如果参数 c 满足描述的条件,则这些函数返回非零(true)。如果参数 c 不满足描述的条件,则这些函数返回零。

    int isalnum(int c) ;  // 该函数检查所传的字符是否是字母和数字。
    int isalpha(int c) ;  // 该函数检查所传的字符是否是字母。
    int iscntrl(int c) ;  // 该函数检查所传的字符是否是控制字符。
    int isdigit(int c) ;  // 该函数检查所传的字符是否是十进制数字。
    int isgraph(int c) ;  // 该函数检查所传的字符是否有图形表示法。
    int islower(int c) ;  // 该函数检查所传的字符是否是小写字母。
    int isprint(int c) ;  // 该函数检查所传的字符是否是可打印的。
    int ispunct(int c) ;  // 该函数检查所传的字符是否是标点符号字符。
    int isspace(int c) ;  // 该函数检查所传的字符是否是空白字符。
    int isupper(int c) ;  // 该函数检查所传的字符是否是大写字母。
    int isxdigit(int c);  // 该函数检查所传的字符是否是十六进制数字。
    
    /*
    标准的空白字符包括:
    ' '     (0x20)    space (SPC) 空格符
    '\t'    (0x09)    horizontal tab (TAB) 水平制表符    
    '\n'    (0x0a)    newline (LF) 换行符
    '\v'    (0x0b)    vertical tab (VT) 垂直制表符
    '\f'    (0x0c)    feed (FF) 换页符
    '\r'    (0x0d)    carriage return (CR) 回车符
    */
    
    
    /*
    字符类
    1	数字
    完整的数字集合 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
    2	十六进制数字
    集合 { 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f }
    3	小写字母
    集合 { a b c d e f g h i j k l m n o p q r s t u v w x y z }
    4	大写字母
    集合 {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z }
    5	字母
    小写字母和大写字母的集合
    6	字母和数字的字符
    数字、小写字母和大写字母的集合
    7	标点符号字符
    集合 ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
    8	图形字符
    字母数字字符和标点符号字符的集合
    9	空格字符
    制表符、换行符、垂直制表符、换页符、回车符、空格符的集合。
    10	可打印字符
    字母数字字符、标点符号字符和空格字符的集合。
    11	控制字符
    在 ASCII 编码中,这些字符的八进制代码是从 000 到 037,以及 177(DEL)。
    12	空白字符
    包括空格符和制表符。
    13	字母字符
    小写字母和大写字母的集合。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    5.3 math.h 数学库

    • 编译时带入参数: -lm
    double acos(double x)   // 返回以弧度表示的 x 的反余弦。
    double asin(double x)   // 返回以弧度表示的 x 的反正弦。
    double atan(double x)   // 返回以弧度表示的 x 的反正切。
    double atan2(double y, double x) // 返回以弧度表示的 y/x 的反正切。y 和 x 的值的符号决定了正确的象限。
    double cos(double x)    // 返回弧度角 x 的余弦。
    double cosh(double x)   // 返回 x 的双曲余弦。
    double sin(double x)    // 返回弧度角 x 的正弦。
    double sinh(double x)   // 返回 x 的双曲正弦。
    double tanh(double x)   // 返回 x 的双曲正切。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • exp() 次幂
    double exp(double x)
    功能: 计算e 的 x 次幂的值。
    参数: x 表示多少次幂
    返回值:  该函数返回 e 的 x 次幂。
    
    • 1
    • 2
    • 3
    • 4
    • pow() 次幂
    double pow(double x, double y)
    功能: 返回 x 的 y 次幂,即 x^y。
    参数: 
    x -- 代表基数的浮点值。
    y -- 代表指数的浮点值。
    返回值:  该函数返回 x 的 y 次幂的结果。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • sqrt 开平方函数
    double sqrt(double x)
    功能: 返回 x 的平方根。
    参数:  x -- 要计算平方根的值 
    返回值:  返回 x 的平方根
    
    • 1
    • 2
    • 3
    • 4
    • ceil() 向上取最小整数
    ceil() 向上取最小整数 
    double ceil(double x)
    功能: 返回 大于或等于 x 的最小的整数值。
    参数: x -- 要操作的数
    返回值:  该函数返回不小于 x 的最小整数值。
    // 例如: x= 11.5 , 向上取最小整数是 12 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • floor() 向下取最大整数
    double floor(double x)
    功能: 返回小于或等于 x 的最大的整数值。
    参数: 
    x -- 要操作的数
    返回值: 
    返回小于或等于 x 的最大的整数值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 实例39
    • 从终端输入一个小数 , 计算这个小数的最小整数和最大整数
    • 注意事项, 因为math.h 是第三方库, 不属于C的标准库, 在编译器需要 带上参数: -lm
    • 源文件
    03-chigh/39-ceil-floor.c
    
    • 1
    • 源代码
    #include  
    #include  
    
    int main(int argc, char const *argv[])
    {
        double a; 
        printf("请输入一个小数 >:");
        scanf("%lf",&a);
        printf("最大整数=%lf\n",ceil(a)); 
        printf("最小整数=%lf\n",floor(a)); 
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 运行结果
    linux@ubuntu:~/work/emb2207/03-chigh$ gcc 39-ceil-floor.c -lm -o 39-ceil-floor
    linux@ubuntu:~/work/emb2207/03-chigh$ ./39-ceil-floor 
    请输入一个小数 >:6.9
    最大整数=7.000000
    最小整数=6.000000
    linux@ubuntu:~/work/emb2207/03-chigh$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • fabs() 绝对值
    double fabs(double x)
    功能:  返回 x 的绝对值。
    参数: 
    x -- 要操作的数
    返回值: 
    返回 x 的绝对值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 实例40
    • 从终端输入一个数,计算这个数的绝对值
    • 源文件
    03-chigh/40-fabs.c
    
    • 1
    • 源代码
    #include  
    #include  
    
    int main(int argc, char const *argv[])
    {
        double a; 
        printf("请输入一个负数 >:");
        scanf("%lf",&a);
        printf("绝对值=%lf\n",fabs(a)); 
        
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 运行结果
    linux@ubuntu:~/work/emb2207/03-chigh$ gcc 40-fabs.c -lm 
    linux@ubuntu:~/work/emb2207/03-chigh$ ./a.out 
    请输入一个负数 >:-19
    绝对值=19.000000
    linux@ubuntu:~/work/emb2207/03-chigh$ ./a.out 
    请输入一个负数 >:80
    绝对值=80.000000
    linux@ubuntu:~/work/emb2207/03-chigh$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 特殊的宏
    #define NULL ((char *)0)#define NULL 0L       // 0 long #define NULL 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.4 stdlib.h 标准库

    • stdlib .h 头文件定义了四个变量类型、一些宏和各种通用工具函数。
    1. 字符串转整数、浮点数
    atof() 字符串转浮点型
    double atof(const char *str)
    功能: 把参数 str 所指向的字符串转换为一个浮点数(类型为 double 型)。
    参数: 
    str -- 要转换的字符串
    返回值: 
    函数返回转换后的双精度浮点数,如果没有执行有效的转换,则返回零(0.0)。
    
    atoi() 字符串转整型 
    int atoi(const char *str)
    功能: 把参数 str 所指向的字符串转换为长整型(类型为 int 型)。
    参数: 
    str -- 要转换的字符串
    返回值: 
    函数返回转换后的整型数,如果没有执行有效的转换,则返回零(0)。
        
    atol() 字符串转长整型 
    long int atol(const char *str)
    功能: 把参数 str 所指向的字符串转换为长整型(类型为 long 型)。
    参数: 
    str -- 要转换的字符串
    返回值: 
    函数返回转换后的长整型数,如果没有执行有效的转换,则返回零(0)。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    2. strtod 把字符串中的数字转换成浮点数并返回数字的下一个字符的位置
    strtod()    // string to  double
    double strtod(const char *str, char **endptr)
    功能: 把参数 str 所指向的字符串转换为一个浮点数(类型为 double 型)
    参数
    str -- 要转换为双精度浮点数的字符串。
    endptr -- 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
    返回值
    该函数返回转换后的双精度浮点数,如果没有执行有效的转换,则返回零(0.0)。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 例如
    int main()
    {
        char str[30] = "20.30300This is test";
        char *ptr;
        double ret;
    
        ret = strtod(str, &ptr);
        printf("数字(double)是:%lf\n", ret);
        printf("字符串部分是:%s\n", ptr);
    
        return (0);
    }
    // 运行结果:
    数字(double)是:20.303000
    字符串部分是:This is test
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    3. strtol 字符串转整数
    strtol()   // string to long 
    long int strtol(const char *str, char **endptr, int base)
    功能: 把参数 str 所指向的字符串根据给定的 base 转换为一个长整数(类型为 long int 型),base 必须介于 236(包含)之间,或者是特殊值 0。
    参数
    str -- 要转换为长整数的字符串。
    endptr -- 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
    base -- 基数,必须介于 236(包含)之间,或者是特殊值 0。 表示的是进制 , 可以是 2, 8 , 10 , 16 
    返回值
    该函数返回转换后的长整数,如果没有执行有效的转换,则返回一个零值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 例如
    include <stdio.h>
    #include 
    
    int main()
    {
       char str[30] = "2030300 This is test";
       char *ptr;
       long ret;
    
       ret = strtol(str, &ptr, 10);
       printf("数字(无符号长整数)是 %ld\n", ret);
       printf("字符串部分是 |%s|", ptr);
    
       return(0);
    }  
    
    // 输出结果
    数字(无符号长整数)是 2030300
    字符串部分是 | This is test|
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    4. strtoul 字符串转无符号长整型
    unsigned long int strtoul(const char *str, char **endptr, int base)   
    // string to unsigned long 
    功能:把参数 str 所指向的字符串根据给定的 base 转换为一个无符号长整数(类型为 unsigned long int 型)
    参数:
    str -- 要转换为无符号长整数的字符串。
    endptr -- 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
    base -- 基数,必须介于 236(包含)之间,或者是特殊值 0。表示的是进制 , 可以是 2, 8 , 10 , 16 
    返回值
    该函数返回转换后的长整数,如果没有执行有效的转换,则返回一个零值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    5. exit() 结束程序
    void exit(int status)
    功能: 立即终止调用程序。
    参数
    status -- 返回给父进程的状态值。程序退出时的返回值 
    返回值
    该函数不返回值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 实例41
    • exit结束程序
    • 源文件
    03-chigh/41-exit.c
    
    • 1
    • 源代码
    #include 
    #include 
    
    
    int main(int argc, char const *argv[])
    {
        
        printf("hello world!!\n"); 
        exit(0);  // 程序立即结束
        printf("hello world!!\n"); 
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 运行结果
    hello world!!
    
    • 1
    6. qsort 排序函数
    void qsort(void *base, size_t nmemb, size_t size,int (*compar)(const void *, const void *) );
    //功能: 排序一段内存的数据 
    // 参数: 
    base : 内存的起始地址
    nmemb : 要比较元素的个数
    size  : 每一个元素的大小
    compr : 是一个指针, 函数类型的指针 , 函数类型: int ( )(const void *, const void *)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 实例47
    • 对一段代码进行排序
    • 源文件
    03-chigh/47-qsort.c
    
    • 1
    • 源代码
    #include 
    #include 
    #include 
    
    // 从小到大 排序
    int compare1(const void *arg1, const void *arg2)
    {
        return *(char *)arg1 - *(char *)arg2;
    }
    
    // 从大到小 排序
    int compare2(const void *arg1, const void *arg2)
    {
        return *(char *)arg2 - *(char *)arg1;
    }
    
    int main(int argc, char const *argv[])
    {
        char buf[] = {"U.S. News & World Report is an American media company that publishes news, \
                    consumer advice, rankings, and analysis. It was launched in 1948 as the merger \
                    of domestic-focused weekly newspaper U.S. News and international-focused weekly \
                    magazine World Report. In 1995, the company launched 'usnews.com' and in 2010, \
                    the magazine ceased printing."};
        qsort(buf, strlen(buf), 1, compare1); // 程序运行时, 会传递给arg1 和arg2 参数
        printf("从小到大:buf=%s\n", buf);
        printf("************************************************************\n");
        qsort(buf, strlen(buf), 1, compare2); // 程序运行时, 会传递给arg1 和arg2 参数
        printf("从大到小:buf=%s\n", buf);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 运行结果
    从小到大:buf=                                                                                                                  &'',,,,,--........001112458999AIINNRRSSUUWWaaaaaaaaaaaaaaaaaaaaaaaaabccccccccccccdddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeefffggggghhhhhhhiiiiiiiiiiiiiiiikkklllllllllmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnnnnnnnooooooooooooopppppppprrrrrrrrrrrrsssssssssssssssssssttttttttttttuuuuuuuvwwwwwwwwyyyyyzz
    ************************************************************
        
    从大到小:buf=zzyyyyywwwwwwwwvuuuuuuuttttttttttttsssssssssssssssssssrrrrrrrrrrrrppppppppooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmlllllllllkkkiiiiiiiiiiiiiiiihhhhhhhgggggfffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddccccccccccccbaaaaaaaaaaaaaaaaaaaaaaaaaWWUUSSRRNNIIA999854211100........--,,,,,''&                                                                                                          
    
    • 1
    • 2
    • 3
    • 4

    5.3 string.h

    • 字符串操作的函数
    1. memchr 字符查找函数
    void *memchr(const void *str, int c, size_t n)
    /*
    功能: 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
    参数:
    str -- 指向要执行搜索的内存块的地址。
    c -- 以 int 形式传递的值,但是函数在每次字节搜索时是使用该值的无符号字符形式 要查找的字符
    n -- 要被分析的字节数。需要查找多找个字节 
    返回值
    该函数返回一个指向匹配字节的指针,如果在给定的内存区域未出现字符,则返回 NULL。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 实例42
    • 在内存中搜索制定的字符
    • 源文件
    03-chigh/42-memchr.c
    
    • 1
    • 源代码
    #include 
    #include 
    #include 
    
    int main(int argc, char const *argv[])
    {
        char buf[] = {"U.S. News & World Report is an American media company that publishes news, \
                    consumer advice, rankings, and analysis. It was launched in 1948 as the merger \
                    of domestic-focused weekly newspaper U.S. News and international-focused weekly \
                    magazine World Report. In 1995, the company launched 'usnews.com' and in 2010, \
                    the magazine ceased printing."};
        char ch;
        char *retp = NULL;
        char *startp = buf;// 内存的起始位置
        int count = 0;
        printf("请输入你要找的字符 >:");
        scanf("%c", &ch);
        while (1)
        {
            //  startp 从内存起始位置开始找
            // strlen(buf) , 这样写会有bug产生, 原因是这是一个固定长度的字节数, 实际搜索中, 随着查找的继续
            // 字符串的长度在减少 , 应该用 strlen(startp)计算
            retp = (char *)memchr(startp, ch, strlen(startp)); 
            if (retp != NULL) // 不为NULL 表示找到了字符, 我们计数
            {
                count++; // 累计
                //找到以后, 要更新startp的位置
                startp = retp+1; // 要跳过找到的字符, 找到字符的下一个位置开始继续搜索
                printf("retp =%s\n",retp);
            }
            else if (retp == NULL)
            {
                break;
            }
        }
        printf("%c 有 %d 个字符\n", ch, count);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 运行结果
    linux@ubuntu:~/work/emb2207/03-chigh$ ./42-memchr 
    请输入你要找的字符 >:a
    a 有 25 个字符
    linux@ubuntu:~/work/emb2207/03-chigh$ ./42-memchr 
    请输入你要找的字符 >:s
    s 有 19 个字符
    linux@ubuntu:~/work/emb2207/03-chigh$ ./42-memchr 
    请输入你要找的字符 >:w
    w 有 8 个字符
    linux@ubuntu:~/work/emb2207/03-chigh$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2. memcmp 内存比较函数
    int memcmp(const void *str1, const void *str2, size_t n)
    /*
    功能: 把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
    str1 -- 指向内存块的指针。
    str2 -- 指向内存块的指针。
    n -- 要被比较的字节数。
    返回值
    如果返回值 < 0,则表示 str1 小于 str2。
    如果返回值 > 0,则表示 str1 大于 str2。
    如果返回值 = 0,则表示 str1 等于 str2。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 实例43
    • 在内存中比较一段内存
    • 源文件
    03-chigh/43-memcmp.c
    
    • 1
    • 源代码
    #include 
    #include 
    #include 
    
    int main(int argc, char const *argv[])
    {
        char buf[] = {"U.S. News & World Report is an American media company that publishes news, \
                    consumer advice, rankings, and analysis. It was launched in 1948 as the merger \
                    of domestic-focused weekly newspaper U.S. News and international-focused weekly \
                    magazine World Report. In 1995, the company launched 'usnews.com' and in 2010, \
                    the magazine ceased printing."};
        char ch;
        int ret;
        char *startp = buf; // 内存的起始位置
        int count = 0;
        while (1)
        {
            //  startp 从内存起始位置开始找
            // strlen(buf) , 这样写会有bug产生, 原因是这是一个固定长度的字节数, 实际搜索中, 随着查找的继续
            // 字符串的长度在减少 , 应该用 strlen(startp)计算
            ret = memcmp(startp, "news", strlen("news"));
            if (ret == 0) // 找到单词 news
            {
                count++; // 累计
                //找到以后, 要更新startp的位置
                printf("startp =%s\n", startp);
                startp ++; //找到单词的下一个位置开始继续搜索
            }
            else
            {
                startp++; // 往后移动
            }
    
            // buf[strlen(buf)] 这是数组元素的最后一个位置, 是'\0'
            if (startp == &buf[strlen(buf)])
            {
                break;
            }
        }
        printf("news 有 %d 个单词\n", count);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 运行结果
    news 有 3 个单词
    
    • 1
    3. memcpy 内存复制
    void *memcpy(void *str1, const void *str2, size_t n)
    功能:从存储区 str2 复制 n 个字节到存储区 str1。
    参数
    str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
    str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
    n -- 要被复制的字节数。
    返回值
    该函数返回一个指向目标存储区 str1 的指针。    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    4. memmove 内存复制
    void *memmove(void *str1, const void *str2, size_t n) 
    功能: 从 str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
        
    void *memmove(void *str1, const void *str2, size_t n)
    参数
    str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
    str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
    n -- 要被复制的字节数。
    返回值
    该函数返回一个指向目标存储区 str1 的指针。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    5. memset() 内存置位
    把一段内存写入特定的值 
    C 库函数 void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
    void *memset(void *str, int c, size_t n)
    参数
    str -- 指向要填充的内存块。
    c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
    n -- 要被设置为该值的字符数。
    返回值
    该值返回一个指向存储区 str 的指针。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 实例44
    • 把结构体或内存置位
    • 源文件
    03-chigh/44-memset.c
    
    • 1
    • 源代码
    #include 
    #include 
    
    typedef struct student
    {
        int number;
        char name[20];
        char sex[10];
        int age;
        float score;
    } student_t;
    
    int main(int argc, char const *argv[])
    {
        student_t stu1;
        int buf[10];
        memset(&stu1, 0, sizeof(student_t)); // 把结构体所占用的内存全部置位0
        printf("stu1 信息:\n");
        printf("stu1.number  : %d\n", stu1.number);
        printf("stu1.name    : %s\n", stu1.name);
        printf("stu1.sex     : %s\n", stu1.sex);
        printf("stu1.age     : %d\n", stu1.age);
        printf("stu1.score   : %f\n", stu1.score);
    
        for (int i = 0; i < 10; i++)
        {
            printf("buf[%d]=%d\n", i, buf[i]);
        }
    
        memset(buf, 0, sizeof(buf));
        for (int i = 0; i < 10; i++)
        {
            printf("buf[%d]=%d\n", i, buf[i]);
        }
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 运行结果
    stu1 信息:
    stu1.number  : 0
    stu1.name    : 
    stu1.sex     : 
    stu1.age     : 0
    stu1.score   : 0.000000
    buf[0]=0
    buf[1]=0
    buf[2]=0
    buf[3]=0
    buf[4]=9
    buf[5]=0
    buf[6]=802829920
    buf[7]=32534
    buf[8]=1642418328
    buf[9]=32764
    buf[0]=0
    buf[1]=0
    buf[2]=0
    buf[3]=0
    buf[4]=0
    buf[5]=0
    buf[6]=0
    buf[7]=0
    buf[8]=0
    buf[9]=0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    6. strchr 字符查找
    C 库函数 char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
    char *strchr(const char *str, int c)
    参数:
    str -- 要被检索的 C 字符串。
    c -- 在 str 中要搜索的字符。
    返回值
    该函数返回在字符串 str 中第一次出现字符 c 的位置,如果未找到该字符则返回 NULL
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    7. strstr 字符串查找
    C 库函数 char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
    
    char *strstr(const char *haystack, const char *needle)
    参数
    haystack -- 要被检索的 C 字符串。
    needle -- 在 haystack 字符串内要搜索的小字符串。
    返回值
    该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 实例45
    • 源文件
    03-chigh/45-strstr.c
    
    • 1
    • 源代码
    #include 
    #include 
    #include 
    
    int main(int argc, char const *argv[])
    {
        char buf[] = {"U.S. News & World Report is an American media company that publishes news, \
                    consumer advice, rankings, and analysis. It was launched in 1948 as the merger \
                    of domestic-focused weekly newspaper U.S. News and international-focused weekly \
                    magazine World Report. In 1995, the company launched 'usnews.com' and in 2010, \
                    the magazine ceased printing."};
        char ch;
        char *retp;
        char *startp = buf; // 内存的起始位置
        int count = 0;
        while (1)
        {
            //  startp 从内存起始位置开始找
            // strlen(buf) , 这样写会有bug产生, 原因是这是一个固定长度的字节数, 实际搜索中, 随着查找的继续
            // 字符串的长度在减少 , 应该用 strlen(startp)计算
            retp = strstr(startp, "news");
            if (retp != NULL) // 找到单词 返回单词的位置
            {
                count++; // 累计
                //找到以后, 要更新startp的位置
                printf("startp =%s\n", retp);
                startp = retp  + 1 ; //找到单词的下一个位置开始继续搜索
            }
            else 
            {
                startp++; // 往后移动
            }
    
            // buf[strlen(buf)] 这是数组元素的最后一个位置, 是'\0'
            if (startp == &buf[strlen(buf)])
            {
                break;
            }
        }
        printf("news 有 %d 个单词\n", count);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 完成实例43的功能
    startp =news,                 consumer advice, rankings, and analysis. It was launched in 1948 as the merger                 of domestic-focused weekly newspaper U.S. News and international-focused weekly                 magazine World Report. In 1995, the company launched 'usnews.com' and in 2010,                 the magazine ceased printing.
    startp =newspaper U.S. News and international-focused weekly                 magazine World Report. In 1995, the company launched 'usnews.com' and in 2010,                 the magazine ceased printing.
    startp =news.com' and in 2010,                 the magazine ceased printing.
    news 有 3 个单词
    
    • 1
    • 2
    • 3
    • 4
    8. 其他函数
    //把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
    char *strcat(char *dest, const char *src) 
           
    //把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。    
    char *strncat(char *dest, const char *src, size_t n) 
      
    //把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
    int strcmp(const char *str1, const char *str2) 
        
    //把 str1 和 str2 进行比较,最多比较前 n 个字节。   
    int strncmp(const char *str1, const char *str2, size_t n)
    
    //把 src 所指向的字符串复制到 dest。    
    char *strcpy(char *dest, const char *src)
    
    //把 src 所指向的字符串复制到 dest,最多复制 n 个字符。
    char *strncpy(char *dest, const char *src, size_t n)
    
    //检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。
    size_t strcspn(const char *str1, const char *str2)
    
    //计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。    
    size_t strlen(const char *str)
    
    //检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,则停止检验,并返回该字符位置。
    char *strpbrk(const char *str1, const char *str2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    5.5 time.h 时间库

    char *asctime(const struct tm *timeptr) // 返回一个指向字符串的指针,它代表了结构 timeptr 的日期和时间。
          
    clock_t clock(void)   // 返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。
    
    char *ctime(const time_t *timer)  // 返回一个表示当地时间的字符串,当地时间是基于参数 timer。
    
    double difftime(time_t time1, time_t time2) // 返回 time1 和 time2 之间相差的秒数 (time1-time2)。
    
    //timer 的值被分解为 tm 结构,并用协调世界时(UTC)也被称为格林尼治标准时间(GMT)表示。
    struct tm *gmtime(const time_t *timer)
    
     //timer 的值被分解为 tm 结构,并用本地时区表示。
    struct tm *localtime(const time_t *timer)
    
    //把 timeptr 所指向的结构转换为一个依据本地时区的 time_t 值。
    time_t mktime(struct tm *timeptr)
    
    //根据 format 中定义的格式化规则,格式化结构 timeptr 表示的时间,并把它存储在 str 中。
    size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)
    
    // 计算当前日历时间,并把它编码成 time_t 格式。    
    time_t time(time_t *timer)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. time 获取系统的时间
    time_t time(time_t *tloc)
    功能:  获取系统时间的秒数 
    参数: 
    tloc : 这个参数可以传参也可以不传参, 如果不传递参数, 设置位NULL即可
         : 如果要传递参数, 用来保存时间的秒数。
    返回值: 
    	成功返回: 纪年时间的秒数 
        失败返回: -1  
    typedef __time_t time_t;       
    #define __SLONGWORD_TYPE	long int
    
    time_t 就是long int 类型的 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2. tm结构体定义
    /* ISO C `broken-down time' structure.  */
    struct tm
    {
      int tm_sec;			/* Seconds.	[0-60] (1 leap second) */  //  0-59 
      int tm_min;			/* Minutes.	[0-59] */  
      int tm_hour;			/* Hours.	[0-23] */
      int tm_mday;			/* Day.		[1-31] */  // 一个月中的哪一日 
      int tm_mon;			/* Month.	[0-11] */  // 月份在计算中要手动加1 
      int tm_year;			/* Year	- 1900.  */    // 在计算中, 要考虑这个因素
      int tm_wday;			/* Day of week.	[0-6] */ // 星期几
      int tm_yday;			/* Days in year.[0-365]	*/ // 一年的第多少天 
      int tm_isdst;			/* DST.		[-1/0/1]*/
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    3. localtime 解析秒数
    struct tm *localtime(const time_t *timer)
    功能: timer 的值被分解为 tm 结构,并用本地时区表示。
    参数: 
    timer :时间的秒数 
    返回值: 
    	成功: 返回tm 结构体首地址, 并把结构体信息填充
        失败: NULL      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 实例46
    • 源文件
    03-chigh/46-time.c
    
    • 1
    • 源代码
    #include 
    #include 
    #include 
    
    char *week[]={"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
    int main(int argc, char const *argv[])
    {
        // long int seconds ;
        time_t seconds = time(NULL); // 或许系统时间的秒数
        printf("seconds=%ld\n", seconds);
        printf("time:%s", ctime(&seconds)); // 直接获取时间字符串, 西方的时间表示法 
    
        // localtime 的功能是把seconds 这个变量解析成一个结构体 struct tm 
        struct tm * tmp =  localtime(&seconds); // 
        printf("%04d-%02d-%02d %02d:%02d:%02d %s\n",tmp->tm_year+1900,tmp->tm_mon+1,tmp->tm_mday,
                                                tmp->tm_hour,tmp->tm_min,tmp->tm_sec,week[tmp->tm_wday-1]);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 运行结果
    seconds=1664175330
    time:Mon Sep 26 14:55:30 2022
    2022-09-26 14:55:30 星期一
    
    • 1
    • 2
    • 3

    5.6 stdlib.h 申请内存

    1. 程序的概念
    • 程序由指令和数据组成, 也就是分为指令段和数据段
    • 用C语言去理解什么是指令什么是数据
    char *week[]={"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};  // 数据 
    int main(int argc, char const *argv[])  // 指令部分 
    {
        // long int seconds ;
        time_t seconds = time(NULL); // 或许系统时间的秒数    // 指令
        printf("seconds=%ld\n", seconds);         // 指令
        printf("time:%s", ctime(&seconds)); // 直接获取时间字符串, 西方的时间表示法  // 指令
    
        // localtime 的功能是把seconds 这个变量解析成一个结构体 struct tm 
        struct tm * tmp =  localtime(&seconds); //  指令
        printf("%04d-%02d-%02d %02d:%02d:%02d %s\n",tmp->tm_year+1900,tmp->tm_mon+1,tmp->tm_mday,
                                                tmp->tm_hour,tmp->tm_min,tmp->tm_sec,week[tmp->tm_wday-1]); // 指令
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 数据有分为: 可读可写的数据, 只读数据
    // 全局变量在编译时,会放到数据段内 
    // static 修饰的局部变量, 也会放到数据段内
    // const 修饰的变量, 是只读的 
    // 字符串也是只读常量
    
    • 1
    • 2
    • 3
    • 4
    • 例如
    // 可以使用命令 readelf 来去读程序的信息
    linux@ubuntu:~/work/emb2207/03-chigh$ size 47-qsort
       
       text    data     bss     dec     hex filename
       2744     632       8    3384     d38 47-qsort
    // text 就是代码段 
    // data 就是数据段 
    // bss  清零数据段, 全都是的数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    2. 进程的概念
    • 程序执行的一个过程就是进程

    • 进程运行起来后, 程序的指令段, 变成进程的代码区

    • 数据段变成静态区

    • 进程会新建2个区, 堆区和栈区

    • 堆是让用户动态申请内存的, 栈区是用来保存函数内的局部变量

    image-20220926161611231

    3. 在堆区申请内存 malloc/free
    • malloc 申请内存
    void *malloc(size_t size);
    // 功能: 在堆区申请指定大小的内存
    // 参数: 
    //  size : 要申请内存字节的大小
    // 返回值:
    //	成功: 返回一个申请到内存的起始地址   
    //  失败: NULL 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 实例48
    • 源文件
    03-chigh/48-malloc.c
    
    • 1
    • 源代码
    #include 
    #include 
    #include 
    
    
    
    int main(int argc, char const *argv[])
    {
        char * p  ; 
        p = malloc(128) ; 
        if(p == NULL) // 申请内存失败
        {
            printf("内存申请失败\n"); 
            exit(-1); 
        }
        memset(p,0,128); 
        memset(p,'A',127);
        printf("1:p=%s\n",p);
        free(p); // 释放已经申请的内存
        printf("2:p=%s\n",p);
        // while(1)
        // {
        //     malloc(1024);
        // }
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 运行结果
    1:p=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    2:p=
    
    • 1
    • 2
  • 相关阅读:
    网络工程师的网络安全之路:应对威胁与保障数据
    抓包工具fiddler
    2022中国电子展,国产超高清技术掀起新兴浪潮
    非母语玩家如何撰写研究性英文论文:0. 前言
    关于进程、线程、协程的概念以及Java中的应用
    使用 Meltano 将数据从 Snowflake 导入到 Elasticsearch:开发者之旅
    机器学习:集成学习(Python)
    Linux 安装Nginx详细图解教程
    推荐算法中CTR和CVR的ESMM模型pytorch实现
    钉钉、企微、飞书学会赚钱了吗?
  • 原文地址:https://blog.csdn.net/shengli001842/article/details/127835484