【C】字符串和内存操作函数的使用及模拟实现

目录

🎈字符串函数

strlen

strcpy

strncpy

strcat

strncat

strcmp

strncmp

strstr

strtok

strerror

perror

字符分类函数

字符转换函数

tolower  

toupper

🎈内存操作函数

memcpy

memmove

memcmp

memset


本文和大家分享一些C语言中常用的字符串和内存处理函数的使用,以及如何去模拟实现

🎈字符串函数

使用字符串函数需要引用头文件  #include<string.h>

strlen

size_t  strlen(const  char*  str);     求字符串长度

· 字符串以'\0'作为结束标志,strlen返回的是'\0'前面的字符个数(不包括'\0')

· 返回值是无符号整数

使用:

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

int main()
{
    char arr[] = "hello world";
    int ret = strlen(arr); //传入首元素地址
    printf("%d\n", ret);   //打印11
    return 0;
}

模拟实现:

#include<stdio.h>

unsigned_int my_strlen(char* str)
{
    int count = 0;
    while (*str++ != '\0')
    {  
        count++;
    }
    return count;
}

int main()
{
    char arr[] = "hello world";
    int ret = my_strlen(arr); //传入首元素地址
    printf("%d\n", ret);   //打印11
    return 0;
}
strcpy

char* strcpy(char* destination, const char* source);      字符串拷贝函数

· 源字符串必须以'\0'结尾,会将'\0'拷贝到目标空间里

· 目标空间必须足够大

· 目标空间必须可变

使用:

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

int main()
{
	char arr1[10] = "xxxxxxxxxx";
	char arr2[] = "wwx";
    char* ret = strcpy(arr1, arr2);
    //返回目标空间的首元素地址
	printf("%s", ret);
	return 0;
}

模拟实现:

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

char*  my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++)
	{//dest为'\0'时,退出循环
		;
	}
	return ret;//返回目标空间的起始地址
}          

int main()
{
	char arr1[10] = "xxxxxxxxxx";
	char arr2[] = "wwx";
	printf("%s", my_strcpy(arr1, arr2));
	return 0;
}
strncpy

char* strcpy(char* destination, const char* source, unsigned int count); 

与strcpy用法相同,是可以控制长度的字符串拷贝函数

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

int main()
{
	char str1[] = "To be or not to be";
	char str2[40];
	char str3[40];
	strncpy(str2, str1, sizeof(str2));
	strncpy(str3, str2, 5);
	str3[5] = '\0'; //复制了前五个后添加终止符号
	puts(str1);//To be or not to be
	puts(str2);//To be or not to be
	puts(str3);//To be
	return 0;
}
strcat

char *strcat( char *Destination, const char *Source );      字符串追加函数

使用:

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

int main()
{
    char a[10] = "ABCDE";//要注意开辟足够的空间
	strcat(a, "FGH");    //从最后一个地址开始,源字符串必须要有\0
	printf("%s", a);     //输出ABCDEFGH    最好不要自己追加自己
	return 0; 
}

模拟实现:

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

char* my_strcat(char* dest, const char* source)
{
	assert(dest && source);
	char* ret = dest;//储存目标空间的起始地址
	while (*dest != '\0')
	{//使目标指针指向\0
		dest++;
	}
	while (*dest++ = *source++)
	{//从\0开始追加,循环跳出说明源字符串'\0'追加完成
		;
	}
	return ret;//返回目标空间的起始地址
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[6] = "world";
	char* ret = my_strcat(arr1, arr2);
	printf("%s", ret);
	return 0;
}
strncat

char *strncat( char *Dest, const char *Source, size_t count );   可控长度的追加函数

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

int main()
{
    char a[10] = "ABCDE";//要注意开辟足够的空间
	strncat(a, "FGHJKL", 3);    //追加三个字符
	printf("%s", a);     //输出ABCDEFGH    
	return 0; 
}
strcmp

int strcmp( const char *str1, const char *str2 );     字符串比较函数

· 比较的是相对应字符的ASCII码值

