對strncpy()函數(shù)來說,它意味著只能使用“n”個字符的空間,包括末尾的NUL字符。
strncpy()函數(shù)也恰好只拷貝“n”個字符。如果第二個參數(shù)沒有這么多字符,strncpy()函數(shù)會用NUL字符填充剩余的空間。如果第二個參數(shù)有多于“n”個的字符,那么strncpy()函數(shù)在還沒有拷貝到NUL字符之前就結(jié)束工作了。這意味著,在使用strncpy()函數(shù)時,你應(yīng)該總是自己在目標(biāo)字符串的末尾加上NUL字符,而不要指望strncpy()函數(shù)為你做這項(xiàng)工作。
對strncat()函數(shù)來說,它意味著最多只能拷貝“n”個字符,如果需要還要加上一個NUL字符。因?yàn)槟阏嬲赖氖悄繕?biāo)字符串能存放多少個字符,所以通常你要用strlen()函數(shù)來計(jì)算可以拷貝的字符數(shù)。
函數(shù)strncpy()和strncat()之間的區(qū)別是“歷史性”的(這是一個技術(shù)用語,指的是“它對某些人確實(shí)起到了一定的作用,并且它可能是處理問題的正確途徑,但為什么正確至今仍然說不清楚”)。
1.strcpy
功能:把從src地址開始且含有NULL結(jié)束符的字符串賦值到以dest開始的地址空間
說明:src和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來容納src的字符串。
返回值:返回指向dest的指針。
源碼:
1 char *strcpy(char *strDestination, const char *strSource)
2 {
3 assert(strDestination!=NULL && strSource!=NULL);
4 char *strD = strDestination;
5 while ((*strDestination++ = *strSource++) != '\0');
6 return strD;
7 }
面試中容易問到的問題:
(1). strcpy能把strSrc的內(nèi)容復(fù)制到strDest,為什么還要char * 類型的返回值?
為了實(shí)現(xiàn)鏈?zhǔn)奖磉_(dá)式:int length = strlen( strcpy( strDest, “hello world”) );
2.strncpy
功能:把src所指由NULL結(jié)束的字符串的前n個字節(jié)復(fù)制到dest所指的數(shù)組中。
說明:1. 如果src的前n個字節(jié)不含NULL字符,則結(jié)果不會以NULL字符結(jié)束。
2. 如果src的長度小于n個字節(jié),則以NULL填充dest直到復(fù)制完n個字節(jié)。
3. src和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來容納src的字符串。
返回值:返回指向dest的指針。
源碼:
1 char *strncpy(char * dest, const char * source, size_t count)
2 {
3 char *start = dest;
4 while (count && (*dest++ = *source++))
5 {
6 count--;
7 }
8 if (count)
9 {
10 while (--count)
11 {
12 *dest++ = '\0';
13 }
14 }
15 return(start);
16 }
面試中容易問到的問題:
(1). strcpy和strncpy的區(qū)別?
one: strncpy 從某種意義上說是安全的。只要n的長度不超過s1分配的實(shí)際長度,就不會造成內(nèi)存越界。
two: 如果n不超過s1的長度,strncpy會在s1的尾部自動添加null字符。
3.memcpy
功能:從源src所指的內(nèi)存地址的起始位置開始拷貝n個字節(jié)到目標(biāo)dest所指的內(nèi)存地址的起始位置中。
說明:one:source和dest所指內(nèi)存區(qū)域不能重疊。
two:如果目標(biāo)數(shù)組本身已有數(shù)據(jù),執(zhí)行memcpy()后,將覆蓋原有數(shù)據(jù)(最多覆蓋n)。如果要追加數(shù)據(jù),則每次執(zhí)行memcpy后,要將目標(biāo)數(shù)組地址增加到你要追加數(shù)據(jù)的地址。
three:source和dest都不一定是數(shù)組,任意的可讀寫的空間均可
返回值:返回指向dest的指針。
源碼:
1 void *memcpy(void *dest, void *source, size_t count)
2 {
3 void *ret = dest;
4 while (count--)
5 *dest++ = *source;
6 return ret;
7 }
面試中容易問到的問題:
(1). memcpy和strcpy的區(qū)別?
one: 復(fù)制的內(nèi)容不同。strcpy只能復(fù)制字符串,而memcpy可以復(fù)制任意內(nèi)容,例如字符數(shù)組、整型、結(jié)構(gòu)體、類等。
two:復(fù)制的方法不同。strcpy不需要指定長度,它遇到被復(fù)制字符的串結(jié)束符"\0"才結(jié)束,所以容易溢出。memcpy則是根據(jù)其第3個參數(shù)決定復(fù)制的長度。
three:用途不同。通常在復(fù)制字符串時用strcpy,而需要復(fù)制其他類型數(shù)據(jù)時則一般用memcpy。
另外,對strncpy、strncat、strncmp,我按我的理解進(jìn)行了說明,可以在這以下幾個基礎(chǔ)上進(jìn)行自己動手實(shí)現(xiàn)。
//求字符串長度函數(shù)
//size_t為無符號整型,一般直接比較
//若用減號比較會產(chǎn)生隱式轉(zhuǎn)換
//如:Mystrlen(str1)-Mystrlen(str2)>=0,此式恒為真
size_t Mystrlen(const char *str)
{
int len =0;
while(*str++ != '\0')
len++;
return len;
}
//字符串復(fù)制函數(shù)
//對于strncpy,標(biāo)準(zhǔn)庫是這樣實(shí)現(xiàn)的:
//根據(jù)指定長度復(fù)制,不管復(fù)制后的str1是否為'\0'結(jié)尾,像strcpy一樣,不管str1是否越界
//也就是說調(diào)用strncpy后要把最后一個字符賦'\0'
char* Mystrcpy(char* str1, const char* str2)
{
assert(str1!=NULL && str2!=NULL);
char* pTemp = str1;
while((*str1++ = *str2++)!='\0');
return pTemp;
}
//拼接函數(shù)
//strncat與strncpy有區(qū)別,strncat只拼接指定長度減一的長度,會在dst結(jié)尾賦'\0'
//不管目標(biāo)空間夠不夠
char* Mystrcat(char* dst, const char* src)
{
assert(dst != NULL && src!=NULL);
char* pTemp = dst;
while(*dst++ !='\0');
dst--;
while((*dst++ = *src++) != '\0');
return pTemp;
}
//比較字符串
//strncmp,只比較指定的長度,其他的不比較,原理與strcmp相似
int Mystrcmp(const char* str1, const char* str2)
{
assert(str1 != NULL && str2 != NULL);
while(*str1 != '\0' && *str2 != '\0')
{
if (*str1 > *str2)
{
return 1;
}
else if (*str1 == *str2)
{
str1++;
str2++;
}
else
{
return -1;
}
}
if (*str1 != '\0')
{
return 1;
}
else if (*str2 != '\0')
{
return -1;
}
else
{
return 0;
}
}