让你提前认识软件开发(10):字符串处理函数及异常保护-阿里云开发者社区

开发者社区> 周兆熊> 正文

让你提前认识软件开发(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,欢迎关注!)

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
2014秋C++第13周项目3参考-成绩处理函数版
课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,课程资源在云学堂“贺老师课堂”同步展示,使用的帐号请到课程主页中查看。  【项目3 - 成绩处理函数版】项目2的另一种实现。输入、求最大/小值等所有功能都通过自定义函数完成。这种设计貌似比项目2麻烦,但其结构有更多的优点,尤其是当程序的规模更大时。通过这个项目,学会将数组
798 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4615 0
iOS 下APNS推送处理函数详解
相比起Android,iOS在推送方面无疑惯例得更好。APNS(Apple Push Notification Service)是苹果公司提供的消息推送服务。其原理就是,第三方应用将要推送给用户的信息推送到苹果服务器,苹果服务器再通过统一的系统接口将这些信息推送到用户的手机上。如果对此不舍了解的朋友可以参见这篇文章:一步一步教你做ios 推送 本文着重叫在App端如何处理推送信息。主
1319 0
【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--控制器和处理函数的注册篇(4/8)【controller+action】
文章目录 前情概要 前边的文章把一些基本的前置任务都完成了。接下就是比较重要的处理函数action是如何自动发现和注册的拉,也就是入口函数RouteHandler(也是我们的第一个express中间件)里面的一些细节。
689 0
React的事件处理函数
React 的事件名称都是使用驼峰标识(比如camelCase) 通过 JSX 可以传递一个函数作为事件处理 HTML: Activate Lasers React: ...
807 0
bboss分页组件翻页js前置处理函数和js后置处理函数使用方法
bboss 3.7.7版本及后续版本为分页组件增加翻页js前置处理函数和翻页js后置处理函数,本文介绍使用方法。 1.说明: 为了实现这个功能,对/include下面的pager.js文件做了重构,将所有的分页处理函数封装到bboss.pager对象中。
733 0
+关注
周兆熊
硕士研究生毕业于南京邮电大学计算机应用技术专业,曾在中兴通讯从事软件开发工作,现就职于重庆某物联网技术公司,任高级嵌入式软件开发工程师。著有《C程序员从校园到职场》一书,同时也是《信息通信技术百科全书》的编者之一及CSDN博客专家。QQ(微信):245924426。
357
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载