让你提前认识软件开发(10):字符串处理函数及异常保护

简介: 第1部分 重新认识C语言字符串处理函数及异常保护         在软件开发项目中,经常有程序要对字符串进行操作。为此,C函数库中提供了一些用来对字符串进行处理的函数,使用起来非常的方便。

第1部分 重新认识C语言

字符串处理函数及异常保护

 

        在软件开发项目中,经常有程序要对字符串进行操作。为此,C函数库中提供了一些用来对字符串进行处理的函数,使用起来非常的方便。但由于字符串都有长度,如果随意对不同的字符串进行连接和拷贝等操作,就可能出现意想不到的后果。

       因此,在实际开发过程中,十分强调对字符串处理函数进行异常保护。本文详细介绍如何正确运用字符串处理函数进行C程序设计。

 

       1. strcatstrncat函数

        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字符串拼接到strDestination后面,最后的返回值是拼装完成之后的字符串strDestination

        这里有一个问题,如果字符串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. strcpystrncpy函数

         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. strcmpstrcnmp函数

         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函数之外,C语言函数库还提供了一个叫做strncmp的函数用于字符串的比较。在MSDN中,其定义为:

        int strncmp( const char *string1, const char *string2, size_t count );

        Remarks: The strncmp function lexicographically compares, at most, the first count characters in string1 and string2 and returns a value indicating the relationship between the substrings.

        strncmp函数只比较两个字符串数组的前count个字符,如果返回值小于0,则前一个字符串要小;如果返回值等于0,则两个字符串相等;如果返回值大于0,则前一个字符串要大。用strncmp函数替换strcmp函数后的代码如下:

/***************************************************************

*版权所有 (C)2014, Zhou Zhaoxiong

*

*文件名称:StrncmpTest.c

*内容摘要:用于测试strncmp函数

*其它说明:无

*当前版本: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);

      

       //调用strncmp函数,第三个参数也可以是strlen(szStrCmp2)

      iRetVal = strncmp(szStrCmp1, szStrCmp2, strlen(szStrCmp1));

 

       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;

}

        也许大家已经注意到了,如果两个字符串的前count个字符相同,而后面的字符不一样,那用strncmp函数判断出来的结果就不准确了。确实是这样的。在实际的软件开发项目中,strncmp函数可用于仅需判断某几位字符是否相等的流程中,strncmp函数不能替代strcmp函数。

 

        在学校学习C语言的过程中,并没有对字符串处理函数的异常保护进行过多的强调,这是学校教育的失误。在实际的软件开发项目中,很重视对代码的异常保护,这不仅涉及到产品质量,也关系到公司的声誉。因此,在编写程序的过程中,我们要时刻将异常保护牢记心中,这样才能写出健壮的、高质量的代码。


 

(欢迎访问南邮BBS:http://bbs.njupt.edu.cn/)
(欢迎访问重邮BBS:http://bbs.cqupt.edu.cn/nForum/index)

(本系列文章每周更新两篇,敬请期待!本人新浪微博:http://weibo.com/zhouzxi?topnav=1&wvr=5,微信号:245924426,欢迎关注!)

目录
相关文章
|
6月前
|
存储 自然语言处理 算法
通过实际的例子,介绍编译器的工作过程
通过实际的例子,介绍编译器的工作过程
44 0
feof用法重点详解(易被误用判断文件结束!!!)
feof用法重点详解(易被误用判断文件结束!!!)
|
C语言 C++
【异常机制高级讲解】异常与多态综合案例
【异常机制高级讲解】异常与多态综合案例
81 0