• 字符(串)及内存操作库函数


    前言

    C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数。

    一.字符串函数

    1.strlen

    1.1分析

    功能:求字符串长度

    参数:str——所求字符串的地址

    size_t strlen(const char* str)
    
    • 1

    返回值:字符串的长度

    注意事项:

    1.字符串已经 '\0’作为结束标志,strlen函数返回的是在字符串中 '\0’前面出现的字符个数(不包含 ‘\0’)

    2.参数指向的字符串必须要以 '\0’结束

    3.注意函数的返回值为size_t,是无符号(unsigned int)的( 易错 )

    例如:image-20220720104629262

    注:strlen(str2) - strlen(str1)恒大于0,因为strlen返回值是无符号整形

    1.2模拟实现strlen

    #include
    #include
    //循环(计数器方式)
    size_t my_strlen1(const char* str)
    {
        assert(str);
        int count = 0;
        while(*str!='\0')
        {
            str++;
            count++;
        }
        return count;
    }
    //指针-指针
    size_t my_strlen2(const char* str)
    {
        assert(str);
        char* left = str;
        while(*str)
        {
            str++;
        }
        char* right = str;
        return left - right;
    }
    //递归(不能创建临时变量)
    size_t my_strlen3(const char* str)
    {
        assert(str);
        if(*str=='\0')
      		return 0;
        else
            return 1 + my_strlen3(str + 1);
    }
    int main()
    {
        char arr[] = "abcdef";
        size_t len = my_strlen1(arr);
        printf("%u\n",len);
        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

    2.strcpy

    2.1分析

    功能:字符串拷贝

    参数:

    dest(destination)——目标字符数组的地址

    src(source)——源字符串的的地址

    size_t strcpy(char* dest, const char* src)
    
    • 1

    返回值:目标字符数组(目标空间)的地址(dest)

    注意事项:

    1.源字符串必须以 '\0’结束

    2.会将源字符串中的 '\0’拷贝到目标空间(如下图)

    3.目标空间必须足够大,以确保能存放源字符串

    4.目标空间必须可变(不一定)

    image-20220720114036376

    2.2模拟实现strcpy

    #include
    #include
    char* my_strcpy(char* dest, const char* src)
    {
        assert(dest&&src);
        char* ret = dest;
        while(*dest++ = *src++)
        {
            ;
        }
    //    while(*dest++ = *src++);while的循环体是;
        return ret;
    }
    int main()
    {
        char arr1[]="abcdef";
        char arr2[20]={ 0 };
        char* ret = my_strcpy(arr2, arr1);
        printf("%s\n",ret);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.strcat

    3.1分析

    功能:字符串追加

    参数:

    dest(destination)——目标字符数组的地址

    src(source)——源字符串的的地址

    char* strcat(char* dest, const char* src)
    
    • 1

    返回值:目标字符数组(目标空间)的地址(dest)

    注意事项:

    1.源字符串必须以 '\0’结束

    2.目标空间必须有足够的大,能容纳下源字符串的内容

    3.目标空间必须可修改

    4.会将源字符串中的’\0’追加到目标空间中

    5.字符串能自己给自己追加,会将字符串中的’\0’覆盖掉,结果是未知的,可能会出现死循环等问题!

    image-20220721110214932

    image-20220721110233652

    3.2模拟实现strcat

    #include
    #include
    char* my_strcat(char* dest, const char* src)
    {
        assert(dest!=NULL);
        assert(src!=NULL);
        char* ret = dest;
        //找到目标空间的末尾
        while(*dest != '\0')
        {
            dest++;
        }
        //覆盖'\0',将原数组的元素赋给目标空间
       	while(*dest++=*src++)
        {
            ;
        }
        return ret;
    }
    int main()
    {
        char arr1[20]="abcde";
        char arr2[]="fghij";
        my_strcat(arr1, arr2);
        printf("%s\n",arr1);
        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

    4.strcmp

    4.1分析

    功能:字符串比较

    参数:str1,str2——要比较的两个字符串(数组)的地址

    char* strcmp(const char* str1, const char* str2)
    
    • 1

    返回值:

    image-20220720151645696

    注意事项:

    1.比较两个字符串是否相等,例如arr1,arr2, 不可以arr1==arr2直接比较,arr1,arr2是数组名,数组名是数组首元素的的地址,地址无法比较,需要使用strcmp函数比较

    2.两个字符串比较,先是俩个字符串的首个字符进行大小的比较,如果相同,再向后进行下一对的比较,和两个字符串的长度无关

    4.2模拟实现strcmp

    #include
    #include
    int my_strcmp(const char* str1, const char* str2)
    {
        { 
            assert(str1 != NULL);
            assert(str2 != NULL);
            if(*str1==*str2 && *str2 == '\0')
                return 0;
            str1++;
            str2++;
    	}
        if(*str1 > *str2)
           return 1;
        else
           return -1;
           //return (*str1 - *str2);	
    }
    int main()
    {
        char arr1[20]="abcde";
        char arr2[20]="abc";
        int ret = my_strcmp(arr1, arr2);
        if (ret > 0)
    	{
    		printf(">\n");
    	}
    	else if (ret < 0)
    	{
    		printf("<\n");
    	}
    	else
    	{
    		printf("==");
    	}
        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

    5.strncpy

    5.1分析

    功能:字符串拷贝,长度受限制

    参数:

    dest(destination)——目标字符数组的地址

    src(source)——源字符串的的地址

    num——拷贝字符串的个数

    char* strncpy(char* dest, const char* src, size_t num)
    
    • 1

    返回值:目标字符数组(目标空间)的地址(dest)

    注意事项:

    1.和strcpy不同的是,可以限制拷贝字符串的个数,拷贝num个字符从源字符串到目标空间

    2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加’\0’,直到num个’\0’

    image-20220721104514483

    5.2模拟实现strncpy

    #include
    #include
    char* my_strncpy(char* dest, const char* src, size_t num)
    {
        assert(dest&&src);
        char* ret = dest;
        while(num && (*dest++ = *src++)!='\0')
        {
        	num--;
        }
        if(num)
        {
             while(num--)
        	{
           		 *dest++='\0';
        	}
        }
        return ret;
    }
    int main()
    {
        char arr1[]="abcdef";
        char arr2[]="bit";
        char* ret = my_strcpy(arr2, arr1, 5);
        printf("%s\n",ret);
        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

    6.strncat

    6.1分析

    功能:字符串追加,有长度限制

    参数:

    dest(destination)——目标字符串(数组)的地址

    src(source)——源字符串的地址

    num——追加字符串的个数

    char* strncat(char* dest, const char* src, size_t num);
    
    • 1

    返回值:目标字符串(数组)的地址(dest)

    注意事项:

    1.追加到目标空间的字符串结尾会添加 ’ \0 '用来结尾

    2.如果源字符串的长度小于num,追加到 ’ \0 ’ 便会停止追加

    3.不可以自己给自己追加(可能会造成死循环)

    image-20220725173131170

    6.2模拟实现strncat

    #include
    #include
    char* my_strncat(char* dest, const char* src, size_t num)
    {
        assert(dest&&src);
        char* ret = dest;
        while(*dest!='\0')
        {
            dest++;
        }
        while(num--)
        {
            while((dest++=*src++)=='\0')
            {
                return ret;
            }
            *dest='\0';
        }
        return ret;
    }
    int main()
    {
        char arr1[20]="abcdef";
        char arr2[]="ghi";
        my_strncat(arr1, arr2, 5);
        printf("%s\n",arr1);
        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

    7.strncmp

    7.1分析

    功能:字符串比较,限制长度

    参数:

    src1,src2——要比较的两个字符串

    num——比较的两个字符串(数组)的地址

    int strncmp(const char* str1, const char* str2)
    
    • 1

    返回值:

    • 第一个子字符串大于第二个子字符串,则返回大于0的数字
    • 第一个子字符串等于第二个子字符串,则返回0
    • 第一个子字符串小于第二个子字符串,则返回小于0的数字

    注意事项:

    比较到出现字符串中两个字符不同或者num个字符全部比较完毕

    7.2模拟实现strncmp

    #include
    #include
    int my_strncmp(const char* str1, const char* str2, size_t num)
    {
        assert(str1&&str2);
        while(num--)
        {
            if(*str1==*str2&&*str1!='\0')
            {
    			*str1++;
                *str2++;
            }
            else
            {
                return (*str1-*str2);
            }
        }
    }
    int main()
    {
        arr1[] = "abcdef";
        arr2[] = "abcdg";
        int ret = my_strncmp(arr1, arr2, 5);
        if(ret>0)
        {
            printf(">\n");
        }
        else if(ret==0)
        {
            printf("==\n");
        }
        else
        {
            printf("<\n");
        }
        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

    8.strstr

    8.1分析

    功能:查找子字符串

    参数:

    src1——被查找的字符串的地址

    str2——要查找的字符串的地址

    char* strstr(const char* str1, const char* str2)
    
    • 1

    返回值:存在返回子字符串所在的地址,不存在则返回空指针

    注意事项:

    image-20220723183042463

    8.2模拟实现strstr

    #include
    #include
    char* my_strstr(const char* str1, const char* str2)
    {
        assert(str1&&str2);
        const char* s1 = str1;
        const char* s2 = str2;
        const char* s1 = p;
        while(*p)
        {
            s1 = p;
            s2 = str2;
            while(*s1==*s2&&s1!='\0'&&s2!='\0')
            {
                s1++;
                s2++;
            }
            if(*s2=='\0')
            {
                return p;
            }
            p++;
        }
        return NULL;
    }
    int main()
    {
        char email[] = "wei@nulixuexi.com";
        char substr[] = "nulixuexi";
        char* ret = my_strstr(email,substr);
        if(ret == NULL)
        {
            printf("字串不存在\n");
        }
        else
        {
            printf("%s\n",ret);
        }
        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

    9.strtok

    9.1分析

    功能:切割字符串

    参数:

    str——被字符串的地址

    sep——分隔符(标记)所组成字符串的地址

    char* strtok(char* str, const char* sep)
    
    • 1

    返回值:找到分割符,返回指向这个分隔符开头的地址;没找到返回空指针

    注意事项:

    1.sep参数是个字符串,定义了用作分隔符的字符集合

    2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记

    3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针

    (注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)

    4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置

    5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记

    6.如果字符串中不存在更多的标记,则返回 NULL 指针

    7.查找时碰到字符串结尾\0,此时这个\0也会也会被当成一个标记,\0之后调用函数返回值都为空指针

    9.2使用实例

    image-20220724102154266

    10.strerror

    10.1分析

    功能:返回错误码所对应的错误信息

    参数:

    errnum——库函数执行失败时,所设置的错误码

    返回值: 返回系统中errno错误码所对应的描述错误文本(字符串)的地址

    注意实现:

    1.使用strerror必须包含的头文件#include

    2.errno - C语言设置的一个全局的错误码存放的变量

    10.2使用实例

    image-20220724111713982

    image-20220724112625969

    二.字符操作函数

    1.字符分类函数

    函数如果它的参数符合下列条件就返回真
    iscntrl任何控制字符
    isspace空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
    isdigit十进制数字 0~9
    isxdigit十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
    islower小写字母a~z
    isupper大写字母A~Z
    isalpha字母az或AZ
    isalnum字母或者数字,az,AZ,0~9
    ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
    isgraph任何图形字符
    isprint任何可打印字符,包括图形字符和空白字符

    2.字符转换函数

    int tolower (int c);//将大写字母转换为小写字母
    int toupper (int c);//将小写字母转换为大写字母
    
    • 1
    • 2
    /* isupper example */
    #include 
    #include 
    int main ()
    {
        int i=0;
        char str[]="Test String.\n";
        char c;
        while (str[i])
        {
            c=str[i];
            if (isupper(c))
            c=tolower(c);
            putchar (c);
            i++;
        }
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行结果:test string.

    三.内存操作函数

    1.memcpy

    1.1分析

    memcpy - 内存拷贝 memory - 记忆 - 内存 copy- 拷贝

    功能:把一块独立的空间中的数据拷贝到另一块独立的空间

    参数:

    dest(destination)——目标数据内存空间的地址

    src(source)——源数据内存空间的地址

    num——拷贝数据的字节数

    void* memcpy(void* dest, const void* src, size_t num ); 
    
    • 1

    返回值:目标数据内存空间的地址(src)

    注意事项:

    1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置

    2.这个函数在遇到’\0’的时候并不会停下来

    3.如果source和destination有任何的重叠,复制的结果都是未定义的

    image-20220724233851958

    1.2模拟实现memcpy

    #include
    #include
    void* my_memcpy(void* dest, const void* src, size_t num )
    {
    	assert(dest&&src);
        void* ret = dest;
        while(num--)
        {
            *(char*)dest = *(char*)src;
            dest = (char*)dest + 1;
            src = (char*)src + 1;
        }
        return ret;
    }
    int main()
    {
        int arr1[] = {1,2,3,4,5,6,7,8,9,10};
        int arr2[] = {0};
        my_memcpy(arr2, arr1, 28);
    	int i = 0;
        for(i = 0; i < 7; i++)
        {
            printf("%d ",arr2[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

    2.memmove

    2.1分析

    功能:把一块独立的空间中的数据拷贝到另一块独立的空间,允许源空间和目标空间出现重叠

    参数:

    dest(destination)——目标数据内存空间的地址

    src(source)——源数据内存空间的地址

    num——拷贝数据的字节数

    void* memmove( void* dest, const void* src, size_t num );
    
    • 1

    返回值:目标数据内存空间的地址(src)

    注意事项:

    1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的

    2.如果源空间和目标空间出现重叠,就得使用memmove函数处理

    2.2模拟实现memmove

    我们模拟实现时要注意,当源空间和目标空间出现重叠时,要考虑数据的拷贝方法,是从前向后拷贝还是从后向前拷贝,正确处理数据,才能得到正确的拷贝结果。有三种情况:

    1.当dest

    image-20220725120458136

    2.当dest>src且dest在src的空间范围内,数据要从后往前处理

    image-20220725120725802

    3.当dest>src且dest不在src的空间范围内,数据从后往前处理或从前往后处理都可以

    image-20220725120711997

    综上所诉,可以总结:

    当dest

    当dest>src时,数据要从后往前进行处理

    #include
    #include
    void* my_mommove(void* dest, const void* src, int num)
    {
        assert(dest&&src);
        void* ret = dest;
        if(dest<src)
        {   
            //前——>后
            while(num--)
            {
                *(char*)dest = *(char*)src;
                dest = (char*)dest+1;
                src = (char*)src+1;
            }
            return dest;
        }
        else
        {
            //后——>前
            while(num--)
            {
               *((char*)dest+num) = *((char*)src+num);
            }
        }
    }
    int main()
    {
        int arr1[] = {1,2,3,4,5,6,7,8,9,10};
        my_memmove(arr1+2, arr1, 5);
        int i = 0;
        for(i = 0; i < 10; i++)
        {
            printf("%d ",arr1[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

    3.memcmp

    3.1分析

    memcmp - memory compare 内存比较

    功能:比较两个内存块

    参数:

    ptr1,ptr2——指向两个内存空间的指针

    num——需要比较的字节数

    int memcmp(const void* ptr1, const void* ptr2, size_t num)
    
    • 1

    返回值:

    image-20220725153908428

    注意事项:

    1.与strcmp不同,该函数在遇到’\0’后,不会停止比较。

    2.该函数是以字节为单位进行比较的。

    使用实例:

    image-20220725164543616

    3.2模拟实现memcmp

    #include
    #include
    int  my_memcmp(const void* ptr1, const void* ptr2, size_t num)
    {
       assert(ptr1&&ptr2);
       while(num--)
       {
           if(*(char*)ptr1==*(char*)ptr2)
           {
               ptr1 = (char*)ptr1+1;
               ptr2 = (char*)ptr2+1;
           }
    	   else
           {
               return *(char*)ptr1 - *(char*)ptr2;
           }
       }
    }
    int main()
    {
        int arr1[] = {1,2,3,4,5};
        int arr2[] = {1,3,2};
        int ret = my_memcmp(arr1, arr2, 12);
        printf("%d\n",ret);
        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

    4.memset

    4.1分析

    memset - memory set 内存设置

    功能:填充内存块

    参数:

    ptr——指向要填充的内存块的指针

    value——要填充的值,该值作为 int 传递,但该函数使用此值的无符号 char* 转换来填充内存块

    num——要填充为该值的字节数

    void* memset(void* ptr, int value, size_t num)
    
    • 1

    返回值:被填充的内存块的地址(ptr)

    注意事项:可用于修改内存,value的类型为int, 但是使用时会转化为char*,例如97会转化为a

    image-20220725161253980

    image-20220725162944894

    4.2模拟实现memset

    #include
    #include
    void* my_memset(void* ptr, int value, size_t num)
    {
        assert(ptr);
        void* ret = ptr;
        while(num--)
        {
            *(char*)ptr = (char*)value;
            ptr = (char*)ptr+1}
        return ret;
    }
    int main()
    {
        int arr[] = "abcdef";
        my_memset(arr,'x', 5);
        printf("%s\n",arr);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    结语

    码字不易,跪求三连!!!

  • 相关阅读:
    rabbitmq
    H桥级联型五电平三相逆变器Simulink仿真模型
    银行业务头条体系推广
    【Kubernetes】k8s集群资源调度
    将 Vue.js 项目部署至静态网站托管,并开启 Gzip 压缩
    Tilt Five AR桌游体验:概念很新颖,但缺乏高质量内容?
    食品行业仓储条码管理系统解决方案
    大火的4D Radar数据集及基线模型汇总
    遥感技术让农业更“智慧”北斗在精准农业领域信息化农业化的特征
    研究生生涯实习记录
  • 原文地址:https://blog.csdn.net/m0_64224788/article/details/126121678