strcpy基本用法


C語言標准庫函數strcpy,把從src地址開始且含有NULL結束符的字符串復制到以dest開始的地址空間

C語言函數

原型聲明:extern char *strcpy(char* dest, const char *src);

頭文件:#include <string.h> 和 #include <stdio.h>

功能:把從src地址開始且含有\0結束符的字符串復制到以dest開始的地址空間

說明:src和dest所指內存區域不可以重疊且dest必須有足夠的空間來容納src的字符串。

返回指向dest的指針

應用實例

已知strcpy函數的原型是:

char * strcpy(char * strDest,const char * strSrc);

⒈不調用庫函數,實現strcpy函數。

⒉解釋為什么要返回char *。

解說

⒈strcpy的實現代碼

char* strcpy(char* strDest, const char* strSrc)
{
    if (strDest==nullptr||strSrc==nullptr)
    {
        throw "Invalid agruments";
    }
    char* strDestCopy = strDest;
    while (strSrc!='\0')
    {
        *strDest++ = *strSrc++;
    }
    *strDest = '\0';
    return strDestCopy;
}

char * strcpy(char * strDest, const char * strSrc)

{

    if ((nullptr == strDest) || (nullptr == strSrc)) //[1]

        throw "Invalid argument(s)"; //[2]

    char * strDestCopy = strDest; //[3]

    while ((*strDest++ = *strSrc++) != '\0'); //[4]

    return strDestCopy;

}

 

錯誤的做法:

[1]

(A)不檢查指針的有效性,說明答題者不注重代碼的健壯性。

(B)檢查指針的有效性時使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),說明答題者對C語言中類型的隱式轉換沒有深刻認識。在本例中char *轉換為bool即是類型隱式轉換,這種功能雖然靈活,但更多的是導致出錯概率增大和維護成本升高。所以C++專門增加了bool、true、false三個關鍵字以提供更安全的條件表達式

(C)檢查指針的有效性時使用((strDest==0)||(strSrc==0)),說明答題者不知道使用常量的好處。直接使用字面常量(如本例中的0)會減少程序的可維護性。0雖然簡單,但程序中可能出現很多處對指針的檢查,萬一出現筆誤,編譯器不能發現,生成的程序內含邏輯錯誤,很難排除。而使用NULL代替0,如果出現拼寫錯誤,編譯器就會檢查出來。

[2]

(A)return new string("Invalid argument(s)");,說明答題者根本不知道返回值的用途,並且他對內存泄漏也沒有警惕心。從函數中返回函數體內分配的內存是十分危險的做法,他把釋放內存的義務拋給不知情的調用者,絕大多數情況下,調用者不會釋放內存,這導致內存泄漏。

(B)return 0;,說明答題者沒有掌握異常機制。調用者有可能忘記檢查返回值,調用者還可能無法檢查返回值(見后面的鏈式表達式)。妄想讓返回值肩負返回正確值和異常值的雙重功能,其結果往往是兩種功能都失效。應該以拋出異常來代替返回值,這樣可以減輕調用者的負擔、使錯誤不會被忽略、增強程序的可維護性。

[3]

(A)忘記保存原始的strDest值,說明答題者邏輯思維不嚴密。

[4]

(A)循環寫成while (*strDestCopy++=*strSrc++);,同[1](B)。

(B)循環寫成while (*strSrc!='\0') *strDest++=*strSrc++;,說明答題者對邊界條件的檢查不力。循環體結束后,strDest字符串的末尾沒有正確地加上'\0'。

⒉返回strDest的原始值使函數能夠支持鏈式表達式,增加了函數的"附加值"。同樣功能的函數,如果能合理地提高的可用性,自然就更加理想。

鏈式表達式的形式如:

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

又如:

char * strA=strcpy(new char[10],strB);

返回strSrc的原始值是錯誤的。其一,源字符串肯定是已知的,返回它沒有意義。其二,不能支持形如第二例的表達式。其三,為了保護源字符串,形參用const限定strSrc所指的內容,把const char *作為char *返回,類型不符,編譯報錯。

在上面的語句中,循環語句

while ((*strDestCopy++=*strSrc++)!='\0');

較難理解,可以把這句理解為以下操作。

第一種:

while( 1 ){ char temp; *strDestCopy = *strSrc; strDestCopy++; strSrc++; temp = *strSrc;if( '\0' == temp )break;}

第二種:

while ( *strSrc != '\0' )

{

*strDestCopy = *strSrc;

strDestCopy++;

strSrc++;

}

*strDestCopy = *strSrc++;

也即:

while ( *strSrc != '\0' )

{

*strDestCopy++ = *strSrc++;

}

*strDestCopy='\0';

使用實例:

//實例1:將一個字符串拷貝到一個足夠長的字符數組中。本例中字符數組為a,長度為20。
//缺點:若數組長度不足以容納整個字符串,則程序運行崩潰。

#include<iostream>
#include<stdlib.h>
using namespace std;
char * strcpy(char * strDest, const char * strSrc){
    char * strDestCopy = strDest;
    if ((NULL == strDest) || (NULL == strSrc)) throw "Invalid argument";
    while ((*strDest++ = *strSrc++) != '\0');
    return strDestCopy;
}

void main(int argc, char * argv[]){

    char a[20], c[] = "i am teacher!";
    try{
        strcpy(a, c);
    }
    catch (char* strInfo) {
        cout << strInfo << endl;
        exit(-1);
    }
    cout << a << endl;
}

 

//實例2:預設兩個字符指針,一個指向字符串,另一個為NULL,在程序運行過程中拷貝。
#include<iostream>
#include<assert.h>
using namespace std;
char *strcpy(char *strDes, const char *strSrc); //函數聲明
int main(){
    const char *strSrc = "helloworld";;
    char *strDes = NULL;
    strDes = strcpy(strDes, strSrc);
    cout << "strSrc=" << strSrc << endl;
    cout << "strDes=" << strDes << endl;
    if (strDes != NULL){
        free(strDes);
        strDes = NULL;
    }
    return 0;
}
char *strcpy(char *strDes, const char *strSrc){
    assert(strSrc != NULL); //若strSrc為NULL,則拋出異常。
    strDes = (char *)malloc(strlen(strSrc) + 1); //多一個空間用來存儲字符串結束符'\0'
    char *p = strDes;
    while (*strSrc != '\0'){
        *p++ = *strSrc++;
    }
    *p = '\0';
    return strDes;
}

 

與strncpy的區別

第一種情況:

char* p="how are you ?";

char name[20]="ABCDEFGHIJKLMNOPQRS";

strcpy(name,p); //name改變為"how are you ? "====>正確!

strncpy(name,p, sizeof(name));//name改變為"how are you ?" =====>正確!后續的字符將置為NULL

第二種情況:

char* p="how are you ?";

char name[10];

strcpy(name,p); //目標串長度小於源串,錯誤!

name[sizeof(name)-1]='\0'; //和上一步組合,彌補結果,但是這種做法並不可取,因為上一步出錯處理方式並不確定

strncpy(name,p,sizeof(name)); //源串長度大於指定拷貝的長度sizeof(name),注意在這種情況下不會自動在目標串后面加'\0'

name[sizeof(name)-1]='\0'; //和上一步組合,彌補結果

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM