字符串函数—C语言(超详细)

目录

 strlen函数

        1.1strlen函数介绍

         1.2函数的基本使用

1.3函数的模拟实现

        1.31计数器方法实现strlen函数

        1.32指针减指针函数方法实现strlen函数       

        1.33递归的方式实现strlen函数

strcpy函数

        2.1strcpy函数的介绍

       2.2 strcpy函数的简单使用

        2.3strcpy函数的模拟实现

strcat函数

        3.1strcat函数的介绍

       3.2 strcat函数的简单使用

        3.3模拟实现strcat函数

strcmp函数

       4.1strcmp函数的介绍

        4.2strcmp函数的基本使用

        4.3strcmp函数的模拟实现

strncpy函数

 strncat函数

strncmp函数

strstr函数

        5.1strstr函数介绍

        5.2strstr函数的基本使用

        5.3strstr函数的模拟实现

strtok函数

        6.1strtok函数介绍

        6.2strtok函数的基本使用

strerror函数

        7.1strerror函数介绍

        7.2strerror函数的简单使用

 字符分类函数:

        字符分类函数的简单使用

memcpy函数

        8.1memcpy函数的介绍

        8.2memcpy函数的简单使用

        8.3memcpy函数的模拟实现

memmove函数

        9.1memmove函数的介绍

        9.2模拟实现memmove函数


 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函数

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

        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.函数memcpysource的位置开始向后复制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;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_maisui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值