• 字符函数和字符串函数(C语言)


    字符函数和字符串函数

    重点

    • 求字符串的长度
      • strlen
    • 长度不受限制的字符串函数
      • strcpy
      • strcat
      • strcmp
    • 长度不受限制的字符串函数的介绍
      • strncpy
      • strncat
      • strncmp
    • 字符串查找
      • strstr
      • strtok
    • 错误信息报告
      • strerror
    • 字符操作
    • 内存操作函数
      • memcpy
      • memmove
      • memset
      • memcmp

    前言

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

    字符函数介绍

    一.strlen

    size_t strlen ( const char * str );

    • 字符串已\0作为结束标志,strlen函数返回的是在字符串中\0前面出现的字符个数(不包含\0).
    • 参数指向的字符串必须要以\0结束
    • 注意函数的返回值是size_t,是无符号的(易错)例如:
    #include 
    #include 
    
    int main() {
        if(strlen("abc") - strlen("abcdef") > 0) {
            printf("> \n");
        }else {
            printf("< \n");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    当我们看到这里的时候以为是-3肯定是小于号,其实不然,返回值是无符号的所以返回的是无符号的-3,这个在内存中肯定是大于0的

    二.strcpy

    char * strcpy ( char * destination, const char * source );

    • 源字符串必须以\0结束
    • 会将源字符串的\0拷贝到目标空间
    • 目标空间必须足够大,以确保能存放源字符串
    • 目标空间必须可变

    以下是模拟实现的代码:

    #include 
    #include 
    
    char* my_strcpy(char* dest,const char* src) {
        assert(dest);
        assert(src);
        char* ret = dest;
        while(*dest++ = *src++);
        return ret;
    }
    
    int main() {
        char arr1[20] = "abc";
        char arr2[] = "hello world!";
        printf("%s\n", my_strcpy(arr1,arr2));
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    三.strcat

    char * strcat ( char * destination, const char * source );

    • 源字符串必须以\0结束
    • 目标空间必须有足够的大,能容纳下源字符串的内容
    • 目标空间必须可修改

    使用场景:

    #include 
    #include 
    
    int main() {
        char arr1[20] = "hello ";
        char arr2[] = "world!";
        strcat(arr1, arr2);
        printf("%s\n", arr1);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这个函数的模拟实现:

    #include 
    #include 
    
    char* my_strcat(char* dest, const char* src) {
        char* cur = dest;
        while(*++cur != '\0');
        while(*cur++ = *src++);
        return dest;
    }
    
    int main() {
        char arr1[20] = "hello ";
        char arr2[] = "world!";
        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

    三.strcmp

    int strcmp ( const char * str1, const char * str2 );

    • 标准规定:
    1. 第一个字符串大于第二个字符串,则返回大于0的数字
    2. 第一个字符串等于第二个字符串,则返回0
    3. 第一个字符串小于第二个字符串则返回小于0的数字

    模拟实现:

    #include 
    #include 
    
    int my_strcmp(const char* src1, const char* src2) {
        while(*src1 == *src2) {
            if(*src1 == '\0') {
                return 0;
            }
            src1 ++;
            src2 ++;
        }
        return src1 - src2;
    }
    
    int main() {
        char arr1[] = "abcdef";
        char arr2[] = "abc";
        int ret = my_strcmp(arr1, arr2);
        printf("%d\n", ret);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    四.strncpy

    char * strncpy ( char * destination, const char * source, size_t num );

    • 拷贝num个字符从源字符串到目标空间
    • 如果源字符串的长度小于num,则拷贝完源字符串后,在目标的后面追加0,知道num个
      使用场景:
    #include 
    #include 
    
    int main() {
        char arr1[] = "abcef";
        char arr2[] = "xxxxxx";
        strncpy(arr1, arr2, 2);
        printf("%s\n", arr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    五.strncat

    char * strncat ( char * destination, const char * source, size_t num );
    这个函数的功能就是追加有长度限制的个数,使用场景:

    #include 
    #include 
    
    int main() {
        char arr1[] = "abcdef";
        char arr2[] = "xxx";
        strncat(arr1, arr2, 2);
        printf("%s\n", arr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    六.strncmp

    int strncmp ( const char * str1, const char * str2, size_t num );

    比较有限制长度的两个字符串使用场景:

    #include 
    #include 
    
    int main() {
        char arr1[] = "abcdef";
        char arr2[] = "abc";
        int ret = strncmp(arr1, arr2, 3);
        printf("%d\n", ret);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    七.strstr

    char * strstr ( const char *, const char * );

    这个函数的功能就是在一个字符串中找另一个字符串是否存在

    使用场景:

    #include 
    #include 
    
    int main() {
        char arr1[] = "abcdefabcdef";
        char arr2[] = "fab";
        char* p = strstr(arr1, arr2);
        if(p == NULL) {
            printf("不存在\n");
        }else {
            printf("%s\n", p);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    模拟实现:

    #include 
    #include 
    
    char* my_strstr(char* str1, char* str2) {
        char* s1 = str1;
        char* s2 = str2;
        char* p = str1;
        while(*p) {
            s1 = p;
            s2 = str2;
            if(*str2 == '\0') {
                return str1;
            }
            while(*s1 != '\0' && *s2 != '\0' && (*s1 == *s2)) {
                s1 ++;
                s2 ++;
            }
            if(*s2 == '\0') {
                return p;
            }
            p ++;
        }
        return NULL;
    }
    
    int main() {
        char arr1[] = "abcdefabcdef";
        char arr2[] = "fab";
        char* p = my_strstr(arr1, arr2);
        if(p == NULL) {
            printf("不存在\n");
        }else {
            printf("%s\n", p);
        }
    }
    
    • 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

    八.strtok

    char * strtok ( char * str, const char * delimiters );

    • delimiters参数是个字符串,定义了用作分隔符的字符集合
    • 第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分隔符分割的标记
    • strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容,并且可以修改)
    • strtok的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置
    • strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
    • 如果字符串你中不存在更多的标记,则返回NULL指针

    使用场景:

    #define _CRT_SECURE_NO_WARNINGS
    
    #include 
    #include 
    
    int main() {
    	char arr[] = "zhangyang@qq.com";
    	char buf[200] = { 0 };
    	strcpy(buf, arr);
    	const char* p = "@.";
    	char* str = strtok(buf, p);
    	printf("%s\n", str);
    	str = strtok(NULL, p);
    	printf("%s\n", str);
    	str = strtok(NULL, p);
    	printf("%s\n", str);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面那个写法比较庸俗,我们用更优雅的方式:

    #define _CRT_SECURE_NO_WARNINGS
    
    #include 
    #include 
    
    int main() {
    	char arr[] = "zhangyang@qq.com";
    	char buf[200] = { 0 };
    	strcpy(buf, arr);
    	const char* p = "@.";
    	char* str = NULL;
    	for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p)) {
    		printf("%s\n", str);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    字符分类函数

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

    内存操作函数

    一.memcpy

    void * memcpy ( void * destination, const void * source, size_t num );

    • 函数从source的位置开始向后复制num个字节的数据到destinatio中去
    • 这个函数在遇到\0的时候并不会停下来
    • 如果source和destinat有任何的重叠复制的结果都是未定义的

    使用场景:

    #include 
    #include 
    
    int main() {
    	int arr1[] = { 1,2,3,4,5,6,7,8 };
    	int arr2[20] = { 0 };
    	memcpy(arr2, arr1, sizeof(arr1[0]) * 3);
    	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++) {
    		printf("%d ", arr2[i]);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    模拟实现:

    #include 
    #include 
    
    int main() {
    	int arr1[] = { 1,2,3,4,5,6,7,8 };
    	int arr2[20] = { 0 };
    	memcpy(arr2, arr1, 12);
    	for (int i = 0; i < 3; i++) {
    		printf("%d ", arr2[i]);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    二.memmove

    void * memmove ( void * destination, const void * source, size_t num );

    我们发下这个函数和上一个函数的参数和返回类型是一样的,但是还是有点区别的

    1. memcpy拷贝的是不重复的内存
    2. memmove是可以拷贝重复的内存的

    模拟实现:

    #include 
    #include 
    
    
    void* my_memcpy(void* dest, void* src, size_t num) {
    	void* ret = dest;
    	if (dest < src) {
    		while (num--) {
    			*(char*)dest = *(char*)src;
    			dest = (char*)dest + 1;
    			src = (char*)src + 1;
    		}
    	}
    	else {
    		while (num--) {
    			*((char*)dest + num) = *((char*)src + num);
    		}
    	}
    	return ret;
    }
    
    int main() {
    	int arr1[] = { 1,2,3,4,5,6,7,8 };
    	int arr2[20] = { 0 };
    	my_memcpy(arr2, arr1, sizeof(arr1[0]) * 3);
    	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); 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
    • 27
    • 28
    • 29
    • 30
    • 31

    加上了一个新的比较,这样就可以实现重叠内存的拷贝

    三.memcmp

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

    • 比较从ptr1和ptr2指针开始的num个字节
    • 返回值如下:
      在这里插入图片描述
      注意是按照一个字节一个字节去比较的
  • 相关阅读:
    【贪心的商人】python实现-附ChatGPT解析
    「React」RSC 服务端组件
    IDEA 2021.3.3最新激活破解教程(可激活至2099年,亲测有效)
    爬虫之BeautifulSoup4
    Nginx动静分离、缓存配置、性能调优、集群配置
    MyBatis核心配置文件解析: 一步步深入理解mybatis-config.xml
    线性表01- 数组与简易接口设计
    C++设计模式
    【轻NAS】Windows搭建可道云私有云盘,并内网穿透公网访问
    java的引用数据类型-附String字符串常量池简介(别再用new String了)
  • 原文地址:https://blog.csdn.net/qq_63474430/article/details/126794963