0. 前言
这篇文章是关于strlen,strcpy,strcat,strcmp,strncpy,strncat,strncmp,strstr的知识点总结,花了不少精力与时间,文章整体超过一万字,可以用来快速查找字符串函数的功能和实现
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在
常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数
1. 函数介绍
1.1 strlen
size_t strlen ( const char * str );
字符串末尾是隐藏着一个'\0'的
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abcdef"; int len1 = strlen(arr1); printf("%d\n", len1); return 0; }
1.1.1主动改变'\0'的位置
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abc\0def"; int len1 = strlen(arr1); printf("%d\n", len1); return 0; }
- 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。
不知道'\0'的位置
#include<stdio.h> #include<string.h> int main() { char arr2[3] = { 'a','b','c'}; int len2 = strlen(arr2); printf("%d\n", len2); return 0; }
原因:
没有'\0',一直从'a'的位置往后数,内存里面一直往后找,什么时候找到'\0',什么时候停下,所以得出的结果是一个随机值
✅"strlen函数的返回类型是size_t - 无符号整型"✅
以下代码函数相减结果为-3,(因为无符号数减无符号数为无符号数),但是-3作为一个无符号整型来看待,那就是说内存中的补码直接当成了一个数字来看待了,而不是转换成原码来看待,那将是一个正整数
#include<string.h> int main() { if (strlen("abc") - strlen("abcdef") > 0) { printf(">\n"); } else { printf("<=\n"); } }
下面的出现现象是我发现的一些问题:
当使用strlen函数但不引用头文件时,执行结果超出预料:
不引用头文件,但是使用它的库函数,这种行为,编译器连警告也没有,正常执行
1. #incl
个人反思:永远记住一个点,就是使用头文件,使用库函数的时候一定要包含正确的头文件,否则它可能会有一些异常的情况。
这就是一次异常啊,因为正常情况下:size_t 返回的值是unsigned int类型的,即使算出负数,它也是会转换成一个>=0的数字。
求字符串长度的方法💥
1.计数器
#include<stdio.h> #include<string.h> #include<assert.h> int my_strlen(const char* str) { int count = 0; assert(str);//断言一下是不是NULL指针 while (*str != '\0') { count++; str++; } return count; } int main() { char arr[] = "bit"; int len = my_strlen(arr); printf("%d\n", len); return 0; }
2.递归
题目要求:不创建临时变量,求字符串长度
思路:当第一个字符‘b’不为‘\0’,那整个字符串长度就是1+my_strlen(str+1)
要是第一个字符串(从str指向的首地址开始)为‘\0’,那就return 0
#include<stdio.h> int my_strlen(char *str) { if (*str != '\0') return 1 + my_strlen(1 + str); else return 0; } int main() { char arr[] = "bit"; int len = my_strlen(arr); printf("%d\n", len); return 0; }
3.指针 - 指针
指针- 指针 == 地址 - 地址
前提:
- 两个指针指向同一块空间,指针的类型是一致的
- 指针 - 指针得到的是指针和指针之间的元素个数(这是语法规定的)
#include<stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9}; int n = &arr[9] - &arr[0]; printf("%d\n", n); return 0; }
1.2 strcpy
char* strcpy(char * destination, const char * source);
- 源字符串必须以 '\0' 结束。
- 会将源字符串中的 '\0' 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
1️⃣常量字符串:
char* p = "abcdefghi"
2️⃣字符串初始化数组本身:
char arr2[] = "hehe\n";
正常的普通操作
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abcdef"; char arr2[] = { 0 }; strcpy(arr2, arr1); printf("%s\n", arr2); return 0; }
错误操作:🧨
1.arr1数组名是一个地址,赋给一个地址arr2。
是错误的。正确操作应该是把数据放在地址所指向的空间里面去,而不是放到地址上
#include<stdio.h> #include<string.h> int main(){ char arr1[] = "qwertyuiop"; char arr2[] = arr1;//err char arr2[20] = { 0 }; arr2 = arr1;//err return 0; }
2.数组没有'\0'
#include<stdio.h> #include<string.h> int main() { char arr1[3] = { 'a','b','c' }; char arr2[20] = "xxxxxxxx"; strcpy(arr2, arr1); printf("%s\n", arr2); return 0; }
可以看到字符'c'后面还有其它不是数组的元素,那是因为'c'的后面没有'\0',所以它会从'c'的后面一直往后找‘\0’, 直到找到为止
3.错误示范 - 目标空间不够大
#include<stdio.h> #include<string.h> int main(){ char arr1[20] = "abcdefgh"; char arr2[3] = "";//错误示范 - 目标空间必须足够大 strcpy(arr2,arr1); printf("%s\n", arr2); return 0; }