• C标准库学习


    前言

    C标准库源码可通过下列两个网站进行查看:The GNU C LibraryWelcome to uClibc-ng! - Embedded C library

    以下学习记录也是以这两个网站提供的库函数源码进行学习的。

    字符串相关

    strcpy()函数

    头文件:#include <string.h>

    函数原型:char *strcpy(char *dest, const char *src);

    函数描述:将src指向的字符串拷贝到dest,包括结束符''。字符串不能重叠,并且dest有足够的空间接收拷贝的字符串。

    返回值:返回指向dest存放字符串的指针。

    函数原型:

    char *strcpy(char *dest, const char *src)
    {
    	char *dst = dest;
    
    	while ((*dst = *src) != '') {
    		src++;
    		dst++;
    	}
    
    	return dest;
    }
    

    可以看出,函数中并不会检查dest的空间大小,只会拷贝字符串直到遇到src字符串的结束符'',因此dest的空间大小需要用户保证。

    测试用例一:dest空间大于src指向的字符串个数。

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char *str_original = "0123456789";
        char buf_dest[12] = {0};
        char *ret = NULL;
        int i = 0;
    
        for (i = 0; i < sizeof(buf_dest); i++)
            buf_dest[i] = 1;
    
        printf("dest:0x%x
    ", buf_dest);
        ret = strcpy(buf_dest, str_original);
        printf(" ret:0x%x
    ", ret);
        for (i = 0; i < sizeof(buf_dest); i++)
            printf("%d ", buf_dest[i]);
        printf("
    ");
    
        return 0;
    }
    

    编译,运行结果:

    $ ./a.out 
    dest:0xca8e26c0
     ret:0xca8e26c0
    48 49 50 51 52 53 54 55 56 57 0 1 
    

    可以看出,字符串拷贝的时候会拷贝字符串结束符''。

    测试用例二:dest空间小于src指向的字符串个数(错误用法)。

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char *str_original = "0123456789";
        char buf_dest[5] = {0};
        char *ret = NULL;
        int i = 0;
    
        for (i = 0; i < sizeof(buf_dest); i++)
            buf_dest[i] = 1;
    
        printf("dest:0x%x
    ", buf_dest);
        ret = strcpy(buf_dest, str_original);
        printf(" ret:0x%x
    ", ret);
        printf("%s
    ", buf_dest);
    
        return 0;
    }
    

    编译,运行:

    $ ./a.out 
    dest:0xe31dee10
     ret:0xe31dee10
    01234567
    

    由于dest没有以''结尾,因此printf打印的信息是错误的,访问的内容已经超过了dest的空间。

    测试用例三:内存重叠

    参考博客:strcpy函数的实现 - Norcy - 博客园 (cnblogs.com)

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char str[12] = "hello";
        strcpy(str + 1, str);  //存在段错误
        printf("%s
    ", str);
    
        return 0;
    }
    
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char str[12] = "hello";
    
        strcpy(str, str+1);
        printf("%s
    ", str);   //打印输出ello
    
        return 0;
    }
    

    第一种情况:strcpy(str + 1, str),这种情况下dest指向'e',而src第一个字符为'h',当拷贝的时候,''结束符会被覆盖掉,导致一直拷贝,陷入死循环。

    第二种情况:strcpy(str, str+1),这种情况下,仅拷贝"ello"。

    strncpy()函数

    头文件:#include <string.h>

    函数原型:char *strncpy(char *dest, const char *src, size_t n);

    函数描述:功能和strcpy函数类似,但仅拷贝src的n字节给dest。另外如果n字节中没有结束符'',那么拷贝完后,dest中是不会有结束符的,这个需要注意。如果src的长度小于n字节,将会在拷贝src字符串之后继续拷贝结束符给dest,直到满足n字节。

    函数原型:

    char *strncpy (char *s1, const char *s2, size_t n)
    {
        reg_char c;
        char *s = s1;
    
        --s1;
    
        if (n >= 4) 
        {
            size_t n4 = n >> 2;
            for ( ; ; )
            {
                c = *s2++;
                *++s1 = c;
                if (c == '')
                    break;
                c = *s2++;
                *++s1 = c;
                if (c == '')
                    break;
                c = *s2++;
                *++s1 = c;
                if (c == '')
                    break;
                c = *s2++;
                *++s1 = c;
                if (c == '')
                    break;
                if (--n4 == 0)
                    goto last_chars;
            }
            n = n - (s1 - s) - 1;
            if (n == 0)
                return s;
            goto zero_fill;
        }
    
    last_chars:
        n &= 3;
        if (n == 0)
            return s;
    
        do
        {
            c = *s2++;
            *++s1 = c;
            if (--n == 0)
                return s;
        } while (c != '');
    
    zero_fill:
        do
            *++s1 = '';
        while (--n > 0);
    
        return s;
    }
    

    测试用例一:src字符串长度大于n,且前n个字符中存在结束符,则只会拷贝到第一个结束符时就结束拷贝。

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char str_original[] = {'a', '', 'b', '', 'c', 'd', 'e', ''};
        char str_dest[8] = {0};
        int i = 0;
    
        strncpy(str_dest, str_original, 8);
        for (i = 0; i < 12; i++)
            printf("%d ", str_dest[i]);
        printf("
    ");
    
        return 0;
    }
    

    编译,运行:

    $ ./a.out    
    97 0 0 0 0 0 0 0 
    

    测试用例二:src字符串长度大于n,且前n个字符中不存在结束符,则会拷贝n个字符。处理这种情况,一般需要自己去在dest末尾添加一个结束符。

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char str_original[] = {'a', 'b', 'c', 'd', 'e', 'f', ''};
        char str_dest[5] = {0};
        int i = 0;
    
        strncpy(str_dest, str_original, 5);
        for (i = 0; i < 5; i++)
            printf("%d ", str_dest[i]);
        printf("
    ");
    
        return 0;
    }
    

    编译,运行:

    $ ./a.out 
    97 98 99 100 101 
    

    测试用例三:src字符串长度小于n,将会在拷贝src字符串之后继续拷贝结束符给dest,直到满足n字节。

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char str_original[] = {'a', 'b', 'c', 'd', 'e', 'f', ''};
        char str_dest[12] = {0};
        int i = 0;
    
        for (i = 0; i < 12; i++)
            str_dest[i] = 1;
    
        strncpy(str_dest, str_original, 12);
        for (i = 0; i < 12; i++)
            printf("%d ", str_dest[i]);
        printf("
    ");
    
        return 0;
    }
    

    编译,运行:

    $ ./a.out    
    97 98 99 100 101 102 0 0 0 0 0 0 
    
  • 相关阅读:
    你的代码又导致资金损失了?活该!
    rabbitmq实现指定消费者才能消费
    没有绝对,没有百分百
    jenkins构建触发器之Build whenever a snapshot dependency is built
    豁然明白的囧事 之 执行mvn:clean deploy提示401 Unauthorized
    (8/8)RPC方法的参数,能用枚举就请考虑枚举
    abstract 关键字
    练习题------代码块
    代码块
    static 关键字
  • 原文地址:https://www.cnblogs.com/mrlayfolk/p/15054745.html
Copyright © 2020-2023  润新知