关于C语言字符串结束符使用注意事项

关于字符串结束符使用注意事项

前言

本文讲解在自己建立解析函数中由于需要获取某一较长字符串中部分信息,
打印时经常在末尾出现多打印的情况,造成很多困惑,如果你也有该方面困惑,
请详细阅读本文,避开以后该方面的应用误区。如果你也有好的解决方法可评论推荐
交流。

1、问题内容:

如下该程序需要提炼str函数有效信息:“123.168.234.555,port:58080”,该程序为解析上述结果的程序。

#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
char str[]="clientIP:123.168.234.555,port:58080;";//待解析的字符串

int main()
{
  char buff[27];//定义接收空间数组
  char *strfirst=NULL;//前地址
  char *strnext=NULL;//后地址
  strfirst=str;//将待解析字符串地址赋值给前地址用作截取操作
  strfirst=strstr(strfirst,":");//从strfirst指向的地址找到":"开始的地址并将该地址赋值给strfirst
  strfirst++;//strfirst自行偏移1,即指向str字符串1的位置。
  strnext=strstr(strfirst,";");//从strfirst指向的位置找到";"所在的地址位置将该地址赋值给strnext
  memcpy(buff,strfirst,strnext-strfirst);//从strfirst指向的位置,复制strnext-strfirst字节个字符(即将"1"到";"之间)到buff
  printf("mall:%d\r\n",strlen(buff));//打印buff字符串的长度
  printf("len:%d\r\n",strnext-strfirst);//打印strnext与strfirst之间的距离
  printf("strfirst:%s\r\n",buff);//打印复制后的buff
  return 0;
}

程序运行结果如下:
在这里插入图片描述
是否存在该疑问,如上述结果明明在strnext与strfirst之间打印为:26,结果却复制了整整30(strlen(buff)=30如上图运行结果),多出的“<a�U”到底是个啥???

2、考究

这个问题正式因为你在使用memcpy过程中,未拷贝字符串结束符“\0”的缘故,以至于C编译器会在复制后的字符串乱加东西。由于字符串就是在编译过程中由系统自己加上的。所以你在定义字符串的时候一般都会预留一个空间如下示例:

 char str[7]="123456";//预留让编译器自动添加结束符
 char str[]="123456";//实则与str[7]相等
 char str[]={'1','2','3','4','5','6'};//不会存在自动添加\0
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
char str[]=" 123456";//三种定义方式
char str1[7]="123456";
char str2[6]={'1','2','3','4','5','6'};
int main()
{
   printf("str:%s\r\n",str);//打印字符串
   printf("str1:%s\r\n",str1);
   printf("str2:%s\r\n",str2);
   printf("len:%d\r\n",strlen(str));//打印所有长度
   printf("len1:%d\r\n",strlen(str1));
   printf("len2:%d\r\n",strlen(str2));
   return 0;
}

运行结果:
str: 123456
str1:123456
str2:123456
len:7
len1:6 //真实使用
len2:6

结论:
str长度实则为7因为会自动开辟一字节作为"\0"
str1长度为6但是他会自动在第七个位置自动添加“\0”
str2未添加“\0”
上面的结论可能还是一头雾水我们将上面的程序修改下

#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
char str[]=" 123456";
char str1[7]="1234567";//修改
char str2[6]={'1','2','3','4','5','6','7'};//修改
int main()
{
   printf("str:%s\r\n",str);
   printf("str1:%s\r\n",str1);
   printf("str2:%s\r\n",str2);
   printf("len:%d\r\n",strlen(str));
   printf("len1:%d\r\n",strlen(str1));
   printf("len2:%d\r\n",strlen(str2));
   return 0;
}

结果:
str: 123456
str1:1234567123456
str2:123456
len:7
len1:13
len2:6
此时由于str1占用预留的一个字节空间及str1[6]位置使系统无法添加“\0”打印内容竟然为“1234567123456” len1:为13字节 因此出现了错误。
但是str2 虽然越界添加内容,任然局限在字符串总长度内因此可以推断该定义方法不会自动加“\0”。

其实在很多操作过程中“\0”很重要,printf以%s打印需要查找打印串的“\0”停止,strlen查询“\0”停止等等,注意:上面的例子str2非字符串形式定义。

3、解决方案:

在网上冲浪了一番后,向该方面的问题有人提及就是解决方法有点少,或者方法拿过来吧不太可行,在某些编译器编译不过。
网上有人亲测sprintf函数可以添加结束符,但是这种方法亲测还是会出现在结尾乱加内容现象。
方法1:建议自己添加一个文件结束符,放法很简单:

#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
char str[]="clientIP:123.168.234.555,port:58080;"; 
int main()
{
  char buff[27];
  char *strfirst=NULL;
  char *strnext=NULL;
  strfirst=str;
  strfirst=strstr(strfirst,":");
  strfirst++;
  strnext=strstr(strfirst,";");
  memcpy(buff,strfirst,strnext-strfirst);
  *(buff+(strnext-strfirst))='\0';//在字符串末尾添加一个结束符
  printf("mall:%d\r\n",strlen(buff));
  printf("len:%d\r\n",strnext-strfirst);
  printf("strfirst:%s\r\n",buff);
  return 0;
}

运行结果:
mall:26
len:26
strfirst:123.168.234.555,port:58080
注意:buff开辟的空间一定要有富裕的空间来添加“\0”,否则会产生越界影响,虽然在本例可正常打印正确结果,但是在空间地址操作上会存在致命错误。

方法2:使用memset清空源串
在每次需要给源串复制内容前可使用memset(scr,0,len);一次清空源串,这样就无需手动复制文件结束符了!!!

#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
char str[]="clientIP:123.168.234.555,port:58080;"; 
int main()
{
  char buff[27];
  char *strfirst=NULL;
  char *strnext=NULL;
  strfirst=str;
  strfirst=strstr(strfirst,":");
  strfirst++;
  strnext=strstr(strfirst,";");
  memset(buff,0,strlen(buff));//修改此处
  memcpy(buff,strfirst,strnext-strfirst);
  printf("mall:%d\r\n",strlen(buff));
  printf("len:%d\r\n",strnext-strfirst);
  printf("strfirst:%s\r\n",buff);
  return 0;
}

说明:
在串中使用memset(scr,0,strlen(scr))与memset(scr,0x30,strlen(scr))是不同的第一个相当于清空源串赋值的内容为NULL,而第二种情况0x30在ascll码中是0赋值的是字符0

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值