介绍一些处理字符串和内存的函数


前言

内存操作和字符串操作是C语言中很独特的地方
如果要控制内存里面的内容或者改变字符串的内容,能用哪些库函数来完成这些任务呢?


模板填写
调用名(小名): , 原名:
功能:
声明:
实现:
调用
注意

字符串

字符串不知道长度版本

最重要要的特性就是,字符串结尾是 ‘\0’

统计字符串长度

调用名(小名): strlen , 原名: string length
功能:统计字符串 0 前的字符个数
声明:

size_t strlen(const char *str);

实现:

size_t my_strlen(const char*str)
{
	assert(str != NULL );
	char * start = str;
	char * end = str;
	while(*end)
	{
		end++;
	}
	return end - str;
}

注意

  1. strlen 的返回值是 size_t ,是 unsigned int ,所以在运算时永远是正数
  2. 有多种实现方式,可以自己尝试

字符串复制

调用名(小名) strcpy , 原名 string copy
功能; 将字符串 A 拷贝到 字符串 B 中
声明:

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

实现:

char* my_strcpy(char* dest,const char* source)
{
	assert(dest != NULL && source != NULL);
	char * ret = dest;
	while(*dest++ = *source++)
	{
		;
	}
	return ret;
}

使用

int main()
{
	char a[20] = "I LOVE CHINA";
	char b[20] = "###############";
	printf("%s\n",strcpy(b,a));
	return 0;
}

注意

  1. 目标空间要大
  2. source 数组要以 0 结尾
  3. 拷贝后dest 的 0 来源于 source

字符串比较

调用名(小名): , strcmp 原名:string compare
功能:
比较字符串中每一个字符的asc 码,找到第一个不同,如果第一个大,返回大于0 的数,如果第一个小,然后小于0的数,完全相等返回0
声明:

int strcmp(const char* first,const char* sec);

实现:

int strcmp(const char* first,const char* sec)
{
	assert((first != NULL) && (sec != NULL));
	//相等的略过
	while(*first == *sec)
	{
		if(*sec == 0)
			{
				return 0;
			}
		else
		{
			first ++ ;
			sec ++ ;
		}
	}
	//不相等的比较
	return *first - * sec;
}

注意

  1. 返回的不一定是 1 0 -1 ,是大于0 0 和小于0的数
  2. 实现逻辑就是 找到第一个不同的数 比较 asc码值

字符串追加

调用名(小名): strcat , 原名: string catch
功能:
在一个字符串数组后面追加另一个数组
声明:

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

实现:

(char*) strcat(char* dest, const char* source)
{
	assert(dest != NULL && source != NULL)
	char* ret = dest;
	while(*dest)
	{
		dest++;
	}
	while(*dest++ = *source++)
	{
		;
	}
	return ret ;
}

注意:

  1. 不能实现自追加,因为追加会影响数组本身的内容

字符串切割

调用名(小名):strtok , 原名:split str into tokens
功能:
按照一些符号切分数组,如果返回 NULL说明切分完毕
声明:

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

调用:

#define _CRT_SECURE_NO_WARNINGS 1
#include<string.h>
#include<stdio.h>
int main() {
	char a[] = "carry@163.com";
	char b[] = "@.";
	char* str = NULL;
	for (str = strtok(a, b); str != NULL; str = strtok(NULL, b))
	{
		printf("%s\n", str);
	}
	return 0;
}

结果:
在这里插入图片描述

注意

  1. 如果要对一个字符串数组切除多次,除了第一次传入要切割的数组 str ,之后形参位置 str 只要填入 NULL, strtok 会在当前的 str 一直切除下去
  2. strtok 有记忆性,形参 str 位置传入 NULL时启用
  3. 切除数组的方式就是加入 \0

字符串给了长度版本

复制

调用名(小名):strncpy
功能:
将 source 数组的 n 个字符串复制到 dest 上,如果 n > source 的长度,其余处补0
声明:

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

调用

int main()
{
	char a[20] = "i love china";
	char b[20] = "###########";
	printf("%s\n",strncpy(b,a,6));
}

在这里插入图片描述
注意

  1. source 不足时 这个函数会一直补 0

追加

调用名(小名): strncat
功能:
在 dest 数组后追加 n 个字符
声明:

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

调用:

