天天看點

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不管,是以如果在超出數組上限時,超出記憶體都沒有被其他程序所占用,那麼一切正常。但是如果有至少一個位元組的記憶體區域屬于其他程序,那麼我這個程式将會出現運作時錯誤。