您的位置:首页 > 其它

经典库函数实现

2016-07-02 13:08 225 查看
经典库函数实现

strcpy()

原型声明:char strcpy(char dest, const char *src);
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。

#include <assert.h>

char *strcpy(char* dest, const char *src) //point1: 源字符串不改变,需要加const保证
<span id="transmark"></span>
{

assert(NULL != dest && NULL != src); //point2:保证指针有效

char * temp = dest; //point3:下面涉及到指针的移动,而我们需要返回dest的头指针,所以dest保留,而使用temp来移动

while ((*temp++ = *src++) != '\0');

/* point4:末尾的'\0'也要复制过来

* 上面先执行 *temp++ = *src++ ,再判断 *src 是否等于'\0'

* 所以保证了'\0'先复制后判断

*/

return dest; //point5:返回dest头指针,支持链式表达式

}

链式的例子:

int length = strlen(strcpy(strA, strB));

strncpy()

strcpy()是一个高危函数,因为没有指定复制的大小,当dest的空间比src小时,就会出错,而我们没法进行控制。于是有了比较安全的strncpy():

//把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回dest。

#include <assert.h>

char *strncpy(char* dest, const char *src, unsigned int n)

{

assert(NULL != dest && NULL != src);

char * temp = dest;

while (n-- > 0 && (*temp++ = *src++) != '\0');

/* 上面语句两种终止情况:

* 1. n = 0,此时下面的语句也不执行,如果未达到src末尾

* 不会自动在dest末尾添加'\0'的,所以需要使用者自己添加

* 2. n > 0 但是src已经到达末尾,那么执行下面语句,将

* dest填充'\0'达到长度n(ANSI C规定)

*/

while (n-- > 0) *temp++ = '\0';

return dest;

}

strcmp()

比较两个字符串
设这两个字符串为str1,str2,
若str1==str2,则返回零;
若str1>str2,则返回正数;
若str1

#include <assert.h>

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

{

assert(NULL != str1 && NULL != str2);

/*不可用while(*str1++==*str2++)来比较,当不相等时仍会执行一次++,

return返回的比较值实际上是下一个字符。应将++放到循环体中进行。*/

while(*str1 && *str2 && *str1 == *str2)

{

str1++;

str2++;

}

return *str1 - *str2;

/* 若相等,则*str1 - *str2 = '\0' - '\0' = 0;

* 否则,*str1 - *str2 != 0;

* 因为前面的位都相等,所以只需要比较当前位来确定返回值

*/

}

strcat()

把src所指字符串添加到dest结尾处(覆盖dest结尾处的’\0’)。

char *strcat(char *dest,const char *src)

{

assert(NULL != dest && NULL != src);

char *temp = dest;

while ('\0' != *temp) //自增放在循环里,才可以覆盖'\0'

++temp;

while ((*temp++ = *src++) != '\0');

return dest;

}

strlen()

功能:计算给定字符串的(unsigned int型)长度,不包括’\0’在内
说明:返回s的长度,不包括结束符NULL。

unsigned int strlen(const char *s)

{

assert(NULL != s);

unsigned int len = 0;

while (*s++ != '\0')

++len;

return len;

}
memset()

void *memset(void *s, int ch, size_t n);

函数解释:将s中前n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。

注意,memset是以【字节】为单位进行赋值的,因此下面用法将导致错误:

int arr[5];

memset(array,1,sizeof(arr));

arr指向5个字节的空间,每个都用ASCII为1的字符去填充,转为二进制后,1就是00000001,占一个字节。一个INT元素是4字节,合 一起就是00000001000000010000000100000001,就等于16843009,就完成了对一个INT元素的赋值了。所以上面结果 不是1而是16843009!

void *memset(void *s,int c,unsigned int n) //point1:s指针类型未知,另外,n为字节数!

{

assert(NULL != s);

void *temp = s;

while (n--)

{

*(char *temp) = (char)c; //point2:转化为字符(1字节)

temp = (char *)temp + 1; //point3:不能自增,因为不知道指针类型

}

return s;

}

