C语言进阶–万字讲解带你学会字符串函数

在这里插入图片描述

动态分区

  • 魔王的介绍:😶‍🌫️一名双非本科大一小白。
  • 魔王的目标:🤯努力赶上周围卷王的脚步。
  • 魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥
    在这里插入图片描述
    ❤️‍🔥大魔王与你分享:不动声色地强大自我,对每件热爱的事物都全力以赴;生活不一定要酷,但一定要有态度。

进程线程

文章目录

core dump

一、前言

C语言学习中我们有一些经常需要用到函数,于是为了提高程序员的效率,便出现了库函数,每个编译器下面都有一套自己的库函数实现方法,可能有略微差异,但是主要功能都是相同的。我们经常说:能用到库函数就不要自己去定义实现,那么本篇带你熟练掌握C语言中的字符串库函数以及部分的模拟实现。

swiftui

二、字符串函数

  • 字符串函数对应的头文件都是<string.h>

1.strlen

1.1 介绍

size_t strlen(const char* str)
规则:一直读取直到遇见’\0’停止,'\0’不算。

Spring的xml版使用

  • 返回值:返回读到字符串中’\0’之前读到的字符个数。
  • 注意点:
  1. 返回的类型为size_t(无符号型),就相当于unsigned int. 所以两个字符串相减不值为负数并且不进行类型转换时,其实它会是一个很大的无符号整型(大于0的数)。
  2. 读取的字符串必须以’\0’结尾,否则一只读取。

1.2 strlen函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[20] = "abcdefg";
	int num1 = strlen(arr);
	size_t num2 = strlen(arr);
	printf("%d\n",num1);
	printf("%u\n",num2);
	return 0;
}

1.3 模拟实现strlen函数

#include <stdio.h>
#include <assert.h>
//逐个判断
size_t my_strlen1(const char* arr)
{
	assert(arr);
	size_t num = 0;
	while (*arr++)
	{
		num++;
	}
	return num;
}
//递归实现
size_t my_strlen2(const char* arr)
{
	assert(arr);
	if (*arr !='\0')
	{
		return 1 + my_strlen2(arr+1);
	}
	else
		return 0;
}
//指针减指针
size_t my_strlen3(const char* arr)
{
	assert(arr);
	char* start = arr;
	while (*arr)
	{
		arr++;
	}
	return arr - start;
}
int main()
{
	char arr[20] = "abcdefg";
	//size_t num = my_strlen1(arr);
	//size_t num = my_strlen2(arr);
	size_t num = my_strlen3(arr);
	printf("%u\n", num);
}

2.strcpy

2.1 介绍

char* strcpy(char* destination, const* source)
规则:将源字符串拷贝到目标空间中,并且也会将’\0’拷贝过去,并且拷贝完第一个\0结束拷贝。

新浪微博

  • 返回值:目标空间的首元素地址。
  • 注意点:
  1. 源字符串必须以’\0’结尾。
  2. 目标空间必须足够大,以确保能存放源字符串。
  3. 目标空间必须可变(也就是不能为字符串常量)。

2.2 strcpy函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[10] = "abcde";
	printf("%s\n", strcpy(arr1, arr2));
	return 0;
}

2.3 模拟实现strcpy函数

#include <stdio.h>
char* my_strcpy(char* dest,const char* src)
{
	char* start = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return start;
}
int main()
{
	char dest[20] = "xxxxxxxxxxxxx";
	char src[16] = "abc";
	printf("%s\n", my_strcpy(dest, src));
	return 0;
}

3.strcat

3.1 介绍

char* strcat(char* destination,const char* source)
规则:从目标空间’\0’位置开始追加,直到源字符串的第一个’\0’为止。

static关键字

  • 返回值:返回目标空间首元素地址。
  • 注意点:
  1. 源字符串必须以’\0’结束。
  2. 目标空间必须有足够大的空间,能容下追加后的字符串的内容。
  3. 目标空间必须可修改(为变量)。
  4. 该函数不能追加自己(因为如果追加自己,那么自己的’\0’会被替换掉,就无法停止了)。
    如图:
    在这里插入图片描述

3.2 strcat函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[20] = "abcde\0qqqqqqq";
	char arr2[10] = "xxxxxx";
	printf("%s\n",strcat(arr, arr2));
	return 0;
}

3.3 模拟实现strcat函数

#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest&&stc);
	char* start = dest;
	while (*dest)
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return start;

}
int main()
{
	char arr1[20] = "abcde\0qqqqqqq";
	char arr2[10] = "xxxxxx";
	printf("%s\n", my_strcat(arr1, arr2));
	return 0;
}

4.strcmp

4.1 介绍

int strcmp(const char* str1, const char* str2)
规则:依次比较字符串中字符的大小(ASCII),直到比出来一个大小不同或者两个字符串同时结束(\0),如果str1<str2,则返回一个小于0的数,如果str1>str2,则返回一个大于0的数,如果结束(两个字符串都到’\0’也没比出来),则两个字符串相等,返回0

LBPH

4.2 strcmp函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcde";
	char arr2[] = "acdef";
	if (strcmp(arr1, arr2) > 0)
	{
		printf("arr1>arr2\n");
	}
	if (strcmp(arr1, arr2) == 0)
	{
		printf("arr1=arr2\n");
	}
	if (strcmp(arr1, arr2) < 0)
	{
		printf("arr1<arr2\n");
	}
	return 0;
}

4.3 模拟实现strcmp函数

#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1,const char* str2)
{
	assert(str1 && str2);
	while (1)
	{
		if (*str1 != *str2)
		{
			return *str1 - *str2;
		}
		else
		{
			if (str1 == '\0')
			{
				return 0;
			}
			str1++;
			str2++;
		}
	}
}
int main()
{
	char str1[] = "abcde";
	char str2[] = "acdef";
	printf("%d\n", my_strcmp(str1, str2));
	return 0;
}

5. strncpy

5.1 介绍

int strncpy(char* destination,const char* source,size_t num)
规则:拷贝源字符串前num个字符到目标空间,如果num大于源字符串字符个数,则多出来的补0(也就是’\0’)。

数仓建模

  • 其他与strcpy一样。

5.2 strncpy函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[10] = "abcde";
	printf("%s\n", strncpy(arr1, arr2,3));
	return 0;
}

5.3 模拟实现strncpy函数

#include <stdio.h>
char* my_strncpy(char* dest, char* src,int num)
{
	char* start = dest;
	while (num--)
	{
		*dest++ = *src++;
	} 
	return start;
}
int main()
{
	char dest[20] = "xxxxxxxxxxxxx";
	char src[16] = "abc";
	printf("%s\n", my_strncpy(dest, src,3));
	return 0;
}

6.strncat

6.1 介绍

char* strncat(char* destination, const char* source,size_t num)
规则:追加源字符串前num个字符到目标空间(从目标空间第一个\0开始追加)。如果num大于源字符串长度,最后也只会追加一个\0,然后停止,再多出来的num就没用了。

知识图谱

  • 其他与strcat一样。

6.2 strncat函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[20] = "abcde\0qqqqqqqqqqqq";
	char arr2[10] = "xxxxxx";
	printf("%s\n", strncat(arr, arr2,20));
	return 0;
}

6.3 模拟实现strncat函数

#include <stdio.h>
#include <assert.h>
char* my_strncat(char* dest, const char* src,int num)
{
	assert(dest && src);
	char* start = dest;

	while (*dest)
	{
		dest++;
	}
	while (num--)
	{
		*dest++ = *src;
		if (*src == '\0')
			return start;
		src++;
	}
	return start;

}
int main()
{
	char arr1[20] = "abcde\0qqqqqqq";
	char arr2[10] = "xxxxxx";
	printf("%s\n", my_strncat(arr1, arr2,20));
	return 0;
}

7.strncmp

7.1 介绍

int strncmp(const char* str1,const char* str2,size_t num)
规则:比较前num个数。

app

  • 其他与strcmp一样。

8.strstr

8.1 介绍

char* strstr(const char* str1,const char* str2)
规则:查找str1中是否含有str2这个字符串。

脱壳

  • 返回值:如果出现,返回str2在str1中第一次出现的地址。如果没有出现(str1中找不到str2),则返回空指针(NULL)。

8.2 strstr函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	char* p = strstr(arr1, arr2);
	if (p != NULL)
		printf("在arr1中出现过");
	else
		printf("在arr2中没出现过");

	return 0;
}

8.3 模拟实现strstr函数

