C++中strncpy函數和strncpy_s函數的使用及注意事項


https://blog.csdn.net/leowinbow/article/details/82745016

在掌握了strcpy函數和strcpy_s函數之后,我們不可避免地會談到strncpy函數和strncpy_s函數,其實這四個函數的功能幾乎一致,就是對兩個字符串數組進行復制和賦值,但是具體實現有一點點區別。

首先來說一下strncpy函數。該函數依然還是存在於標准名稱空間std內,出現的目的很簡單,對於strcpy函數,只能將兩個字符串進行完整的復制和賦值,這里就會產生一個實際應用時的問題,如果我們只需要復制某個字符串的前幾個字符呢?

其實對於這個問題,我們首先可能會想到使用strcpy_s函數,因為該函數有一個長度,我們在安全函數的基礎上將長度表示成我們希望復制的長度,但是實際運行時這樣寫會出現問題,舉例如下:

  1.  
    // strncpy_s.cpp
  2.  
    //
  3.  
     
  4.  
    #include "stdafx.h"
  5.  
    #include <iostream>
  6.  
    #include <cstring>
  7.  
     
  8.  
    int main()
  9.  
    {
  10.  
    using namespace std;
  11.  
     
  12.  
    char str1[100];
  13.  
    char str2[5];
  14.  
    cout << "Please enter your favorite lines (Warning: No longer than 100!):\n";
  15.  
    cin.getline(str1, 100);
  16.  
    strcpy_s(str2, 5, str1);
  17.  
    cout << "str1 is " << endl << str1 << endl;
  18.  
    cout << "while str2 is " << endl << str2 << endl;
  19.  
     
  20.  
    system( "pause");
  21.  
    return 0;
  22.  
    }

對於以上代碼,運行結果如下圖所示:

由運行結果可知,Buffer is too small,即告訴我們安全函數之所以安全,就是不可以這樣操作,不可以把一個長度超過x的字符串數組復制並賦值給長度為x的字符串數組。

於是由此,strncpy函數應運而生。

由於我使用的IDE是Visual Studio 2017,所以只要使用strncpy函數就會報錯並提示使用安全版本,所以這里對於基礎版本的strncpy函數只做理論介紹。

strncpy函數的原型如下所示:

char * strncpy(char * str2, char * str1, int size);

功能就是復制str1中的內容,賦進str2中,復制的長度由size的數值決定,size的類型不一定是Int,但我們一般來說遇到的長度都是整數,所以這里用int比較簡單。

比如說以下語句:

  1.  
    char str1[5] = "abcd";
  2.  
    char str2[10] = "leonardo";
  3.  
    strncpy(str2, str1, 3);

因為IDE不支持基礎版本函數,所以我沒法看運行結果,就文字描述一下。

以上代碼運行之后,strncpy函數會將str1的前3個字符的內容復制,賦到str2里,於是str2就變成了‘a’'b'‘c’。

那么對於strncpy_s函數,原型如下所示:

strncpy_s(char * str2, int size2, char * str1, int size1);

這里多了一個長度,就是被復制的str2的長度,我們可以用sizeof(str2)來表示這個長度。

那么改成使用strncpy_s函數之后,上面的代碼就可以正確運行了。

  1.  
    // strncpy_s.cpp
  2.  
    //
  3.  
     
  4.  
    #include "stdafx.h"
  5.  
    #include <iostream>
  6.  
    #include <cstring>
  7.  
     
  8.  
    int main()
  9.  
    {
  10.  
    using namespace std;
  11.  
     
  12.  
    char str1[5] = "abcd";
  13.  
    char str2[10] = "leonardo";
  14.  
    cout << "str1 is " << endl << str1 << endl;
  15.  
    cout << "str2 is " << endl << str2 << endl;
  16.  
    strncpy_s(str2, sizeof(str2), str1, 3);
  17.  
    cout << "after the copy str2 is " << endl << str2 << endl;
  18.  
     
  19.  
    system( "pause");
  20.  
    return 0;
  21.  
    }

運行結果如下圖所示:

於是回到我們最早那個代碼,稍作修改使用strncpy_s函數,修改后代碼如下:

  1.  
    // strncpy_s.cpp
  2.  
    //
  3.  
     
  4.  
    #include "stdafx.h"
  5.  
    #include <iostream>
  6.  
    #include <cstring>
  7.  
     
  8.  
    int main()
  9.  
    {
  10.  
    using namespace std;
  11.  
     
  12.  
    char str1[5] = "abcd";
  13.  
    char str2[10] = "leonardo";
  14.  
    cout << "str1 is " << endl << str1 << endl;
  15.  
    cout << "str2 is " << endl << str2 << endl;
  16.  
    strncpy_s(str2, sizeof(str2), str1, 3);
  17.  
    cout << "after the copy str2 is " << endl << str2 << endl;
  18.  
     
  19.  
    char str3[100];
  20.  
    char str4[10];
  21.  
    cout << "Please enter your favorite lines (Warning: No longer than 100!):\n";
  22.  
    cin.getline(str3, 100);
  23.  
    strncpy_s(str4, sizeof(str4), str3, 10);
  24.  
    cout << "str3 is " << endl << str3 << endl;
  25.  
    cout << "while str4 is " << endl << str4 << endl;
  26.  
     
  27.  
    system( "pause");
  28.  
    return 0;
  29.  
    }

