天天看点

atoi itoa strcpy strcmp strlen strcat memcpy memset实现

实现总结一下C常用库中的一些函数,把书上的变成自己的!

其中:atoi 在标准库,但itoa不在标准库中, stdlib中,strcpy,strcmp,strlen,strcat,memcpy,memset 在库string中

一 atoi  

原型为 int atoi(const char *nptr),实现字符串转为整型。 方法一:

int myatoi(const char *nptr)
{
	assert(nptr != NULL);

	int i = 0;
	int sign = 1;
	int number = 0;

	while(' ' == nptr[i] || '\t'== nptr[i])
		i++;
	sign = (nptr[i] == '-') ? -1 : 1;

	while('-' == nptr[i] || '+' == nptr[i])
		i++;
	while(nptr[i] != '\0')
	{
		number = number*10 + (nptr[i] - '0');
		i++;
	}
	number = sign * number;
	return number;

}
           

这种方法是网上常见的方法,但是在测试的过程中发现,当输入字符串为“   -123    ”时,输出结果不是-123,那时因为在最后一次循环中,只判断了是否为结束符,而没有判断是否不是数字,所以我做了如下修改:

while(nptr[i] >= '0' && nptr[i] <='9' )
	{
		number = number*10 + (nptr[i] - '0');
		i++;
	}
           

其效果等效于方法二中的 isdigit()函数。 方法二:可以直接调用ctype库中的函数实现

int myatoi(const char *nptr)
{
	assert(nptr != NULL);

	int i = 0;
	int sign = 1;
	int number = 0;

	while(isspace(nptr[i]))
		i++;
	sign = (nptr[i] == '-') ? -1 : 1;

	while('-' == nptr[i] || '+' == nptr[i])
		i++;
	while(isdigit(nptr[i]))
	{
		number = number*10 + (nptr[i] - '0');
		i++;
	}
	number = sign * number;
	return number;
}
           

二 itoa

原型为 void itoa(int n, char [ ]),实现把整型转为字符串。

由于整数长度未知,不能直接获得整数,需要对其进行逆序。

void myitoa(const int num,char *s)
{
	int n = num;
	int i = 0;
	int j = 0;

	char *temp = new char[10];
	if(n < 0)
	{
		s[i] = '-';
		i++;
		n = -num;
	}

	while(n > 0)
	{
		temp[j] = n%10 + '0';
		n = n/10;
		j++;
	}
	temp[j] = '\0';
	j--;

	while(j >=0)
		s[i++] = temp[j--];
	s[i] = '\0';
}
           

三 strcpy

原型为 char* strcpy(char *str1,const char * str2),把str2所指的字符串复制到str1中,返回目的存储区的初始地址

char* myStrcpy(char* dst,const char* src)
{
	assert( src != NULL);
	assert( dst != NULL);
	char *address = dst;
//	memcpy(dst,src,strlen(src)+1);
	while((*dst++ = *src++) != '\0');

	return address;
}
           

四 strcmp

原型为 int strcmp(const char *str1,const char * str2),比较str1,str2所指字符串的大小,如果str1 = str2,返回0,str1 < str2,返回<0,str1 > str2 ,返回 >0。

int mystrcmp(const char *dst,const char *src)
{
	assert(dst != NULL && src != NULL);
	
	while(*dst && *src && *dst == *src)
	{
		dst++;
		src++;
	}
	return *dst-*src;	
}
           

五 strlen

原型为 int strlen(const char *str),返回str的字符长度, 不包括'\0'(字符串中的空格包括在内)

int mystrlen(const char *src)
{
	assert(src != NULL);
	int length = 0;
	while(*src != '\0')
	{
		length++;
		src++;
	}
	return length;
}
           

六 strcat

原型为 char *strcat(char *str1,const char *str2),把str2所指的字符串连接到str1,并返回目的存储区初始地址

char *mystrcat(char *dst,const char *src)
{
	assert(dst != NULL && src != NULL);

	char *address = dst;
	while(*dst != '\0')
		dst++;
	while((*dst ++ = *src ++) != '\0');
	*dst = '\0';
	return address;
}
           

注意:在dst指针移到dst末尾时,不能

while(*dst++ != '\0'); 
           

如果这样的话,不能达到连接的效果,最后返回的只是dst的内容。这是因为* 和 ++ 的优先级一样,则自左向右执行,即当判断dst为结束符,其会指向下一个字节,即'\0'的下一个字节。所以address保存的内容是:dst ‘\0’ src '\0',输出时遇'\0'停止,即dst '\0'。

七 memcpy

原型为 void *memcpy(void *str,const void *str2,size_t n),存储器拷贝,把str指的n个字符拷贝到str1中,返回目的存储区起始地址

void *mymemcpy(void *dst,const void *src,size_t n)
{
	assert(dst != NULL && src != NULL);
	//assert((dst >= src+n) || (src >dst+n));

	char *tempdst =(char *) dst;
	char *tempsrc = (char *)src;

	while(n-- )
		*tempdst++ = *tempsrc++;

	return dst;
}
           

  为了防止内存重叠,可以做如下修改:

 void *mymemcpy(void *dst,const void *src,size_t n)
{
	assert(dst != NULL && src != NULL);
	char *tempdst =(char *) dst;
	char *tempsrc = (char *)src;
	//assert((tempdst >= tempsrc+n) || (tempsrc > tempdst+n));

	size_t i = 0;
	if(tempdst > tempsrc && tempdst < tempsrc + n)
	{

		while(n--)
			*tempdst++ = *tempsrc++;

	}
	else
	{

		while(n--)
			*tempdst++ = *tempsrc++;

	}

	return dst;
}

int _tmain(int argc, _TCHAR* argv[])
{
	char src[] = "abadc";
	char dst[] = "SCH";
	mymemcpy(dst,src,2*sizeof(char));
	cout <<dst<<endl;
	return 0;
}

           

注意:函数调用时,返回值只是地址。

memcpy和strcpy区别: 1.strcpy只能复制字符串,而memcpy不限制数据类型 2.strcpy不需要知道字符串长度,一直复制,直到'\0',这样容易溢出,而memcpy遇到'\0'不停止,指导n才结束。

八 memset

原型为 void *memset(void *str,int v,size_t n),把str所指区域的前n个字节均设为v,返回的是该区域的起始地址。

void *mymemset(void *dst,int v,size_t n)
{
	assert(dst != NULL);
	char *address = (char *)dst;
	while(n--)
		*address++ = v;
	return dst;
}
           

对于memset来说,没有越界不越界之分,数组的界是程序员逻辑一部分,memset不管,因此如果在超出数组上限时,超出内存都没有被其他进程所占用,那么一切正常。但是如果有至少一个字节的内存区域属于其他进程,那么我这个程序将会出现运行时错误。