博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
常用字符串函数原理及实现
阅读量:3590 次
发布时间:2019-05-20

本文共 7345 字,大约阅读时间需要 24 分钟。

 
1.函数名称: void* memchr_m(const void* buffer, int ch, int count)

   函数说明:字符串函数实现,防止memchr函数重载,定义为memchr_m函数

                            在buffer指向的数组的count个字符的字符串里查找ch 首次出现的位置。int ch表示字符对应的ascii

                            返回一个指针,指向ch 在字符串中首次出现的位置, 如果ch 没有在字符串中找到,返回NULL。

#include
#include
using namespace std;void* memchr_m(const void* buffer, int ch, int count){ assert(NULL != buffer); char*p = (char*)buffer; while (*p!='\0' && count--) { if (*p == (char)ch) return (void*)p; p++; } return NULL;}int _tmain(int argc, _TCHAR* argv[]){ char a[] = "pengpeng has a nice mood!"; char *p; p = (char*)memchr_m(a, 'm', 100); //p = (char*)memchr_m(a, 'x', 100); if (p != NULL) { cout << "Find!" << endl; cout << p << endl; } else { cout << "Not Find!" << endl; } getchar(); return 0;}

2.函数名称: strstr(s1,s2)

  函数说明:用于在字符串中查找子串,函数返回s2在s1中第一次出现的字符串地址,若s1中没有找到s2,返回NULL,若s2为空,则返回s1.

char* strstr_m(const char *s1, const char *s2){	if (*s2 == '\0')			/*如果s2为空,则返回s1*/		return ((char *)s1);	for (; s1 != '\0'; ++s1)	/*每次后移s1的位置,在新的位置进行下一次匹配*/	{		const char *sc1, *sc2;		while ((*s1 != *s2) && (*s1 != '\0')) ++s1; /*在s1中找到和s2第一个字符匹配的位置*/		if (*s1 == '\0')		 /*如果找不到,说明s1现在的位置不匹配,退出循环进行下一次匹配*/			break;		else					/*如果找到和s2第一个字符匹配的位置,开始逐个匹配s2后面的字符*/		for (sc1 = s1, sc2 = s2; sc1 != '\0'; ++sc1, ++sc2)		{			if (*sc2 == '\0')		/*如果匹配完毕,返回s1此时的位置*/				return ((char *)s1);			else if (*sc1 != *sc2)	/*如果后面有一个字符不匹配,说明s1现在的位置不匹配,退出循环进行下一次匹配*/				break;		}	}	return (NULL);}int _tmain(int argc, _TCHAR* argv[]){	char *s = "1233345hello";	char *sub = "333435";	const char *p = strstr_m(s, sub);	if (NULL != p)		printf("%s\n", p);	else		printf("can find the matching str\n");	getchar();	return 0;}
3. 函数名称:char *strchr(const char *s, char c);
    函数说明:查找字符串s中首次出现字符c的位置

    返回值:成功则返回要查找字符第一次出现的位置,失败返回NULL。 

char* strchr_m(const char*s, char c){	assert(s != NULL);	while (*s != '\0')	{		if (*s == c)			return (char*)s;		s++;	}	return NULL;}int _tmain(int argc, _TCHAR* argv[]){	char *s = "1233345hello";	char ch = '5';	const char *p = strchr_m(s, ch);	if (NULL != p)		printf("%s\n", p);	else		printf("can find the matching str\n");	getchar();	return 0;}

Linux下实现:

思路:

  1. 检测字符串安全性,s2为空果断抛弃之。

  2. s1逐个递增,并与s2整串比较内存大小,判断字串是否相等。相等则返回s1,否则s1++,再执行比较。

  3. 最后返回空值,代表未找到相符的串

char *strstr(const char *s1, const char *s2){    size_t l1, l2;     l2 = strlen(s2);    if (!l2)        return (char *)s1;    l1 = strlen(s1);    while (l1 >= l2)    {        l1--;        if (!memcmp(s1, s2, l2))            return (char *)s1;        s1++;    }    return NULL;}
关于memcmp的实现见函数 7

4. 函数名称:char* strcpy_m(char*dst ,const char* src)
    函数说明:字符串复制

char* strcpy_m(char* dst, const char* src){	assert(dst != NULL && src != NULL);  	char *ret = dst;  	while ((*dst++ = *src++) != '\0');      //或者改为		while((*dst=*src)!='\0') 	return ret;						      //{ dst++; src++}	}

说明1:const修饰,源字符串参数用const修饰,防止修改源字符串。
说明2:空指针检查, assert(src!=NULL)  增加健壮性、如果拼写错误编译器就会查出来
说明3:返回目标地址,要返回char * ,返回dst的原始值使函数能够支持链式表达式。
链式表达式的形式如:int l = strlen(strcpy(strA, strB));
说明4: 循环写成while(*src != '\0') *dst++ = *src++;
循环体结束后,dst字符串的末尾没有正确地加上'\0'.
说明5:char s[10]="hello";strcpy(s, s + 1); //应返回ello,
strcpy(s+1, s); //应返回hhello,但实际会报错,因为dst与src重叠了,把'\0'覆盖了
所谓
重叠,就是src未处理的部分已经被dst给覆盖了,只有一种情况:src <= dst <= src + strlen(src)
C函数memcpy自带内存重叠检测功能,下面给出memcpy的实现my_memcpy。

char * strcpy_m2(char *dst, const char *src){	assert(dst != NULL && src != NULL);	char *ret = dst;	memcpy_m(dst, src, strlen(src) + 1);	return ret;}

5.函数名称:void *memcpy_m(void *dst, const void* src, int cnt);

   函数说明:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中

void *memcpy_m(void *dst, const void* src, int cnt){	assert(dst != NULL && src != NULL);	void *ret = dst;	if (dst >= src && (char*)dst <=(char*) src + cnt - 1) //内存重叠,从高地址开始复制	{		dst = (char*)dst + cnt - 1;		src = (char*)src + cnt - 1;		while (cnt--)		{			*(char*)dst = *(char*)src;			dst = (char*)dst - 1;			src = (char*)src - 1;		}	}	else    //正常情况,从低地址开始复制    无重叠  dst<=src	{		while (cnt--)		{			*(char*)dst = *(char*)src;			dst = (char*)dst + 1;			src = (char*)src + 1;		}	}	return ret;}

由以上很简单可以给出:

6.函数名称:char* strncpy(char* dst, const char* src, int n)
   函数说明:把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回dest。
                            注意提前结束即遇到'\0'和n个长度字节数据复制结束的情况

char* strncpy_m(char* dst, const char* src, int n){	assert(dst != NULL && src != NULL);	char*ret = dst;	while ((n--) && (*dst++ = *src++) != '\0')	{		if (n == 0)			*dst = '\0';		break;	}	return ret;}//或者修改为char* strncpy_m2(char* dst, const char* src, int n){	assert(dst != NULL && src != NULL);	char*ret = dst;	while ((n--) && (*dst++ = *src++) != '\0');	if (n < 0)		*dst = '\0';	return ret;}
7.函数名称:
i
nt memcmp(const void *cs, const void *ct, size_t count)
   函数说明:比较内存区域参数cs和 ct的前count个字节。
当cs<ct时,返回值小于0;
当cs==ct时,返回值=0;
当cs>ct时,返回值大于0;
Linux类似实现:
int memcmp(const void *cs, const void *ct, size_t count){        const unsigned char *su1, *su2;        int res = 0;        for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)                if ((res = *su1 - *su2) != 0)                        break;        return res;}
int strcmp(const char *cs, const char *ct){        signed char __res;        while (1) {                if ((__res = *cs - *ct++) != 0 || !*cs++)//比较到结束符\0,时,已经做了__res = *cs - *ct了,但是此时*cs和*ct的值都为\0,所以返回肯定为0                        break;        }        return __res;}
/**strncmp - Compare two length - limited strings* @cs: One string* @ct : Another string* @count : The maximum number of bytes to compare* /int strncmp(const char *cs, const char *ct, size_t count){	signed char __res = 0;	while (count) {		if ((__res = *cs - *ct++) != 0 || !*cs++) //比较到结束符\0,时,已经做了__res = *cs - *ct了,所以不等长度时,肯定返回不为0			break;		count--;	}	return __res;}

首先看看3个函数的功能:

      1、strcmp(const char * a1,const char *a2)
           用来比较a1和a2两个字符串(按ASCII值大小相比较),注意点是这个函数只能用来比较字符串
                  当a1<a2时候,返回的值<0
                  当a1>a2时候,返回的值>0
                  当a1=a2时候,返回的值=0
     2、strncmp(const char * a1,const char *a2,int maxlen)
          与上面的函数类似),用来比较a1和a2两个字符串的,但是之比较两个字符串的钱maxlen长度的字符串
                  当a1<a2时候,返回的值<0
                  当a1>a2时候,返回的值>0
                  当a1=a2时候,返回的值=0
     3、int memcmp (const void *a1, const void *a2, size_t size) 
           原型是:extern int memcmp(void *buf1, void *buf2, unsigned int count);
          功能上来说是比较a1和a22个buff内的前size个字节,如果相同返回的结果是0

比较:

1、strcmp是按照字节比较的,如果出现"\0"的情况会终止比较;

       2、memcmp 用来比较内存块的内容是否一致,不常用于字节的比较,中包含一些由于边界对齐需求而填入结构对象中的空格、联合 (union)结束的额外空格、字符串所分配的空间未使用完的部分引起的“holes”的话,最好使用memcmp来完成,这些“holes”的内容是不确定的,在执行byte-wise比较时结果也是不明确的;

      3、strcmp比较的字符串,而memcmp比较的是内存块,strcmp需要时刻检查是否遇到了字符串结束的 \0 字符,而memcmp则完全不用担心这个问题,所以memcmp的效率要高于strcmp

8.  字符串转换int

int str2int(const char *str){	int temp = 0;	const char *ptr = str;  //ptr保存str字符串开头	if (*str == '-' || *str == '+'){//如果第一个字符是正负号,		str++;                      //则移到下一个字符	}	while (*str != 0){		if ((*str < '0') || (*str > '9')){//如果当前字符不是数字			break;                       //则退出循环		}		temp = temp * 10 + (*str - '0'); //如果当前字符是数字则计算数值   没有考虑溢出		str++;      //移到下一个字符	}	if (*ptr == '-'){                   //如果字符串是以“-”开头,则转换成其相反数		temp = -temp;	}	return temp;}

int转换为字符串

void int2str(int n, char *str){	char buf[10] = "";	int i = 0;	int len = 0;	int temp = n < 0 ? -n : n;  // temp为n的绝对值	if (str == NULL){		return;	}	while (temp){		buf[i++] = (temp % 10) + '0';  //把temp的每一位上的数存入buf		temp = temp / 10;	}	len = n < 0 ? ++i : i;  //如果n是负数,则多需要一位来存储负号	str[i] = 0;            //末尾是结束符0	while (1){		i--;		if (buf[len - i - 1] == 0){			break;		}		str[i] = buf[len - i - 1];  //把buf数组里的字符拷到字符串	}	if (i == 0){		str[i] = '-';          //如果是负数,添加一个负号	}}

转载地址:http://xiown.baihongyu.com/

你可能感兴趣的文章
springboot+vue+element-ui实现图文上传(表单文字和图片一起入库)
查看>>
springboot+vue+element-ui下载excel模板(静态文件)
查看>>
vue项目打包部署后二级页面刷新变成404问题
查看>>
springboot在Windows服务器部署做成服务
查看>>
vue的页面刷新和单独组件的销毁重建
查看>>
vue+ckplayer+rtmp
查看>>
vue+pg库+openlayer5+geoserver+离线地图瓦片构建gis地图+地图撒点+点击点出现地图弹框(***完整流程***)
查看>>
openlayer5实现地图撒点,点击弹框效果
查看>>
vscode炫酷写代码插件Power Mode
查看>>
实现字符串倒叙
查看>>
node中引入其他ejs文件,并给引入文件传参,类似iframe
查看>>
ejs中在页面上使用if-else
查看>>
moment中时间为12小时制,dayjs中时间为12小时制
查看>>
vue解决打包后文件过大的问题-使用压缩插件打包后压缩文件-compression-webpack-plugin
查看>>
爆料称字节跳动实习生删库
查看>>
无缝滚动lunbot
查看>>
如何将Map集合写入txt文件中
查看>>
springboot参数检验,Assert使用
查看>>
htonl函数原理
查看>>
MACOS的Python虚拟环境使用笔记
查看>>