#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1,const char* str2)
{
	assert(str1);
	if (str2 == '\0')
		return str1;//特殊情况,如果srt2首字符就是\0,那么返回str1的首元素地址。
	while (1)//不会一直循环,因为根据下面的代码:发现str1包含str2就会返回str2在str1中出现的位置,如果没有,等到str1走到\0就会返回空指针。
	{
		char* s1 = str1;//创建目的:使每次循环str1可以前进一个字符的位置。
		char* s2 = str2;//创建目的:每次判断玩可以使str2回到原来首字符的位置。

		while (*s1 == *s2)
		{
			if (*s1 == '\0')
				return str1;//两个同时结束
			s1++;
			s2++;
		}
		if (*s2 == '\0')//str2结束,str1没结束,也就是说str2在str1内
		{
			return str1;
		}
		str1++;//str1和str2不相等,让str1向前进一个字符,重新进入循环判断
		if (*str1 == '\0')
		{
			return NULL;//str1在下次循环时已经为\0了,也就是说str1已经走到头了,还是没能找到str2,结束循环,返回空指针
		}
	}

}
int main()
{   
	char arr1[] = "aabcde";
	char arr2[] = "abcd";
	char* p = my_strstr(arr1, arr2);
	if (p != NULL)
		printf("在arr1中出现过");
	else
		printf("在arr2中没出现过");
	return 0;
}

9.strtok

9.1 介绍

char* strtok(char* str, const char* sep)
规则:sep参数是个字符串,定义了用作分隔符的字符集合,也就是当字符串str中出现字符串sep中包含的字符时,会分割以下。
使用方法:分割一个字符串时,第一次第一个参数传这个字符串的首元素地址,之后第一个参数都传空指针。strtok函数会自己实现怎么找到标记后的位置(所以创造者在创造strtok函数时使用了静态局部变量,每次使用完这个函数通过静态局部变量使标记后的位置不会被销毁,以便下次使用)。

微信小程序下载

  • 返回值:当发现分割符后,就会返回本次判断的首字符地址。当分隔符第一次为\0时(\0也是分割符,因为sep是字符串,默认最后会加入\0。),还是返回本次判断的首字符地址,下次就会返回空指针(因为当是以\0分割时,也就意味着分割结束了)。
  • 注意点:
  1. 字符串sep中每个字符都代表分割符,是分隔符的字符集合,因为是字符串,所以最后会默认加上\0,\0是最后一个分隔符。
  2. 第一个参数str指定一个字符串,它包含了0个或多个由sep字符串中一个或者多个分隔符分割的标记。
  3. strtok函数找到str中的下一个标记(也就是分隔符),并将其用\0结尾(也就是把这个标记符改为\0,即字符串的内容被修改了),返回一个指向这个标记的指针。
  4. 因为每次的分隔符都会被修改为\0,所以str指向的这个字符串必须是变量,而不能是字符串常量。
  5. strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  6. strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  7. 如果字符串不存在更多的标记,则返回NULL指针(也就是当标记为\0之后再使用strtok函数就会返回空指针,除非传入另一个字符串)。

9.2 strtok函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "abc@bc.d";
	char p[] = "@.";
	char* a = NULL;//指针不用时赋上空指针比较安全
	for (a = strtok(arr, p);a!=NULL;a=strtok(NULL,p))
	{
		printf("%s\n", a);
	}
	return 0; 
}

10.strerror

10.1 介绍

char* strerror(int errnum)
头文件 <errno.h>
规则:首先要知道errno是一个全局变量,每当库函数使用出错时,程序会将出错的情况对应的错误码赋给errno(每次出错都会赋一次),strerror函数会根据错误码将错误码指向的错误情况的首元素地址返回。每一个项目都会有自己的一套错误码对应的错误信息,目的就是让我们直到当代码出错时具体是哪方面出错了。

制造

10.2 扩展

perror函数(与strerror类似)
void perror(const char* str)
对应头文件为<stdio.h>
perror是直接打印错误信息,在打印错误信息前,会先打印自定义信息(然后会自己寻找errnum里的错误码将其变为对应的错误信息打印出来)。它会先打印出str指向的字符串,然后加上一个冒号和空格,然后打印错误信息。如果str指向的是空指针,那么就不再打印自定义信息,会直接打印错误信息。

微信小程序组件

10.3 注意

  1. 要及时去运用这些函数,因为每次的错误信息(错误码)会覆盖掉上一次的错误码。
  2. perror不一定比strerror好,因为perror只能打印出错误信息,而strerror是返回返回错误信息的首元素地址。具体视情况而定。
  3. strerror用时一般写成strerror(errno),errno不用自己定义,头文件自带的,但是要包含对应头文件<errno.h>,每次库函数出现错误,都会自动讲错误码赋到全局变量errno里。

二、字符函数

1.字符分类函数

  • 为真返回非0,为假返回0

这些函数里面的参数可以是字符也可以是整型,因为字符最终也会转为整型再被识别。

ganache