memcpy()

内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。

void *memcpy(void *dest, const void *src, size_t n)

{

assert(NULL != dest && NULL != src);

int i = 0;

void *temp = dest;

while (i < n)

{

*((char *)temp + i) = *((char *)src + i); //未知类型,不能自增

++i;

}

return dest;

}
atoi()

这个函数就比较经典了,面试常常出现,因为可以考察各种特殊情况:空指针、空串、正负号、非法字符、溢出等等。

最大的int:0x7FFF FFFF;
最小的int:0x8000 0000;

enum = {Invalid = 0, Valid};

bool errno = Invalid;

int atoi(const char * str)

{

long long num = 0; //point1:可能溢出,所以用long long存

errno = Invalid;

if (NULL != str && *str != '\0') //point2

{

bool minus = false;

if (*str == '+')

{

++str;

}

else if (*str == '-')

{

++str;

minus = true;

}

if ('\0' != *str) //只有符号,Invalid

atoiCore(str, minus, num);

}

return (int)num; //已经检查过溢出,保证了num在int范围内

}

void atoiCore(const char *str, bool minus, long long &num)

{

while ('\0' != *str)

{

if (*str >= '0' && *str <= '9')

{

num = num*10 + (*str) - '0';

++str;

if ((!minus && num > 0x7FFFFFFF)||(minus && (-num) < (signed int)0x80000000))

{

errno = Invalid;

num = 0;

return;

}

}

else

{

errno = Invalid;

num = 0;

return;

}

}

if (minus)

num = -num;

errno = Valid;

}

char *itoa(int num,char *str,int radix)

{//num:int型原数,str:需转换成的string,radix,原进制,

/* 索引表 */

char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

unsigned unum;/* 中间变量 */

int i=0,j,k;

/* 确定unum的值 */

if(radix==10&&num<0){/* 十进制负数 */

unum=(unsigned)-num;

str[i++]='-';

}else

unum=(unsigned)num;/* 其他情况 */

/* 逆序 */

do{

str[i++]=index[unum%(unsigned)radix];

unum/=radix;

}while(unum);

str[i]='\0';

/* 转换 */

if(str[0]=='-')

k=1;/* 十进制负数 */

else

k=0;

/* 将原来的“/2”改为“/2.0”,保证当num在16~255之间,radix等于16时,也能得到正确结果 */

for(j=k;j<(i-1)/2.0+k;j++){

num=str[j];

str[j]=str[i-j-1+k];

str[i-j-1+k]=num;

}

return str;

}

strstr

函数功能:找出src字符串在dest字符串中第一次出现的位置(不包括src的'\0')
函数说明:返回该位置的指针,如找不到,返回空指针。
函数实现:

char* _strstr(const char* dest, const char* src)

{

assert(dest != nullptr);

//判断dest指针是否为空,若为空抛出异常

if (!src)

return (char*)dest;

while (*dest)

{

const char* destTmp = dest;

const char* srcTmp = src;

while (*srcTmp == *destTmp && (*srcTmp))//限时*srcTmp与*destTmp比较后相等至'\0'时继续访问出现越界

{

srcTmp++;

destTmp++;

}

if (!(*srcTmp))

return (char*)destTmp;

dest++;

}

return nullptr;

}

寻找字串的KMP算法

void GetNext(char* p,int next[])

{

int pLen = strlen(p);

next[0] = -1;

int k = -1;

int j = 0;

while (j < pLen - 1)

{

//p[k]表示前缀,p[j]表示后缀

if (k == -1 || p[j] == p[k])

{

++k;

++j;

next[j] = k;

}

else

{

k = next[k];

}

}

}

int KmpSearch(char* s, char* p)

{

int i = 0;

int j = 0;

int sLen = strlen(s);

int pLen = strlen(p);

while (i < sLen && j < pLen)

{

//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++

if (j == -1 || s[i] == p[j])

{

i++;

j++;

}

else

{

//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]

//next[j]即为j所对应的next值

j = next[j];

}

}

if (j == pLen)

return i - j;

else

return -1;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: