C语言常用字符串函数

专栏:C语言
每日一句:别在乎别人的目光,自己只管一心走路。熬过去,你就能看到柳暗花明,熬过去,你就能看到雨后彩虹,熬过去,你就能看到动人风景。


前言

本文重点介绍处理字符和字符串库函数的使用和注意事项

在这里插入图片描述

文章中的函数介绍图片来源于cplusplus.com

一、求字符串长度:strlen

1.strlen的简单介绍

在这里插入图片描述
strlen函数的作用是求字符串长度

size_t strlen(const char *str);

字符串是已‘\0'作为结束标志,strlen函数返回的是在字符串中出现在'\0'之前的有效字符的个数。
参数str指向的字符串必须要以'\0'作为结束标志
注意函数的返回值为size_t,size_t是无符号的
在这里插入图片描述

2.strlen的模拟实现

在这里,给大家介绍三种实现方式

2.1利用指针-指针实现

前面介绍过,指针-指针得到的是元素之间的个数,利用这个原理,就能实现strlen

#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
    
    
	assert(str);
	const char* st = str;记录str的起始地址
	while (*++str);
	return str - st;
}
int main()
{
    
    
	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述

2.2利用递归实现

如果*str不为'\0'就可以return 1 + my_strlen(++str)这样每次都可以+1,直到遇到字符串的结束标志'\0',结束递归。

#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
    
    
	assert(str);
	if (*str)
	{
    
    
		return 1 + my_strlen(++str);
	}
	else
	{
    
    
		return 0;
	}
}

int main()
{
    
    
	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述

2.3利用循环实现

利用循环实现很简单,循环只要不遇到'\0',就继续循环。

#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
    
    
	assert(str);
	int cnt = 0;
	while (*str)
	{
    
    
		cnt++;
		str++;
	}
	return cnt;
}

int main()
{
    
    
	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述

二、拷贝字符串strcpy和strncpy

1.strcpy的介绍

在这里插入图片描述

char* strcpy(char* destination, const char* source);

源字符串必须以'\0'为结束标志
会将源字符串中的'\0'拷贝到目标空间
目标空间必须足够大,以确保能够存放源字符串
目标空间必须可变

1.1strcpy的模拟实现

#include <stdio.h>
#include <assert.h>

char* my_strcpy(char* str1, const char* arr2)
{
    
    
	assert(str1 && arr2);
	char* ret = str1;
	while (*str1++ = *arr2++);
	return ret;
}

int main()
{
    
    
	char str1[20] = "";
	const char arr2[] = "h h x x";
	my_strcpy(str1, arr2);
	printf("%s", str1);
	return 0;
}

在这里插入图片描述

注:strcpy的返回值是目标字符串的起始地址

2.strncpy的简单介绍

在这里插入图片描述

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

拷贝num个字符从源字符串到目标字符串中
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标字符串的后面追加0,直到够num个为止

在这里插入图片描述

三、连接字符串strcat和strncat

1.strcat的简单介绍

在这里插入图片描述

char * strcat ( char * destination, const char * source );

源字符串必须以'\0'为结束标志
目标空间必须足够大,以确保能够容纳源字符串的内容
目标空间必须可变

1.1strcat模拟实现

要模拟实现strcat,需要先找到目标字符串的尾,也就是’\0’的位置,然后让源字符串的内容连接在目标字符串后面即可

#include <stdio.h>
#include <assert.h>

char* my_strcat(char* arr, const char* str)
{
    
    
	assert(arr && str);
	char* ret = arr;
	while (*++arr);
	
	while (*arr++ = *str++);
	return ret;
}

int main()
{
    
    
	char arr[20] = "hao hao";
	const char str[10] = " xue xi";
	my_strcat(arr, str);
	printf("%s", arr);
	return 0;
}

在这里插入图片描述

2.strncat的简单介绍

在这里插入图片描述

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

如果源字符串的长度小于 num,则仅复制源字符串的结束标志之前的内容。

在这里插入图片描述

四、比较字符串strcmp和strncmp

1.strcmp的简单介绍

在这里插入图片描述

int strcmp ( const char * str1, const char * str2 );

这个strcmp是比较字符串的函数,但它并不是一串一串的比较,而是一个字符一个字符的比较。
如果str1 > str2 则返回 1
如果str1 = str2 则返回 0
如果srt1 < str2 则返回 -1

1.1strcmp的模拟实现

#include <stdio.h>
#include <assert.h>
#include <string.h>
int my_strcmp(const char* arr, const char* str)
{
    
    
	assert(arr && str);
	
	while (*arr == *str)
	{
    
    
		if (!*arr)
		{
    
    
			return 0;
		}
		arr++;
		str++;
	}

	if (*arr > *str)
	{
    
    
		return 1;
	}
	else
	{
    
    
		return -1;
	}
}

int main()
{
    
    
	char arr[20] = "ba";
	const char str[10] = "bd";
	int cmp = my_strcmp(arr, str);
	printf("%d\n%d", cmp, strcmp(arr, str));
	return 0;
}

在这里插入图片描述

2.strncmp的简单介绍

在这里插入图片描述

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

在这里,num是要比较的字符个数。

在这里插入图片描述

五、查找字符穿strstr

1.strstr的简单介绍

在这里插入图片描述

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

str2 中指定的整个字符序列在 str1 中首次出现的位置,如果序列在 str1 中不存在,则返回null 指针。

1.1strstr的模拟实现

#include <stdio.h>

int n, m;

int ne[20];

char* my_strstr(char* str, char* ch)
{
    
    
	for (int i = 2, j = 0; i <= n; i++)
	{
    
    
		while (j && str[i] != str[j + 1])
		{
    
    
			j = ne[j];
		}
		if (str[i] == str[j + 1])
		{
    
    
			j++;
		}
		ne[i] = j;
	}

	for (int i = 1, j = 0; i <= m; i++)
	{
    
    
		while (j && ch[i] != str[j + 1])
		{
    
    
			j = ne[j];
		}
		if (ch[i] == str[j + 1])
		{
    
    
			j++;
		}
		if (j == n)
		{
    
    
			return ch + i + 1 - n;
			break;
		}
	}
}

int main()
{
    
    
	char str[20], ch[20];
	scanf("%d%s%d%s", &n, (str + 1), &m, (ch + 1));
	printf("%s", my_strstr(str, ch));
	return 0;
}

在这里插入图片描述

六、错误信息strerror和perror

1.strerror的简单介绍

在这里插入图片描述

char * strerror ( int errnum );

返回错误码所对应的错误信息。

#include <stdio.h>
#include <string.h>

int main()
{
    
    
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));

	return 0;
}