1.iscntrl 任何控制字符。
2.isspace 空白字符:空格(‘ ’),换页(‘\f’),回车(‘\n’),制表符(‘\t’)或者垂直制表符(‘\v’)。
3.isdigit 十进制的数字字符(0~9)。
4.isxdigit 十六进制数字字符(字母可以是大小写的a~f)。
5.islower 小写字母a~z。
6.isupper 大写字母A~Z。
7.isalpha 所有大小写字母。
8.isalnum 所有字母或者数字字符。
9.ispunct 标点符号及任何不属于数字字符或者字母的图形字符(可打印)。
10.isgraph 任何图形字符(数字和字母也算),必须为可打印出来图形的字符,比如数字0,1,2等对应的打印不出来的不是。
11.isprint 任何可打印字符,包括图形字符和空白字符。

unix

2.字符转换函数

字符转换函数
头文件也为<stype.h>

exe

  • 返回值:如果有对应的大小写,返回值为转换后的ASCII值,否则为该字符的ASCII值。

int tolower(int c)
int toupper(int c)
传字符和整型一样,不过多了一个把字符转换为整型的步骤。

vant

三、内存函数

  • 对应头文件都是<string.h>
  • 因为没有指定特定的类型,所以修改以字节为单位,传的参数需要用无符号指针接收,返回值也是无符号型,在用时强转。

1.memcpy

1.1 介绍

当我们把目光不只针对字符串,那么数据内存的拷贝就又需要新的库函数来实现,这时候我们便知道了memcpy函数。

jdk安装

void* memcpy(void* destination,const void* source,size_t num)
规则:将源字符串前num字节拷贝到目标空间。

网络协议

返回值:返回目的空间的首元素地址。
注意点:

抽象类与多态

  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  2. 这个函数遇到\0不会停下。
  3. 该函数不能用于内存重叠(因为可能重叠部分还没赋值就被替换掉了)。
  4. 是以字节为单位的。

1.2 memcpy函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[20] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	memcpy(arr1, arr2, 20);
	for (int i = 0; i < 4; i++)
		printf("%d", arr1[i]);
	return 0;
}

1.3 模拟实现memcpy函数

#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest,const void* src,size_t num)
{
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;	
		src = (char*)src + 1;
	}
}
int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	my_memcpy(arr1, arr2, 20);
	for (int i = 0; i < 4; i++)
		printf("%d\0", arr1[i]);
	return 0;
}

2.memmove

2.1介绍

前面提到memcpy的前两个参数不能有重叠部分,那么当有重叠部分时应该怎么办呢,这时候我们就要认识以下memmove函数了。

音乐系统网站

void* memmove (void* destination, const void* source, size_t num)
规则:和memcpy一样,不过应用更广泛,因为也可以实现两个空间有重叠部分时的拷贝。

tornado

2.2 memmove函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	memmove(arr, arr+2,12);
	return 0;
}

2.3 模拟实现memmove函数

  • 先看一下重叠部分的解析图
    请添加图片描述
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest,const void* src, size_t num)
{
	assert(dest && src);
	if (dest > src)//从后向前
	{
		while (num--)
		{
			*((char*)dest+num) = *((char*)src+num);
		}
	}
	else//从前向后
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
}
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	my_memmove(arr, arr+2,12);
	return 0;
}

3.memcmp

  • 介绍

int memcmp( const void* ptr1, const void* ptr2, size_t num)
规则:比较前num个字节,若发现ptr1>ptr2返回大于0整型,ptr1<ptr2返回小于0整型,如果前num字节都相等,返回0

远程调试

4.memset

  • 介绍

void* memset( void* ptr, int value, size_t num)
规则:将ptr指向的空间前num个字节都改为整型value

  • 注意点:
  1. value也可以是字符,因为字符进入计算机被识别也是通过转换成ASCII码值(整型)。
  2. 是以字节为单位,而不是某个类型的字节大小。

四、总结

在这里插入图片描述

💘原创不易,还希望各位佬佬支持一下

\textcolor{colourful}{💘原创不易,还希望各位佬佬支持一下}

💘原创不易,还希望各位佬佬支持一下

💓点赞,你的认可是我创作的动力!

\textcolor{red}{💓点赞,你的认可是我创作的动力!}

💓点赞,你的认可是我创作的动力!

💕收藏,你的青睐是我努力的方向!

\textcolor{orange}{💕收藏,你的青睐是我努力的方向!}

💕收藏,你的青睐是我努力的方向!

💞评论,你的意见是我进步的财富!

\textcolor{aqua}{💞评论,你的意见是我进步的财富!}

💞评论,你的意见是我进步的财富!

✨✨请点击下面关注大魔王✨✨
❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥大魔王.❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注