目录
strlen函数
1.1strlen函数介绍
size_t strlen (const char *str);
1.字符串以\0作为结束标志,strlen函数返回的是在字符串中\0前面出现的字符个数(不包含\0)
2.参数指向的字符串必须要以\0结束
3.函数的返回类型为size_t,相当于unsigned int无符号
1.2函数的基本使用
#include<stdio.h>
#include<string.h>
int main() {
char arr[] = "abcd";//数组里面存放了abcd\0
int len1 = strlen(arr);
printf("%d", len1);//结果返回4
int arr2 = {'a','b','c','d'};
int len2 = strlen(arr2);//结果返回随机数
return 0;
}
1.3函数的模拟实现
1.31计数器方法实现strlen函数
设置一个计数的变量,让一个字符指针遍历字符数组的每一个元素,如果指针指向的元素不是’\0’,计算器就自增,直到指针指向的元素是’\0’,就停止遍历,并返回计数器。
因为是模拟实现,我们就只求一致,返回值就设置为size_t
#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* str) {
assert(str);
size_t count = 0;
while (*str != '\0') {
count++;
str++;
}
return count;
}
int main() {
char arr[] = "abcde";
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
1.32指针减指针函数方法实现strlen函数
元素名是首元素的地址,我们就在定义一个指针,指向这个数组,让这个指针进行遍历,指向的不是’\0’就让指针进行自增。最后让遍历完数组的指针减去数组名(也就是首元素的地址)。
注意:当两个指着指向同一块空间时,指针减指针的绝对值就是两个指针之间的元素个数,而不是 个数*数据类型所占的空间。
#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char *str) {
char* count = str;
while (*count != '\0') {
count++;
}
return count - str;
}
int main() {
char arr[] = "abcde";
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
1.33递归的方式实现strlen函数
代码实现的思想:这种方式是不用创建临时变量的一种方法, 只使用指针进行遍历,如果指针指向的不是’\0’,那么就返回1和指针指向后一个数据的结果。
#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* str) {
assert(str);
if (*str != '\0') {
return 1 + my_strlen(str + 1);
}
else {
return 0;
}
}
int main() {
char arr[] = "abcde";
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
strcpy函数
char* strcpy(char* destination, const* source)
2.1strcpy函数的介绍
Copies the C string pointed by source into the array pointed by destination,including the terminating null characrer (and stopping at the point).
1.源字符串必须以\0结束
2.会将源字符串中的\0拷贝到目标空间
3.目标空间必须足够大,确保能存放源字符串
4. 目标空间必须可变
2.2 strcpy函数的简单使用
#include <stdio.h>
int main() {
char arr1[20] = { "*********"};
char arr2[] = { "Hello" };
//将arr2的数据拷贝到arr1中
strcpy(arr1, arr2);
printf("%s", arr1);//返回结果为Hello 因为strcpy函数会将\0拷贝过去
return 0;
}
2.3strcpy函数的模拟实现
#include <assert.h>
#include <string.h>
char* my_strcpy(char* dest,const char* src) {
char* ret = dest;
assert(dest && src);
while (*dest++ = *src++) {
;
}
return ret;
}
int main() {
char arr1[20] = { "*********"};
char arr2[] = { "Hello" };
my_strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
strcat函数
char* strcat(char* destination,const char* source);
3.1strcat函数的介绍
Appends a copy of the source string to the destination string.The terminating null character in destination is overwritten by the first character of source,and a null-character is included at the end of the new string formed by the concatenation of both in destination.
1.源字符串必须以\0结束
2.目标空间必须足够的大,能容纳下字符串的内容
3.目标空间可修改
4.不可以自己给自己追加
3.2 strcat函数的简单使用
函数的追加,想在arr1数组中追加一个arr2数组,可以通过以下代码来实现
#include <stdio.h>
#include <string.h>
int main() {
char arr1[20] = "Hello ";
char arr2[] = "CSDN" ;
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
3.3模拟实现strcat函数
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char*src) {
assert(dest && src);
char* ret = dest;
while (*dest != '\0') {
dest++;
}
while (*dest = *src) {
;
}
return ret;
}
int main() {
char arr1[20] = "Hello ";
char arr2[] = "CSDN" ;
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
strcmp函数
int strcmp(const char* str1,const char* str2)
4.1strcmp函数的介绍
This function starts comparing the first character of each string,If they are equal to each other,it continues with the following pairs until the characters differ or until a terminating null-character is reached.
1.第一个字符串大于第二个字符串,返回大于0的数字
2.第一个字符串等于第二个字符串,返回等于0的数字
3.第一个字符串小于第二个字符串,返回小于0的数字
4.2strcmp函数的基本使用
int main() {
char arr1[] = "CSDN";
char arr2[] = "CSDN";
if (arr1 == arr2) {
printf("==");
}
else {
printf("!=");
}
return 0;
}
此处返回结果为!=, arr1是数组名,arr2也是数组名,数组名是首元素的地址,可以发现arr1中的首元素地址和arr2中的首元素地址不相等,所以返回结果为!=,如果要比较两个字符串是否相等,应该比较的是两个字符串的内容,而不是字符串的地址是否相等。
1.第一个字符串大于第二个字符串,返回大于0的数字
2.第一个字符串等于第二个字符串,返回等于0的数字
3.第一个字符串小于第二个字符串,返回小于0的数字
可以利用strcmp函数的返回值来判断两个字符串的大小,字符进行对比时,会一一对比字符的ASCII码
#include <string.h>
int main(){
char arr1[] = "Hello";
char arr2[] = "CSDN";
int ret = strcmp(arr1, arr2);
if (ret < 0) {
printf("<");
}
else if (ret > 0) {
printf(">");
}
else {
printf("=");
}
}
4.3strcmp函数的模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
int my_strcmp(const char* arr1,const char* arr2) {
assert(arr1 && arr2);
while (*arr1 == *arr2) {
if (*arr1 == '\0') {
return 0;
}
arr1++;
arr2++;
}
return (*arr1 - *arr2);
}
int main(){
char arr1[] = "Hello";
char arr2[] = "CSDN";
int ret = my_strcmp(arr1, arr2);
if (ret < 0) {
printf("<");
}
else if (ret > 0) {
printf(">");
}
else {
printf("=");
}
}
由以上函数的介绍可知,strcpy,ctrcat,ctrcmp是长度受限的字符串函数,如果想使用字符串不受限的函数,可以使用ctrncpy,strncat,scrncmp函数
strncpy函数
char *strncpy(char* destination,const char* source,size_t num);
相比于strcpy函数,strncpy函数多了一个参数size_t num,使用此函数可以拷贝相对应的字字节数
#include <stdio.h>
#include <string.h>
int main() {
char arr1[20] = "***** CSDN";
char arr2[] = "hello";
strncpy(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;//返回hello CSDN
}
strncat函数
char* strncat(char* destination,const char* source,size_t num);
与strncpy函数相同,在参数部分增加了一个size_t num,可以设置需要添加的参数的个数,注意,strbcat函数执行完之后,会再后方重新添加一个\0
int main() {
char arr1[15] = "Hello ";
char arr2[] = "CSDN****";
strncat(arr1, arr2, 4);
printf("%s", arr1);
return 0;
}//返回 Hello CSDN
strncmp函数
与strncpy和strncat函数相同,增加了一个size_z num参数,可以设置需要比较的字符串函数的个数,使用方法和strcmp相同
strstr函数
const char* strstr(const char* str1,const* str2);
5.1strstr函数介绍
在一个字符串中找另外一个字符串,找另外一个字符串,如果找到了,返回子串在字符串中的地址,如果找不到,则返回一个空指针。
5.2strstr函数的基本使用
在arr2字符串中找arr1字符串,找到了则返回arr2后面的字符串,没找到则在屏幕上输出没找到
#include <string.h>
int main() {
char arr1[] = "CSDN";
char arr2[] = "Hello CSDN!!!";
char* ret = strstr(arr2, arr1);
if (ret == NULL) {
printf("没找到");
}
else {
printf("%s\n", ret);
}
return 0;
}//返回CSDN!!!
5.3strstr函数的模拟实现
暴力求解法:
思路:
情况1:假设有一个字符串str1为abcdef,一个字符串str2为def,需要在str1字符串中查找字符串str2,此时可以在str1字符串中一次遍历。
情况2:假设有一个字符串str1为abbcdef,一个字符串str2为bcd,此时在查找到第一个字符b时,与str2中的b对应,接着查找str1字符串中b后面的b,与str2中的第二个字符比较,会发现两者不相等,此时如果按照情况1的算法会发现紧接着会查找str1中的c,与str2中的b相比较,这种算法可以发现并不能查找到str2字符串。
所以,我们可以在str1字符串中定义一个起始变量s1.指向首元素,定义一个变量p,也同样指向首元素,定义一个变量s2,指向str2中的首元素,p变量记录对比的对应的str1的首元素地址,如果p指向的元素与s1相等,那么s1++,s2++,对比s1和s2是否相等,如果不相等,则p++,再将s1指向p的地址,判断下一个字符是否和s2中的第一个字符相等,如果相等,则使用创建的s1变量与s2变量对比,知道s2找到\0为止,如果没有找到,那么则返回一个空指针,总之,p变量用来指向str1字符串中所查找的一个字符的地址,s1变量和s2变量用来对比两个变量是否相等。
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1,const char* str2) {
char* s1 = str1;
char* s2 = str2;
char* p = str1;
assert(str1 && str2);
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 str1[] = "abbcdef";
char str2[] = "bcd";
char* ret = my_strstr(str1, str2);
if(ret == NULL){
printf("字符串不存在");
}
else{
printf("%s\n", ret);
}
return 0;
}
strtok函数
6.1strtok函数介绍
用来切割字符串1.sep 参数是个字符串,定义了用作分隔符的字符集合2.第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。3.strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针(注: strtok函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改。)4.strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串 中的位置。5.strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。6.如果字符串中不存在更多的标记,则返回 NULL 指针。
6.2strtok函数的基本使用
#include <string.h>
int main() {
char* sep = ".";
char str[40] = "www.csdn.net";
char* ret = strtok(str, sep);//strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。
printf("%s\n", ret);//输出www
ret = strtok(NULL, sep);//strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
printf("%s\n", ret);//输出csdn
ret = strtok(NULL, sep);//strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
printf("%s\n", ret);//输出net
return 0;
}
可以发现,如果数据量大了的话,需要多行代码,这种写法就特别繁琐,所以可以进行优化。
#include <string.h>
int main() {
char* sep = ".";
char str[40] = "www.csdn.net";
char* ret = NULL;
for (ret = strtok(str, sep); ret != NULL; ret = strtok(NULL, sep)) {
printf("%s\n", ret);
}
return 0;
}
strerror函数
char* strerror(int errnum);
7.1strerror函数介绍
1.返回错误码,所对应的错误信息。
2.c语言的库函数,在执行失败的时候,都会设置错误码,例如1,2,3,4,5,每个错误码所对应不同的错误信息
/* strerror example : error list */#include <stdio.h>#include <string.h>#include <errno.h> // 必须包含的头文件
可以看到,不同的错误码对应的错误信息是不同的。
7.2strerror函数的简单使用
返回了No such file or directory,电脑中并没有CSDN.txt这个文件,此时会返回错误码,可以通过 printf("%s", strerror(errno));语句来输出错误的原因。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main() {
FILE* fp = fopen("CSDN.text", "r");//打开一个CSDN文件,以读的方式
if (fp == NULL) {
printf("%s", strerror(errno));
}
else {
;
}
return 0;
}
字符分类函数:
头文件<ctype.h>
函数
|
如果他的参数符合下列条件就返回真
|
iscntr
|
任何控制字符
|
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
|
任何可打印字符,包括图形字符和空白字符
|
字符分类函数的简单使用
例如 isspace函数的使用
#include <stdio.h>
#include <ctype.h>
int main() {
int a = isspace('w');
printf("%d\n", a);//输出0
return 0;
}
此函数可以判断是否是空白字符,通常用来在字符串中判断这个字符串是否是空白字符,如果是空白字符,指针++,以上函数的使用方法相同,不一一列举。
memcpy函数
8.1memcpy函数的介绍
void * memcpy ( void * destination, const void * source, size_t num );
strcpy和strncpy函数在使用中只能拷贝字符串,但是如果出现一组数字或者浮点型数据需要拷贝,strcpy和strncpy函数是不可以进行拷贝的,此时可以使用memcpy函数将内存进行拷贝,此时就不需要在意数据的类型。
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 '\0' 的时候并不会停下来。3.如果 source 和 destination 有任何的重叠,复制的结果都是未定义的。
8.2memcpy函数的简单使用
#include<stdio.h>
int main() {
int arr1[] = { 1, 2, 3, 4, 5, 6, 7 };
int arr2[] = { 8 };
memcpy(arr1, arr2, 4);
return 0;
}
此时arr1数组中的值为{8,2,3,4,5,6,7};
8.3memcpy函数的模拟实现
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* str1, const void* str2, size_t num) {
assert(str1 && str2);
void* ret = str1;
while (num--) {
*(char*)str1 = *(char*)str2;//void型不可以直接解引用,此处强制类型转换成char型,每次cpy一个字节
str1 = (char*)str1 +1 ;
str2 = (char*)str2 + 1;
}
return ret;
}
int main() {
int arr1[] = { 1, 2, 3, 4, 5, 6, 7 };
int arr2[] = { 8 };
my_memcpy(arr1, arr2, 4);
return 0;
}
如果希望将arr1中的数组的1-5个元素拷贝到3-7个元素上面,会发现,当拷贝到第三个数据的时候,第三个数据已经被修改成了第一个数据了,所以,memcpy函数不可以用来处理重叠内存之间的拷贝(在vs中可以重叠修拷贝),我们可以使用memmove函数。
memmove函数
9.1memmove函数的介绍
void * memmove ( void * destination, const void * source, size_t num );
1.和 memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的。2.如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。
9.2模拟实现memmove函数
在刚刚的情况中,如果希望将arr1中的1-5个元素拷贝到3-7个数据中,会发现拷贝到第三个数据的时候,第三个数据已经被修改成第一个数据了,此时如果先将地5个数据拷贝到第7个数据,第4个数据拷贝到第六个数据,依次拷贝,会发现,并不会存在被覆盖的情况,那么是不是所有的拷贝都从后往前覆盖就可以避免不被覆盖的情况呢?假设如果一个数组中,希望将3-7个数据拷贝到2-5个数据中,从后往前拷贝也会发现存在被覆盖的情况,所以,有些时候需要从前往后处理数据,有些时候有需要从后往前处理数据。由以上情况我们可以判断拷贝数据和需要被拷贝i的数据的地址,如果被拷贝的首元素地址在拷贝数据的前面时,可以从前向后拷贝,反之,可以从后向前拷贝。
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, void* src, size_t num) {
assert(dest && src);
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[] = { 0,1,2,3,4,5,6,7,8,9 };
my_memmove(arr1, arr1 + 2, 8);
int i = 0;
for (i = 0; i < 10; i++) {
printf("%d", arr1[i]);
}
return 0;
}