對於str3,它本身的長度是100,用戶輸入可以輸入小於100的任意長度的字符,但是str4沒有這么長,它的長度只有10,所以只能把str3的前10個字符內容復制給str3。

但是上面這樣寫還是有點問題,那就是字符串數組的最后一位一定是‘\0',如果直接復制10位,無法賦進str4,因為這樣就把它最后一位的'\0'給覆蓋了,就會報錯,所以我們修改上面代碼的strncpy_s()函數那里,改為

strncpy_s(str4, sizeof(str4), str3, 9);

這樣就正確了。

運行結果如下圖所示:

於是就完成了我們之前所說的,希望只復制某個字符串數組的一部分給另一個字符串數組的功能了。

其實這個功能還可以延伸,假如說,我們希望復制的字段並不是原字符串最開始的字符怎么辦呢,其實也很簡單,只需要在strncpy_s函數的第三個參數處進行操作就可以了。

比如說我們希望從第2個字符開始復制,那么第3個參數就由"str3"改寫為"str3+1"即可。因為str3是數組,數組名直接使用而不帶標號,即是表示地址,所以“str3+1”即是表示str3[1]的地址了,同理"str3+5"即是表示str[5]的地址。

於是我們把上述程序的第23行,即strncpy_s()函數賦值那一句改成如下所示:

strncpy_s(str4, sizeof(str4), str3 + 1, 9);

運行結果如下圖:

從圖中可以看出,確實是從第2個字符開始復制的。

那么接下來我們就要考慮,如果希望復制的不是連續的字符,而是分散的,比如說str3[2],str3[5],str3[8]和str3[9]這種呢?

這種情況就需要多個strncpy_s語句了,因為每一句只能進行一次復制和賦值,多次才能完成上述任務。

此時我們就需要去操作第1個參數了,即str4,因為str4也是一個數組名表示地址,所以我們這樣分散復制時,后面幾次復制就需要從str4的str4[2]開始賦值了。

我們來看一下完整代碼:

  1.  
    // strncpy_s.cpp
  2.  
    //
  3.  
     
  4.  
    #include "stdafx.h"
  5.  
    #include <iostream>
  6.  
    #include <cstring>
  7.  
     
  8.  
    int main()
  9.  
    {
  10.  
    using namespace std;
  11.  
     
  12.  
    char str1[5] = "abcd";
  13.  
    char str2[10] = "leonardo";
  14.  
    cout << "str1 is " << endl << str1 << endl;
  15.  
    cout << "str2 is " << endl << str2 << endl;
  16.  
    strncpy_s(str2, sizeof(str2), str1, 3);
  17.  
    cout << "after the copy str2 is " << endl << str2 << endl;
  18.  
    cout << endl;
  19.  
     
  20.  
    char str3[100];
  21.  
    char str4[10];
  22.  
    cout << "Please enter your favorite lines (Warning: No longer than 100!):\n";
  23.  
    cin.getline(str3, 100);
  24.  
    cout << endl;
  25.  
    strncpy_s(str4, sizeof(str4), str3 + 2, 1);
  26.  
    strncpy_s(str4 + 1, sizeof(str4) - 1, str3 + 5, 1);
  27.  
    strncpy_s(str4 + 2, sizeof(str4) - 2, str3 + 8, 2);
  28.  
    cout << "str3 is " << endl << str3 << endl;
  29.  
    cout << "while str4 is " << endl << str4 << endl;
  30.  
     
  31.  
    system( "pause");
  32.  
    return 0;
  33.  
    }

上述代碼的第25,26,27三行都是在進行strncpy_s函數的復制,可以看到我們分了3次復制,因為str3[2],str3[5]都只能單獨復制,因為不連續,而str3[8]和str3[9]可以聯合復制,因為連續。

上述代碼運行結果如下圖所示:

從圖中可以看到,str3[2]是‘ ’,str3[5]是'm',str3[8]是'i',str3[9]是's'。

所以這樣我們就完成了分散復制的功能了。

目前我掌握的有關strncpy函數和strncpy_s函數的使用及注意事項就是這樣,以后繼續學習遇到新的知識了會持續補充。


免責聲明!

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



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