#define _CRT_SECURE_NO_WARNINGS 1
#include<string.h>
#include<stdio.h>
int main() {
	char a[20] = "i love china";
	char b[20] = "###########";
	//printf("%s\n", strncpy(b, a, 6));
	printf("%s\n", strncat(b,a,6));
	
	return 0;
}

在这里插入图片描述

注意

  1. 这个可以用来自追加,因为会自动补0

比较

调用名(小名): strncmp
功能:
比较两个字符串的前 n 项
声明:

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

调用:

int main()
{
	char a[] = "i am your father";
	char b[] = "i am not your father";
	int ret = strncmp(a,b,10);
	if(ret == 0)
	{
		printf("两个字符串相同");
	}
	else
	{
		printf("两个字符串不同");
	}
	return 0;
}

寻找子串

调用名(小名): strstr
功能:

在字符串 a 中找到字符串 b
找到,返回第一次出现子字符串的地址
没找到返回 NULL 指针

声明:

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

实现:
思路:设立一个指针 str 记录子串在被寻字符串的起始位置,如果首字符和子串一样
就分离出一个新的地址,一直向下比,直到比到子串结束都一样,就返回 str

char* my_strstr(const char* str1,const char* str2)
{
	char * p = NULL;
	char*  q = NULL;
	while(*str1)
	{
		//第一个数相等
		if(*str1 == *str2 && *str2 != 0 )
		{
			//储存子串开始的地方
			p = str1;
			q = str2;
			while(*str1 == *str2)
			{
				str1++;
				str2++;
			}
			if(*str2 == 0)
			{
				return p;
			}
			//找到了不同,而且不是0
			else
			{
				p++;
				str1 = p;
				str2 = q;
			}
		}
		else
		{
			str1++;
		}
	}
	return NULL;
}

调用

int main()
{
	char a[20] = "abbbcdef";
	char b[20] = "bbb";
	char* ret = my_strstr(a, b);
	if (ret == NULL)
	{
		printf("没找到");
	}
	else
	{
		printf("%s",ret);
	}
	return 0;
}

对错误码的操作

调用名(小名): , 原名: strerror
功能:
每次出现错误时, 每种错误会储存在一个全局变量 errno 中
随后,用 strerror(errno) 可以直接打印出错误
声明:

char * strerror ( int errnum );

调用

int main()
{
	dosomething();
	//如果出现了错误
	printf ("Error opening file unexist.ent: %s\n",strerror(errno));
	//可以看到错误
}

注意

内存操作

内存复制

调用名(小名): memcpy,原名: memory copy
功能:

直接操作内存里头,然后把一个数组的 n 个字节复制到另一个数组

声明:

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

实现:

void* my_memcpy (void* dest,const void* source,size_t num)
{
	char * ret = dest;
	while(num--)
	{
		*(char*)dest = *(char*)source;
		dest = (char*)dest+1;
		source = (char*) source+1;
	}
	return ret;
}

调用
和 strcpy 是一样的
注意

  1. 实现的时候 dest ++ 和 source ++ 是容易出问题的
  2. 这种写法 是不能实现自 copy的,但是VS的写法不是这种写法,是 memmove的写法

内存移动

调用名(小名): memmove
功能:

不仅能够实现 memcpy 还能够实现 数组的一部分在数组内移动
在这里插入图片描述

声明:

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

实现:

void* memmove(void* dest,const void* source,size_t num)
{
	char * ret = dest;
	while(num -- )
	{
		// source 在前,从后向前复制
		if(dest > source)
		{
			*((char*)(dest)+num) = *((char*)(source)+num);
		}
		//source 在后,从前向后赋值
		else
		{
			*(char*)dest = *(char*)source;
			dest = (char*) dest + 1;
			source = (char*) source + 1;
		}
	}
	return ret;
}

调用

int main()
{
	char a[20] = "abbbcdef";
	char b[20] = "bbb";
	char* ret = my_memmove(a+2, a, 4);
	printf("%s", ret);
	
}

注意

  1. 部分编译器 memcpy 有 memmove的功能,但是有些是没有的,不要瞎用
  2. 实现过程要分一下情况

总结

  1. 在做字符串的题目时,可以尝试使用字符串函数
  2. 复制追加都需要保证 dest 函数足够大
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值