C语言———字符与字符串

目录

函数介绍

1. strlen

         1.1 模拟实现strlen

2. strcpy

        2.1 模拟实现strcpy 

3. strcat

        3.1 模拟实现strcat 

4. strcmp

        4.1 模拟实现strcmp 

5. strncpy 

6. strncat

7. strncmp

8. strstr

        8.1 模拟实现strstr

9. strtok

10. strerror

字符分类函数

字符转换

内存操作函数

11. memcpy

12. memmove

        12.1 模拟实现memmove

13. memcmp

14. memset

结语:


函数介绍

       c语言没有字符串类型,所以我们要把字符串放入字符数组中,当我们使用字符串函数时,就要引头文件:#include <string.h>


1. strlen

size_t strlen ( const char * str );
返回一个无符号整数
用来求字符串长度
字符串末尾隐藏放置了一个 ' \0 ' ,返回 ' \0 ' 之前的字符个数

        这里的arr就是数组的首元素地址,只要传入一个地址,就可以向后访问,直到找到 ‘ \0 ’ 为止。

这里打印了一个随机值,因为该字符串没有‘ \0 ’,strlen就会继续向后访问,直到找到' \0 '才听停止。

         1.1 模拟实现strlen

为了模拟这个函数,我们也要像库里的函数声明一样,规定函数名,返回类型,参数类型

 为了使代码更加健壮,所以用了const和assert。  


2. strcpy

char* strcpy ( char * destination , const char * source );
源字符串必须以 '\0' 结束。
会将源字符串中的 '\0' 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。

 所以在写代码的时候一定不要忘了‘ \0 ’

        2.1 模拟实现strcpy 

把注释部分简写成这样,代码看着也更加简洁。

链式访问 :用函数的返回值来作为printf函数的参数。


3. strcat

字符串追加函数

char * strcat ( char * destination , const char * source );
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。

        3.1 模拟实现strcat 


4. strcmp

int strcmp ( const char * str1 , const char * str2 );
这个函数比较的是对应位的ASCII码值,如果该位相同,比较下一位。
第一个字符串大于第二个字符串,则返回大于 0 的数字
第一个字符串等于第二个字符串,则返回 0
第一个字符串小于第二个字符串,则返回小于 0 的数字

        4.1 模拟实现strcmp 


5. strncpy 

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

 

拷贝 num 个字符从源字符串到目标空间。
如果源字符串的长度小于 num ,则拷贝完源字符串之后,在目标的后边追加 0 ,直到 num 个。

6. strncat

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

追加指定字节的字符串


7. strncmp

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

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

8. strstr

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

字符串找另一个字符串,看是不是子串

        8.1 模拟实现strstr

 

 总结一下:

        str1和str2开始时要把值赋给s1和s2,还要把str1再赋给新变量cur,因为如果这一组不是子串,那么下次循环开始的位置是这次开始的下一位,也就是上面说的s1+1,还有如果不是子串,s2也要回到初始位置上。最后,如果s2指向的内容为'\0',就证明s1和s2这一组就是我们要找的子串,那么就要返回arr1数组中记录该位置的起始位置,也就是cur,如果找不到就返回一个空指针。


9. strtok

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


10. strerror

char * strerror ( int errnum );
返回错误码,所对应的错误信息。
#include <errno.h> // 必须包含的头文件

字符分类函数

#include <ctype.h> //头文件
函数 如果他的参数符合下列条件就返回真
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 :字母或者数字,a~z,A~Z,0~9
ispunct : 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph : 任何图形字符
isprint :   任何可打印字符,包括图形字符和空白字符
        举个例子,这个islower函数判断,这个字符是不是小写字符,如果是就返回非0值,如果不是则返回0。这些函数使用起来还是非常方便的。

字符转换

int tolower ( int c ); //转换成小写字母
int toupper ( int c);  //转换成大写字母
#include <ctype.h> //头文件


内存操作函数

11. memcpy

void * memcpy ( void * destination , const void * source , size_t num );
函数 memcpy 从s rc 的位置开始向后复制 num 个字节的数据到 dest 的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。

如果 src dest 有任何的重叠,复制的结果都是未定义的。
也就是说,如果我们想把(arr1+2)的内容拷贝到arr1中,像我们模拟出来的函数是从前往后拷贝的,但在拷贝的过程中,会改变原src的内容。

但结果并不是这样,就是因为上述的原因 


12. memmove

void * memmove ( void * destination , const void * source , size_t num );
为了解决memcpy带来的问题,就出现了memmove函数,这个函数可以实现覆盖部分的拷贝,就不会出现在拷贝时改变了内容而出现的问题。

        12.1 模拟实现memmove

 

 总结一下:

        因为在库中,memmove函数返回类型是void*,参数也是void*,所以才传入一个size_t类型的值,这里就是几个字节,引出要把两个形参都强制类型转换成char*来计算。

        从前向后:强转成char*后解引用拿到1个字节,从前向后把每个字节都改变,改变完这个之后,dest和src都+1,还要继续强转,因为强转不会永久改变,之后通过改变count来控制次数。

        从后向前:大致与从前向后一致,就是改变方向,这里一开始时count=20,之后--变成19,强转之后+19正好访问到最后一个字节,通过count--,从后向前依次拷贝。

         最后注意:在vs这个编译器中,即使是覆盖的拷贝,memcpy也是可以实现的,因为这个编译器的不断优化,所以可以实现字符串自己拷贝自己。但是,可能也只是在vs这个编译器中可以实现,其他的编译器不一定可以实现。所以想要实现字符串自己拷贝自己,还是选择memmove。


13. memcmp

int memcmp ( const void * ptr1 , const void * ptr2 , size_t num );
这里与strcmp的区别不大,>返回正数,<返回负数,=返回0。

14. memset

void *memset( void *dest, int c, size_t count );

作用是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。


结语:

       关于字符串的相关内容就介绍到这里,虽然文章中介绍了许多字符串函数的模拟实现,但是这并不一定就是库里面的实现方法,可以说是其中一种解决方法,写出来只是为了更好的了解这个函数是如何实现的,在日常写代码的过程中,就可以直接引用了。

        字符串完结,期待下一篇。

猜你喜欢

转载自blog.csdn.net/m0_64607843/article/details/123607483