c的字符串函数以及内存操作函数

在c语言中谈论字符串

一、存储:c语言中没有字符串类型,所以用char *类型的指针变量指向或者用字符指针存放字符串;
二、 '\0':字符串 默认以'\0'结尾,若是不写,编译器会默认加上;
        所以存放字符串的 数组大小应该是strlen+1;(eg:char arr[ ] = "abcd";此时数组的大小默认是4+1;);
三、 内存位置:当字符串是保存在指针变量时,在内存中字符串是被放在 字符常量区的,是 不可被修改的,而此时的 指针变量仅仅保存的是字符串的首元素字符的地址,若此时该指针变量是在代码块内部简单定义的,在内存中该指针变量是被保存在栈中的; 当字符串被保存在数组中时,字符串是充当数组元素被保存在数组中的,若此时数组是在代码块内部简单定义的,则此时在内存中,字符串就被保存在栈上可以被修改
函数使用:c语言中提供的字符串函数
1、strlen函数
     size_t strlen( const char * string );
     返回字符串长度(该字符串长度是无符号数):不包括'\0';
eg:该代码返回的结果为1。
char *str1 = "abcd";
char *str2 = "abc";
if(strlen(str2) - strlen(str1) > 0){
     return 1;
}
else{
     return 0;
}

因:strlen函数返回值为无符号数,所以无符号数减去无符号数永远是无符号数,所以此处的条件判断永远为真。

2、strcpy函数
     char *strcpy( char * strDestination , const char * strSource );
    将源字符串整体拷贝给目标字符串,返回目标字符串:保证要将 源字符串的'\0'也复制给目标字符串。
3、 strncpy函数
     char *strncpy( char * strDest , const char * strSource , size_t count );
    将源字符串的count个字符拷贝给目标字符串,返回目标字符串:当源字符串的长度 与count相等,不会默认加'\0'。
4 、strcat函数
     char *strcat( char * strDestination , const char * strSource );
    将源字符串整体(包括'\0')拼接在目标字符串从'\0'开始的位置:不能自己给自己拼接,原因是:源字符串的'\0'已经被覆盖,不能结束。
5 strncat函数
     char *strncat( char * strDest , const char * strSource , size_t count );
    将源字符串的count个字符拼接在目标字符串从'\0'开始的位置:拼接完成后会默认加上'\0'。
6 、strstr函数
     char *strstr( const char * string , const char * strCharSet );
    寻找子串函数,返回一个指针,指向strCharSet在字符串中的第一次出现的位置。
7 、strcmp函数
     int strcmp( const char * string1, const char * string2 );
    比较两个字符串,返回1(string1>string2)、0(string1 == string2)、-1(string1 <string2)。
8 strncmp函数
     int strncmp( const char * string1 , const char * string2 , size_t count );
    比较两个字符串中count个字符,返回值同上。
9 、strchr函数
     char *strchr( const char * string , int c );
    在字符串中找字符,返回一个指针,指向字符串中第一次出现的c。
10、strrchr函数
     char *strrchr( const char * string , int c );
    从字符串右边开始找字符c,返回一个指针, 指向字符串中最后一次出现的c。
11、strpbrk函数
     char *strpbrk( const char * string , const char * strCharSet );
    字符串查找指定字符集中的字符,返回string中第一个出现在strCharSet中的字符的地址。
12、strpan函数
    size_t strspn( const char * string , const char * strCharSet );
    查找第一个子字符串,返回string中开始部分匹配strCharSet中字符的个数。
13、strcspn函数
     size_t strcspn( const char * string , const char * strCharSet );
    在字符串中查找子字符串,返回string中开始部分出现的不在strCharSet中的字符个数。
14、strtok函数
     char *strtok( char * strToken , const char * strDelimit );
    第一个参数:操作字符串;第二个参数:定义了用作分隔符的字符集合;
    功能:根据strDelimit分割字符串
    原理:找到下一个分隔符,并将其替换为'\0',结束此次分割;
    当第一个参数不为空时,函数将找到第一个分隔符,strtok函数将保存它在字符串中的位置;
    当第一个参数不为空时,函数将在同一个字符串中被保存的位置开始,查找下一个分隔
char str[] = " hello, my_word."
char *del = " ,_.";
char *split = strtok(str, del);
while(split != NULL){
    printf("%s\n",spilt);
    spilt = strtok(NULL, del);
}

出结果为:

hello
my
word
15、strerror函数  
     char *strerror( int errnum );
    返回错误码所对应的错误信息:erron,错误码(0:成功;非0:失败),全局变量。

内存操作函数
此类函数均是以字节操作。
1 、memcpy函数:字节拷贝函数
     void *memcpy( void *dest, const void *src, size_t count );
2 、memmov函数:字节拷贝函数
     void *memmove( void *dest, const void *src, size_t count );
     两个函数的区别见谈论c的memcpy与memmove函数
3、memset函数:按字节整体赋值函数
     void *memset( void *dest, int c, size_t count );
     第一个参数:目标内存地址;
     第二个参数:赋值;
    第三个参数:要赋值的内存大小(字节单位)。
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<Windows.h>


//模拟实现strlen的三种方式
//方式1:计数器方式
int my_strlen1(const char *str)
{
	int count = 0;
	while (*str){
		count++;
		str++;
	}
	return count;
}
//strlen的返回值为count:(是无符号数!!!)
//方式2:递归(不创建临时变量)
int my_strlen2(const char *str)
{
	if (!*str){
		return 0;
	}
	return 1 + my_strlen2(str + 1);
}
//方式3:指针-指针
int my_strlen3(const char *str)
{
	char *p = str;
	while (*p){
		p++;
	}
	return p - str;//尾-头
}

//模拟实现strcpy
char *my_strcpy(char *des, const char *src)
{
	assert(des);
	assert(src);//判断是否为空
	char *ret = des;
	while (*des = *src){//保证src的'\0'也被复制
		des++;
		src++;
	}
	return ret;//返回拷贝后的des
}

//模拟实现strncpy
//特点:当src_len == num时, 复制完成后不加'\0'
char *my_strncpy(char *des, const char *src, int num)
{
	assert(des);
	assert(src);
	char *ret = des;
	while (num--){
		*des = *src;
		des++;
		src++;
	}
	return ret;
}

//模拟实现strcat
//不可以自己拼接自己:从目标字符串的'\0'开始覆盖,所以结果是不会退出,因为源字符串已无'\0'
char *my_strcat(char *des, const char *src)
{
	assert(des);
	assert(src);
	char *ret = des;
	while (*des){//从des的'\0'开始复制
		des++;
	}
	while (*des = *src){
		des++;
		src++;
	}
	return ret;//返回拼接完成后的des
}

//模拟实现strncat
//特点:拼接完默认加'\0'
char *my_strncat(char *des, const char *src, int num)
{
	assert(des);
	assert(src);
	char *ret = des;
	while (*des){//从des的'\0'开始复制
		des++;
	}
	while ((num--) && (*des = *src)){
		des++;
		src++;
	}
	return ret;
}

//模拟实现strstr(子串查找)
char *my_strstr(const char *des, const char *src)
{
	assert(des);
	assert(src);
	char *d = (char *)des;
	char *ds = NULL;
	char *s = (char *)src;
	while (*d){//如果在此字符串des已经判断到了'\0',则退出,未找到子串
		ds = d;
		s = src;
		while (*s && *ds && *ds == *s){
			ds++;
			s++;
		}
		if (!*s){//如果在此*s == 0,则子串已找到
			return d;
		}
		if (!*ds){//如果在此*ds == 0,则des已经找完,未找到子串
			return NULL;
		}
		//走到这说明while循环是因为*ds!=*s跳出的
		d++;
	}
}

//模拟实现strcmp
int *my_strcmp(const char *src, const char *des)
{
	assert(des);
	assert(src);
	int ret = 0;
	while (!(ret = *(unsigned char *)src - *(unsigned char *)des) && *des){//将较大几率不成立的条件放置前面判断
		//此处判断条件,没有判断*src为空:(原因)当判断条件1成立时说明src和des相等,此时会去判断条件2
		//当条件2成立,则退出,此时代表ret == 0(也可以说明此时src == 0;(src-des == 0))
		src++;
		des++;
	}
	if (ret < 0){
		ret = -1;
	}
	else if (ret > 0){
		ret = 1;
	}
	else{
		ret = 0;
	}
	return ret;
}

//模拟实现strncmp
int *my_strncmp(const char *src, const char *des, int num)
{
	assert(des);
	assert(src);
	int ret = 0;
	while ((num--) && !(ret = *(unsigned char *)src - *(unsigned char *)des) && *des){
		src++;
		des++;
	}
	if (ret < 0){
		ret = -1;
	}
	else if (ret > 0){
		ret = 1;
	}
	else{
		ret = 0;
	}
	return ret;
}