· str1大于str2,返回大于0的值,反之返回小于0的值,相等返回0

使用:

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

int main()
{
	char arr1[] = "abcf";
	char arr2[] = "abcde";
	int ret = strcmp(arr1, arr2);
	if (ret == 0)
	{
		printf("arr1==arr2");
	}
	else if (ret > 0)
	{//输出
		printf("arr1 > arr2");
	}
	else
	{
		printf("arr1 < arr2");
	}
	return 0;
}

模拟实现:

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

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 != '\0')
	{//遍历其中一个字符串
		int ret = *str1 - *str2;
        //对应的每一个字符相减
		if (ret != 0)
		{//不为零时直接返回
			return ret;
		}
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char arr1[] = "abcf";
	char arr2[] = "abcde";
	int ret = my_strcmp(arr1, arr2);
	if (ret == 0)
	{
		printf("arr1==arr2");
	}
	else if (ret > 0)
	{
		printf("arr1 > arr2");
	}
	else
	{
		printf("arr1 < arr2");
	}
	return 0;
}
strncmp

int strncmp( const char *str1, const char *str2, size_t count );    可控长度的比较

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

int main()
{
	char arr1[] = "abcf";
	char arr2[] = "abcde";
	int ret = strncmp(arr1, arr2, 2);
    //比较前两个字符
	if (ret == 0)
	{
		printf("arr1==arr2");
	}
	else if (ret > 0)
	{
		printf("arr1 > arr2");
	}
	else
	{
		printf("arr1 < arr2");
	}
	return 0;
}
strstr

char *strstr( const char *str, const char *strson );       在str中寻找子字符串

使用:

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

int main()
{
	char arr1[] = "acdbcdefgh";
	char arr2[] = "defgh";
	char* ret = strstr(arr1, arr2);
    //在arr1中是否能找到arr2
	if (ret == NULL)
	{//找不到返回NULL
		printf("找不到!\n");
	}
	else
	{//找到则返回母串与子串对应的首字符地址
		printf("找到了!%s\n", ret);
	}
	return 0;
}

模拟实现:

#include<stdio.h>

char* my_strstr(const char* str1, const char* str2)
{//模拟实现
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cp = str1;
	if (*str2 == '\0')
	{//str2为空时
		return str1;
	}
	while (cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{//同为\0时,不加以上条件,可能导致越界访问
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{//说明\0之前的字符相同
			return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "acdbcdefgh";
	char arr2[] = "defgh";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{//找不到返回NULL
		printf("找不到!\n");
	}
	else
	{//找到则返回母串与子串对应的首字符地址
		printf("找到了!%s\n", ret);
	}
	return 0;
}
strtok

char *strtok( char *str, const char *strDelimit );    字符串切割函数

· 将str以 strDelimit中的分隔符切割开来

使用:

#include<stdio.h>

int main()
{
	char arr1[] = "18870251842@163.com";
	char p[] = "@.";
    //将字符串内得到分隔符放在p内
	char arr2[30] = { 0 };
	strcpy(arr2, arr1);          
	//一般会拷贝一个字符串用来切割
	char* ret = NULL;
	for (ret = strtok(arr2, p); ret != NULL; ret = strtok(NULL, p))
	{//使用循环,减少代码冗余
		printf("%s\n", ret);
	}
	//ret = strtok(arr2, p); //18870251842
	//会找到第一个分隔符,将其替换为\0,记录位置,返回首字符地址
	
	//ret = strtok(NULL, p); //163
	//找到下一个分隔符,将其替换,并记录位置,返回记录位置的下一个位置地址,
	
	//ret = strtok(NULL, p); //com
	//同样,遇到\0函数结束,不可以使用\0作为分割字符,返回记录位置的下一个位置地址
	return 0;
}
strerror

char *strerror( int errno);       翻译错误信息

使用:

//库函数使用错误时,都会设置错误码
//只要调用库函数发生错误,就会将错误码放到 全局变量 errno 中
#include<stdio.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{//文件打开失败,设置错误码
		printf("%s", strerror(errno)); //打印翻译的错误信息
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

部分错误信息表

perror

void perror( const char *string );            翻译并打印错误信息

字符分类函数

引用头文件  #include<ctype.h>

	char a = '1';
	int ret = islower(a);
	printf("%d\n", ret); //0
字符转换函数
tolower  

int tolower( int c );           转化为小写字符

toupper

int toupper( int c );           转化为大写字符

	char arr[20] = { 0 };
	scanf("%s", arr);
	int i = 0;
	while (arr[i] != '\0')
	{
		if (isupper(arr[i]) == 1)
		{//是大写就转换为小写字符
			arr[i] = tolower(arr[i]);
		}
		printf("%c ", arr[i]); 
		i++;
	}

🎈内存操作函数

需要引用头文件 #include<string.h>

memcpy

void *memcpy( void *dest, const void *src, size_t count );    内存拷贝函数

· 用来进行不重叠内存的拷贝

使用:

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

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 40);
    //传入目标地址和源地址,拷贝的单位是字节
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

内存重叠时不要使用memcpy函数

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

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]); //1 2 1 2 1 2 1 8 9 10 
        //不能保证所有的编译器都可以
	}
	return 0;
}

