1. 程式人生 > 實用技巧 >C++中strncpy函式和strncpy_s函式的使用及注意事項

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

對於以上程式碼,執行結果如下圖所示:

由執行結果可知,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. #include "stdafx.h"
  4. #include <iostream>
  5. #include <cstring>
  6. int main()
  7. {
  8. using namespace std;
  9. char str1[5] = "abcd";
  10. char str2[10] = "leonardo";
  11. cout << "str1 is " << endl << str1 << endl;
  12. cout << "str2 is " << endl << str2 << endl;
  13. strncpy_s(str2, sizeof(str2), str1, 3);
  14. cout << "after the copy str2 is " << endl << str2 << endl;
  15. system("pause");
  16. return 0;
  17. }

執行結果如下圖所示:

於是回到我們最早那個程式碼,稍作修改使用strncpy_s函式,修改後程式碼如下:

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

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

上述程式碼的第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函式的使用及注意事項就是這樣,以後繼續學習遇到新的知識了會持續補充。