//模拟实现strchr
//查找字符串s中首次出现字符c的位置
char *my_strchr(const char *str, char ch)
{
	assert(str);

	char *tmp = str;
	while (*tmp != '\0' && *tmp != ch){
		tmp++;
	}
	if (*tmp == ch){
		return tmp;
	}
	else{
		return NULL;
	}
}

//模拟实现memcpy:以字节位基本操作单位
//赋值数字节长度的内存;以空指针类型来接收
void *my_memcpy(void *des, const void *src, int size)
{
	//字节为单位:强转一个字节为单位的类型
	assert(des);
	assert(src);
	char *des_ch = (char *)des;
	unsigned char * src_ch = (unsigned char *)src;
	while (size){
		*des_ch = *src_ch;
		des_ch++, src_ch++;
		size--;
	}
	return des;
}

//模拟实现memmove
void *my_memmove(void *des, const void *src, int size)
{
	assert(des);
	assert(src);
	char *des_ch = (char *)des;
	unsigned char * src_ch = (unsigned char *)src;
	if (des_ch <= src_ch || des_ch >= src_ch + size){//类型完整才能进行指针运算
		//从前往后拷贝的情况
		while (size--){
			*des_ch = *src_ch;
			des_ch++, src_ch++;
		}
	}
	else{
		//从后向前拷贝的情况
		des_ch = des_ch + size - 1;
		src_ch = src_ch + size - 1;
		while (size--){
			*des_ch = *src_ch;
			des_ch++, src_ch++;
		}
	}
	return des;
}

int main()
{
	/*char *str = "anxsdfj12";
	printf("%d\n", my_strlen1(str));
	printf("%d\n", my_strlen2(str));
	printf("%d\n", my_strlen3(str));*/

	/*char *src = "qweasdz765";
	char des[20];
	printf("%s\n", my_strcpy(des, src));*/

	/*char *src = "abcd efgh 123";
	char des[15] = "zxcv asdf 456";
	printf("%s\n", my_strncpy(des, src, 13));*/

	/*char *src = "hjklg123";
	char des[20] = "asdf";
	printf("%s\n", my_strcat(des, src));*/

	/*char *src = "hjklg123";
	char des[12] = "asdf";
	printf("%s\n", my_strncat(des, src, 8));*/

	/*char *src = "asdf";
	char *des = "qwasuitasdfcxnz";
	printf("%s\n", my_strstr(des, src));*/

	/*char *src = "abcdefg";
	char *des = "abcdekg";
	printf("%d\n", my_strcmp(src, des));*/

	char *src = "abcdewg";
	char *des = "abcdekg";
	printf("%d\n", my_strncmp(src, des, 6));

	/*char *str = "safjqla";
	char ch = 'q';
	printf("%s\n", my_strchr(str, ch));*/

	//char src[10] = "qweasdz";
	//int size = strlen(src) + 1;
	//char des[20];

	printf("%s\n", my_memcpy(des, src, size));//打印结果:qweasdz
	printf("%s\n", my_memcpy(src, src + 1, size));//打印结果:weasdz
	printf("%s\n", my_memcpy(src + 1, src, size));//打印结果:qqqqqqqq

	printf("%s\n", my_memmove(des, src, size));//打印结果:qweasdz
	printf("%s\n", my_memmove(src, src + 1, size));//打印结果:weasdz
	printf("%s\n", my_memmove(src + 1, src, size));//打印结果:weasdz

	memcpy(des, src, size);
	printf("%s\n", src);//打印结果:qweasdz

	memcpy(src, src + 1, size);
	printf("%s\n", src);//打印结果:weasdz

	//memcpy(src + 1, src, size);//第5种情况
	//printf("%s\n", src);//结果为:qqweasdz

	//printf("%s\n", memmove(src + 1, src, size));//打印结果:qweasdz//说明:返回拷贝的值
	//memmove(des, src, size);
	//printf("%s\n", src);//打印结果:qweasdz

	//memmove(src, src + 1, size);
	//printf("%s\n", src);//打印结果:weasdz

	memmove(src + 1, src, size);//第5种情况
	printf("%s\n", src);//结果为:qqweasdz

	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值