字符串函数和内存操作函数


前言

C语言中对字符和字符串的处理非常频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数。


一、常用字符串函数

1.strlen

size_t strlen ( const char * str );

(1)字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含 ‘\0’ )。
(2)参数指向的字符串必须要以 ‘\0’ 结束。
(3)注意函数的返回值为size_t,是无符号的( 易错 )。

2.strcpy字符串拷贝

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

将source的字符串拷贝到destination中,对应空间上的会覆盖掉。
(1)源字符串必须以 ‘\0’ 结束。
(2)会将源字符串中的 ‘\0’ 拷贝到目标空间。
(3)目标空间必须足够大,以确保能存放源字符串。
(4)目标空间必须可变。
补充:
“目标空间足够大”由程序调用者保证,因此是不怎么靠谱的。C语言之后的编程语言不再是这样,类似的操作都支持自适应,自动扩容。

3.strcat字符串拼接

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

将source的字符串追加到destnation字符串的后面。
(1)源字符串必须以 ‘\0’ 结束。
(2)目标空间必须有足够的大,能容纳下源字符串的内容。
(3)目标空间必须可修改。

4.strcmp字符串比较

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

标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字

按照字典序进行比较。例如"zhangsan"和"lisi"两个字符串,比较第一个字母,‘z’的ASCII码大于’l’,则函数返回一个大于零的数字。若ASCII码相等,则继续比较下一个字母的ASCII码,直到一个字符串结束。如"abc"和"abcd",到’c’为止,均相等,那么较长的那个字符串较大。

5.strstr查找子串

char * strstr ( const char *, const char * )

例如:"llo"是“helloworld”的一个子串,若找到子串,strstr函数返回一个指向子串位置的指针;若没找到,则返回空指针NULL。

6.strtok字符串切分

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

字符串切分是一个实际开发中非常高频使用的功能。
例如,若想切分以下字符串:
在这里插入图片描述

p = strtok(str," ");

第一次调用,参数传了str,strtok会从str位置开始往后找,找到空格符之后,就会把这个位置改成’\0’,同时记录这个位置,最后返回起始位置(指向I的指针)。

p = strtok(NULL," ");

第二次调用,参数传了NULL,表示从上次切分的位置的下一个位置继续切分。

strtok从上次位置继续往后找空格符,找到后改成’\0’,记录位置,返回指向’a’的指针。

第三次调用同第二次,返回’a’的指针。

第四次调用的时候,从student的s出发往后找,没有找到空格,而是遇到了’\0’,那么这次strtok的调用也是结束了,返回’s’的指针。

第五次调用,起始位置已经是’\0’了,所以直接返回NULL表示整个切分都已经结束了。
在这里插入图片描述

注意:strtok有很多缺陷,在实际开发中很少使用。
1、使用太麻烦(需要搭配循环,且每次循环参数不同)。
2、修改了原始字符串。
3、需要使用static变量来记录上次的切分位置,线程不安全。

二、常用内存函数

1.memcpy拷贝

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

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

模拟实现memcpy的代码如下:

void* myMemcpy(void* dest, const void* src, size_t num) {
	assert(dest != NULL && src != NULL);
	char* pDest = (char*)dest;
	char* pSrc = (char*)src;
	for (size_t i = 0; i < num; i++) {
		//*(dest + i) = *(src + i);
		*(pDest + i) = *(pSrc + i);
	}
	return dest;
}

2.memmove重叠拷贝

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

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

模拟实现代码如下:

void* myMemcpy(void* dest, const void* src, size_t num) {
	assert(dest != NULL && src != NULL);
	char* pDest = (char*)dest;
	char* pSrc = (char*)src;
	for (size_t i = 0; i < num; i++) {
		//*(dest + i) = *(src + i);
		*(pDest + i) = *(pSrc + i);
	}
	return dest;
}

补充——关于合法性判定

assert是一种比较严厉的处理方式,一旦触发,程序就会崩溃。

注意事项:
1、一般是拿参数和空指针判定。
2、若当前场景下是比较严重的问题,适合使用assert。若不是,就是应该使用if语句自行处理问题。
3、判定的时机最好是double check,调用的时候要判定,调用内部也要判定。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值