您的位置:首页 > 其它

常用字符串函数原理及实现

2017-04-20 10:11 465 查看
1.函数名称: void* memchr_m(const void* buffer, int ch, int count)
   函数说明:字符串函数实现,防止memchr函数重载,定义为memchr_m函数
                            在buffer指向的数组的count个字符的字符串里查找ch 首次出现的位置。int ch表示字符对应的ascii
                            返回一个指针,指向ch 在字符串中首次出现的位置, 如果ch 没有在字符串中找到,返回NULL。#include<iostream>
#include<assert.h>
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下实现:

思路:

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

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

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

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.函数名称:int 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] = '-'; //如果是负数,添加一个负号
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息