模拟实现:

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

void* my_memcpy(void* dest, const void* sou, int num)
{
	void* ret = (char*)dest;
	while (num--)
	{
		 *((char*)dest)++ = *((char*)src)++;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 40);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}
memmove

void *memmove( void *dest, const void *src, size_t count );    内存拷贝函数

· 功能与memcpy一样

· 可以处理内存重叠的情况

使用:

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

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]); // 1 2 1 2 3 4 5 8 9 10
	}
	return 0;
}

模拟实现:

#include<stdio.h>

void* my_memmove(void* dest, const void* sou, size_t num)
{
	void* ret = (char*)dest;
	if (dest < sou)
	{
		while (num--)
		{
            *((char*)dest)++ = *((char*)src)++;
		}
    	return ret;
	}
	else
	{
		while (num--)
		{//开始进入循环为20 再--  进入循环最小值为1,再--
			*((char*)dest + num) = *((char*)sou + num);
            //使用时num最小为0,最大为19
		}
     	return ret; 
	}
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1, arr1 + 2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]); // 1 2 1 2 3 4 5 8 9 10
	}
	return 0;
}
memcmp

int memcmp( const void *buf1, const void *buf2, size_t count );   内存比较函数

使用:

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

int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[] = { 1,2,3,260,5 };
	int ret = memcmp(arr1, arr2, 14); //比较的单位是字节
	printf("%d\n", ret);  //arr1>arr2,返回1,反之返回-1,相等返回0
	return 0;
}

模拟实现:

#include<stdio.h>

int my_memcmp(const void* p1, const void* p2, unsigned int num)
{
	while (num--)
	{
		int ret = *((char*)p1)++ - *((char*)p2)++;
		if (ret != 0)
		{
			return ret;
		}
	}
	return 0;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[] = { 1,2,3,260,5 };
	int ret = my_memcmp(arr1, arr2, 20);
	printf("%d\n", ret); 
	return 0;
}
memset

void *memset( void *dest, int c, size_t count );         内存设置函数

· 将从目标地址开始的count个字节设置为c

使用:

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

int main()
{
	char arr[] = "XXXXXXXXXXXXXXX";
	char* ret = memset(arr, 'a', 5);
	printf("%s\n", ret);
	return 0;
}

模拟实现:

#include<stdio.h>

void* my_memset(void* dest, int c, unsigned int num)
{
	void* ret = dest;
	while (num--)
	{
		*((char*)dest)++ = c;
	}
	return ret;
}

int main()
{
	char arr[] = "XXXXXXXXXXXXXXX";
	char* ret = my_memset(arr, 'a', 5);
	printf("%s\n", ret);
	return 0;
}

这里介绍一些常用的函数,如果想要深入了解可以在C/CPP官方网站查看,感谢支持❤️❤️❤️

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值