在这里插入图片描述
这就是一些错误信息。

2.perror的简单介绍

在这里插入图片描述

void perror ( const char * str );

打印报错信息

#include <stdio.h>
#include <string.h>

int main()
{
    
    
	FILE* fp = fopen("Haifan.txt", "r");//这里并没有该文件
	if (fp == NULL)
	{
    
    
		perror("fp");
	}
	/*fclose(fp);
	fp = NULL;*/
	return 0;
}

在这里插入图片描述

七、内存函数memcpy,memmove和memset

1memcpy的简单介绍

在这里插入图片描述

void * memcpy ( void * destination, const void * source, size_t num );

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到’\0’的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。

1.1memcpy的模拟实现

#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* arr1, const void* arr2, size_t num)
{
    
    
	assert(arr1 && arr2);
	void* ret = arr1;
	while (num--)
	{
    
    
		*((char*)arr1) = *((char*)arr2);
		arr1 = (char*)arr1 + 1;
		arr2 = (char*)arr2 + 1;
	}
	return ret;
}

int main()
{
    
    
	int arr1[] = {
    
     1,2,3,4,5 };
	int arr2[5] = {
    
     0 };
	my_memcpy(arr1, arr2, 8);
	return 0;
 }

在这里插入图片描述

2.memmove的简单介绍

在这里插入图片描述

void * memmove ( void * destination, const void * source, size_t num );

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

2.1memmove的模拟实现

#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memmove(void* arr1, const void* arr2, size_t num)
{
    
    
	assert(arr1 && arr2);
	void* ret = arr1;
	if (arr1 < arr2)
	{
    
    
		while (num--)
		{
    
    
			*((char*)arr1) = *((char*)arr2);
			arr1 = (char*)arr1 + 1;
			arr2 = (char*)arr2 + 1;
		}
	}
	else
	{
    
    
		while (num--)
		{
    
    
			*((char*)arr1 + num) = *((char*)arr2 + num);
		}
	}
	return ret;
}

int main()
{
    
    
	int arr1[] = {
    
     1,2,3,4,5 };
	my_memmove(arr1+1, arr1, 16);
	int arr2[] = {
    
     1,2,3,4,5 };
	memmove(arr2 + 1, arr2, 16);
	return 0;
}

在这里插入图片描述

3.memset的简单介绍

在这里插入图片描述

void * memset ( void * ptr, int value, size_t num );

这个函数是对ptr按字节把ptr每一个字节初始化成value,一共是num个字节

#include <stdio.h>
#include <string.h>

int main()
{
    
    
	int arr[5] = {
    
     0 };
	memset(arr, 0x3f, sizeof(arr));
	return 0;
}

在这里插入图片描述
在这里插入图片描述
这样,就能把arr的每个字节变成了0x3f

总结

以上是对常用字符串函数的总结,希望对大家有所帮助。

猜你喜欢

转载自blog.csdn.net/weixin_73888239/article/details/128620952