讓你提前認識軟體開發(10):字串處理函式及異常保護
第1部分 重新認識C語言
字串處理函式及異常保護
在軟體開發專案中,經常有程式要對字串進行操作。為此,C函式庫中提供了一些用來對字串進行處理的函式,使用起來非常的方便。但由於字串都有長度,如果隨意對不同的字串進行連線和拷貝等操作,就可能出現意想不到的後果。
因此,在實際開發過程中,十分強調對字串處理函式進行異常保護。本文詳細介紹如何正確運用字串處理函式進行C程式設計。
1. strcat和strncat函式
strcat函式的作用是連線兩個字元陣列中的字串。在MSDN中,其定義為:
char *strcat( char *strDestination, const char *strSource );
Remarks: The strcat function appends strSource to strDestination and terminates the resulting string with a null character. The initial character of strSource overwrites the terminating null character of strDestination. It returns the destination string (strDestination).
strcat函式將strSource
這裡有一個問題,如果字串strSource的長度大於了strDestination陣列的長度,就會出現陣列越界的錯誤,程式就會崩潰。如下程式碼所示:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrcatTest.c
*內容摘要:用於測試strcat函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值:無
*其它說明:無
*修改日期版本號修改人修改內容
* ------------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrDestination[10] = "Hello";
INT8 szStrSource[10] = "Hello123";
//先列印源字串和目的字串
printf("The source string is: %s\n", szStrSource);
printf("The destination string is: %s\n", szStrDestination);
strcat(szStrDestination, szStrSource); //呼叫strcat函式
//列印拼裝完成之後的字串
printf("The changed destination string is: %s\n", szStrDestination);
return 0;
}
在該段程式碼中,szStrDestination陣列的長度小於szStrSource中字串的長度,當利用strcat函式進行字串的連線操作時,異常就出現了。執行程式碼後彈出的異常框如下圖所示。
為了解決這個問題,在使用strcat函式之前,需要先對字串和字元陣列的長度進行比較,讓字串函式進行安全的連線操作,即保證最終字串的長度不超過目的字元陣列的長度。修改後的程式碼如下所示:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrcatTest.c
*內容摘要:用於測試strcat函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值:無
*其它說明:無
*修改日期版本號修改人修改內容
* -------------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrDestination[10] = "Hello";
INT8 szStrSource[10] = "Hello123";
//先列印源字串和目的字串
printf("The source string is: %s\n", szStrSource);
printf("The destination string is: %s\n", szStrDestination);
//對目的字元陣列的長度進行異常保護 begin
if (sizeof(szStrDestination) - strlen(szStrDestination) < strlen(szStrSource))
{
printf("The source string is too long!\n"); //列印異常訊息
return 1; //異常返回
}
//對目的字元陣列的長度進行異常保護 end
strcat(szStrDestination, szStrSource); //呼叫strcat函式
//列印拼裝完成之後的字串
printf("The changed destination string is: %s\n", szStrDestination);
return 0;
}
如上程式碼所示,當源字串太長時,程式便異常退出了,不會執行後面的字串連線操作。雖然可以保證程式的正常執行,但畢竟沒有完成我們想要的功能,有不有其他辦法呢?既能保證連線操作的正常進行,又不會讓程式彈出異常訊息框。
為了解決strcat函式可能出現的問題,C語言函式庫提供了一個叫做strncat的函式。在MSDN中,其定義為:
char *strncat( char *strDest, const char *strSource, size_t count );
Remarks: The strncat function appends, at most, the first count characters of strSource to strDest. The initial character of strSource overwrites the terminating null character of strDest. If a null character appears in strSource before count characters are appended, strncat appends all characters from strSource, up to the null character. If count is greater than the length of strSource, the length of strSource is used in place of count. The resulting string is terminated with a null character.
strncat函式只將strSource陣列中的前count個字元拼接到strDest陣列的後面。因此,不管strSource陣列中的字串有多長,只要count控制得當,都不會出現字串的越界錯誤。用strncat函式替換strcat函式後的程式碼如下:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrncatTest.c
*內容摘要:用於測試strncat函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值:無
*其它說明:無
*修改日期版本號修改人修改內容
* ----------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrDestination[10] = "Hello";
INT8 szStrSource[10] = "Hello123";
//先列印源字串和目的字串
printf("The source string is: %s\n", szStrSource);
printf("The destination string is: %s\n", szStrDestination);
//呼叫strncat函式
strncat(szStrDestination, szStrSource,sizeof(szStrDestination)-strlen(szStrDestination));
//列印拼裝完成之後的字串
printf("The changed destination string is: %s\n", szStrDestination);
return 0;
}
鑑於strcat函式的缺陷和strncat函式的優點,實際的軟體開發專案中,均推薦用strncat函式代替strcat函式來實現字串的連線。
2. strcpy和strncpy函式
strcpy函式的作用是將一個字元陣列中的字串拷貝到另外一個字元陣列中。在MSDN中,其定義為:
char *strcpy( char *strDestination, const char *strSource );
Remarks: The strcpy function copies strSource, including the terminating null character, to the location specified by strDestination. It returns the destination string.
strcpy函式將strSource字串拷貝到strDestination陣列中,最後的返回值是拷貝完成之後的字串strDestination。
這裡有一個問題,如果字串strSource的長度大於了strDestination陣列的長度,就會出現陣列越界的錯誤,程式就會崩潰。如下程式碼所示:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrcpyTest.c
*內容摘要:用於測試strcpy函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值:無
*其它說明:無
*修改日期版本號修改人修改內容
* -----------------------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrDestination[5] = {0}; //定義的同時,對變數進行初始化
INT8 szStrSource[10] = "Hello1234";
//先列印源字串和目的字串
printf("The source string is: %s\n", szStrSource);
printf("The destination string is: %s\n", szStrDestination);
strcpy(szStrDestination, szStrSource); //呼叫strcpy函式
//列印拷貝完成之後的字串
printf("The changed destination string is: %s\n", szStrDestination);
return 0;
}
在該段程式碼中,szStrDestination陣列的長度小於szStrSource中字串的長度,當利用strcpy函式進行字串的拷貝操作時,異常就出現了。執行程式碼後彈出的異常框如下圖所示。
為了解決這個問題,在使用strcpy函式之前,需要先對字串和字元陣列的長度進行比較,讓字串函式進行安全的拷貝操作,即保證被拷貝字串的長度不超過目的字元陣列的長度。修改後的程式碼如下所示:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrcpyTest.c
*內容摘要:用於測試strcpy函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值: 無
*其它說明:無
*修改日期版本號修改人修改內容
* -----------------------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrDestination[5] = {0}; //定義的同時,對變數進行初始化
INT8 szStrSource[10] = "Hello1234";
//先列印源字串和目的字串
printf("The source string is: %s\n", szStrSource);
printf("The destination string is: %s\n", szStrDestination);
//對目的字元陣列的長度進行異常保護 begin
if (sizeof(szStrDestination) < strlen(szStrSource))
{
printf("The source string is too long!\n"); //列印異常訊息
return 1; //異常返回
}
//對目的字元陣列的長度進行異常保護 end
strcpy(szStrDestination, szStrSource); //呼叫strcpy函式
//列印拷貝完成之後的字串
printf("The changed destination string is: %s\n", szStrDestination);
return 0;
}
如上程式碼所示,當源字串太長時,程式便異常退出了,不會執行後面的字串拷貝操作。雖然可以保證程式的正常執行,但畢竟沒有完成我們想要的功能,有不有其他辦法呢?既能保證拷貝操作的正常進行,又不會讓程式彈出異常訊息框。
為了解決strcpy函式可能出現的問題,C語言函式庫提供了一個叫做strncpy的函式。在MSDN中,其定義為:
char *strncpy( char *strDest, const char *strSource, size_t count );
Remarks: The strncpy function copies the initial count characters of strSource to strDest and returns strDest. If count is less than or equal to the length of strSource, a null character is not appended automatically to the copied string. If count is greater than the length of strSource, the destination string is padded with null characters up to length count. It returns strDest.
strncpy函式只將strSource陣列中的前count個字元拷貝到strDest陣列中。因此,不管strSource陣列中的字串有多長,只要count控制得當,都不會出現字串的越界錯誤。用strncpy函式替換strcpy函式後的程式碼如下:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrncpyTest.c
*內容摘要:用於測試strncpy函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值:無
*其它說明:無
*修改日期版本號修改人修改內容
* ---------------------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrDestination[5] = {0}; //定義的同時,對變數進行初始化
INT8 szStrSource[10] = "Hello1234";
//先列印源字串和目的字串
printf("The source string is: %s\n", szStrSource);
printf("The destination string is: %s\n", szStrDestination);
//呼叫strncpy函式,並進行長度判斷 begin
if (sizeof(szStrDestination) < strlen(szStrSource))
{
strncpy(szStrDestination, szStrSource, sizeof(szStrDestination));
}
else
{
strncpy(szStrDestination, szStrSource, strlen(szStrSource));
}
//呼叫strncpy函式,並進行長度判斷 end
//列印拷貝完成之後的字串
printf("The changed destination string is: %s\n", szStrDestination);
return 0;
}
鑑於strcpy函式的缺陷和strncpy函式的優點,實際的軟體開發專案中,均推薦用strncpy函式代替strcpy函式來實現字串的拷貝。
3. strcmp和strcnmp函式
strcmp函式的作用是進行字串的比較。在MSDN中,其定義為:
int strcmp( const char *string1, const char *string2 );
Remarks: The strcmp function compares string1 and string2 lexicographically and returns a value indicating their relationship. If return value < 0, string1 less than string2; if return value = 0, string1 identical to string2; if return value > 0, string1 greater than string2.
strcmp函式進行字串的比較時,如果前者大於後者,則返回值大於0;如果前者等於後者,則返回值等於0;如果前者小於後者,則返回值小於0。如下程式碼所示:
/***************************************************************
*版權所有 (C)2014, Zhou Zhaoxiong。
*
*檔名稱:StrcmpTest.c
*內容摘要:用於測試strcmp函式
*其它說明:無
*當前版本:V1.0
*作者:周兆熊
*完成日期:20140405
*
*修改記錄1: //修改歷史記錄,包括修改日期、版本號、修改人及修改內容等
* 修改日期:
* 版本號:
* 修改人:
* 修改內容:
***************************************************************/
#include <stdio.h>
#include <string.h>
typedef signed char INT8; //重定義資料型別
typedef signed int INT32; //重定義資料型別
/**********************************************************************
*功能描述:主函式
*輸入引數:無
*輸出引數:無
*返回值:無
*其它說明:無
*修改日期版本號修改人修改內容
* -----------------------------------------------------------------------------------------------
* 20140405 V1.0 周兆熊建立
***********************************************************************/
INT32 main(void)
{
INT8 szStrCmp1[10] = "Hello";
INT8 szStrCmp2[10] = "Hello";
INT32 iRetVal = 0; //定義的同時,對變數進行初始化
//先列印源字串和目的字串
printf("The first string is: %s\n", szStrCmp1);
printf("The second string is: %s\n", szStrCmp2);
iRetVal = strcmp(szStrCmp1, szStrCmp2); //呼叫strcmp函式
if (iRetVal < 0)
{
printf("string1 is less than string2\n");
}
else if (iRetVal == 0) //注意:是“==”,而不是“=”
{
printf("string1 is identical to string2\n");
}
else
{
printf("string1 is greater than string2\n");
}
return 0;
}
除了strcmp函式之外,