NapoleonWang 发表于 2017-4-11 11:15:25

问一个C语言上的问题

调试程序过程中,遇到了一个问题。如下:
#defineDEFAULT_SE          "000000 "   //有7个字符



char SerialNum;//定义一个数组


strcpy( SerialNum , DEFAULT_SE);//复制内存中的数据


i =strlen(DEFAULT_SE);
j=strlen(SerialNum);


结果打印出来的:
i=7
j>7(j是一个大于7的数)


我的疑问不确定,大家帮我分析下:
1、宏定义DEFAULT_SE虽然是7个字符,但是后面编译器自动加了一个\0 吗?,那实际上是不是有8个字符长度?
2、由于SerialNum 的定义只有七个字节宽度,导致strcpy(SerialNum, DEFAULT_SE)没有将\0复制过去,也就是SerialNum结尾没有\0,导致计算得j>7呢?


另外,看了一下百度百科对C语言中strcpy的介绍:
C语言标准库函数strcpy,把从src地址开始且含有'\0'结束符的字符串复制到以dest开始的地址空间。
也就是说strcpy这个函数是把最后的\0复制过去的,根本原因是我这个地方定义数组内存不够导致的,是这样的吗?


还请各位老师指教。谢谢。

moyanming2013 发表于 2017-4-11 11:15:26

本帖最后由 moyanming2013 于 2017-4-11 12:30 编辑

MrJiu 发表于 2017-4-11 11:43
首先,你要去小学进修一下下!!!"000000 "->这只有6个0,不是7个;
其次,字符串很显然是会在后面加\0的 ...

楼主只说有7个字符(没说7个0),这个没毛病。
潜在的毛病是:
1.strcpy会通过判断‘\0’来遍历DEFUALT_SE,然后把所有的有效字符都复制到SerialNum里面,你没有在这里死机是因为:刚好第7个字符是‘\0’也就不再复制了,虽然这里没死机,但是这是你碰上了,而不是你的业务能力好(反而明显的暴露了你的水平)。这种写法虽然没死机但实际是错误的(如下述)!
2.一般,定义一个字符串,然后使用C库里面的字符串处理函数,比如strlen、strcpy等等,都需要确保最后必须有个‘\0’,C库函数都是用‘\0’来判断遍历的结束的,所以,对于SerialNum来说执行完strcpy后,它里面没有‘\0’,导致的结果是后续对SerialNum用C库函数都会有死机的风险,而且风险巨大。编译器对显示字符串都会在其最后自动添加一个‘\0’。
3.上述C库是老库,你可以用诸如strncpy等带有‘n’的保险的c库函数,在一些时候它可以给你“我是对的”的假象,其实你是碰上了,但实际是错误的。再者,你可以自己写一些类似的函数而不用关注‘\0’,但必须指定真实的长度,比如针对SerialNum,真实长度是7,必须时刻跟着长度!这个时候,往往把它做成一个结构体,一个数组成员str,一个实际长度成员strLen。此时就可以不用特殊的‘\0’了(节省了1个字节),因为我们自己处理。

MrJiu 发表于 2017-4-11 11:43:26

首先,你要去小学进修一下下!!!"000000 "->这只有6个0,不是7个;
其次,字符串很显然是会在后面加\0的,否则就不叫字符串了;
最后,至于你说的j打印出来的值是大于7的...我觉得不太可能,因为SerialNum的内存是够存储的!!!当然,除非你把"000000 "6个0变成7个0,这样SerialNum就不够存储了!!但是,strcpy和strlen都是以检测\0作为检测结束符,所以,有可能数组溢出,进而导致跑飞!!!!

NapoleonWang 发表于 2017-4-11 13:10:16

MrJiu 发表于 2017-4-11 11:43
首先,你要去小学进修一下下!!!"000000 "->这只有6个0,不是7个;
其次,字符串很显然是会在后面加\0的 ...

首先确实是六个0,后面加个空格。一看到你说的前一句,下面的就懒得看了。还是看看楼下的兄弟解答吧。;olo

NapoleonWang 发表于 2017-4-11 13:29:25

:'(bu neng da zi,bu nenghui fu .shen me qing kuang .wo xiang hui lou shangde .

NapoleonWang 发表于 2017-4-11 13:46:03

moyanming2013 发表于 2017-4-11 12:26
楼主只说有7个字符(没说7个0),这个没毛病。
潜在的毛病是:
1.strcpy会通过判断‘\0’来遍历DEFUALT_S ...

weishenmebunengda zi ......

MrJiu 发表于 2017-4-11 13:48:53

moyanming2013 发表于 2017-4-11 12:26
楼主只说有7个字符(没说7个0),这个没毛病。
潜在的毛病是:
1.strcpy会通过判断‘\0’来遍历DEFUALT_S ...

注意楼主的下面言论,第7个不是指\0的,然后楼主补充了一下,后面有个空格...说实话这个空格完全就是考虑人的眼神啊,

MrJiu 发表于 2017-4-11 13:51:59

NapoleonWang 发表于 2017-4-11 13:10
首先确实是六个0,后面加个空格。一看到你说的前一句,下面的就懒得看了。还是看看楼下的兄弟解答吧。;ol ...

首先,你这个问题完全就是误导人啊!!!!鬼会注意别人的空格!!!
其次,我下面的解释恰好是完全正确的,注意我说了这么一句话:至于你说的j打印出来的值是大于7的...我觉得不太可能,这是基于我没有注意到空格的前提得出的结论....如果是由空格,那j的值就是一个看情况,未知的值,因为完全取决于这个只指针自加的时候,什么时候指到的值是\0就结束!!!

moyanming2013 发表于 2017-4-11 15:12:29

MrJiu 发表于 2017-4-11 13:48
注意楼主的下面言论,第7个不是指\0的,然后楼主补充了一下,后面有个空格...说实话这个空格完全就是考虑 ...

我当然看到有个空格啦,我看你的回复你是没看到这个空格。
还是我说的,7个字符没错啊:6个0+1个空格=7个字符,你说楼主(红框部分):

楼主没说有7个0啊!再说了,楼主说7个字符也没错啊(是你少看了1个空格)。要我说不要在眼神上下文章,这个眼神完全不是重点,重点是没看清还胡说。
哎~~再再说了,你作为版主怎么能这么说楼主呢,要是大家什么都会,还要论坛干什么,还要工作干什么,去大街上等风把钱刮过来就行了。不能以为自己是版主就开始卖弄,更不能侮辱别人!子曰“三人行,必有我师焉”。
请问你只发过3个主题帖,怎么当上的版主?

moyanming2013 发表于 2017-4-11 15:34:59

我3楼(https://www.stmcu.org.cn/module/forum/forum.php?mod=redirect&goto=findpost&ptid=611439&pid=2252309&fromuid=3089512)讲了那么多理论还没看明白啊,我还是针对你的问题通俗点回答你吧:
1.编译器会自动给显示字符串加1个字符‘\0’,但实际上字符长度是7。
注意:编译器自动加个字符,也会自动管理这里面的内存分配。这和字符数组不同,字符数组的大小是确定的,内存分配也是确定的,故要给出1个空余字节来存放‘\0’,否则参考我回复的3楼里面的第3条。
2.strcpy什么都不知道,只知道复制内存,遇到‘\0’就停止。同时为了保证C字符串的完整性,会把这个‘\0’添加到(或复制到)目的地址。此时,因为SerialNum的大小是7,所以往第7个下标写‘\0’时会死机,但这里没死机,没死机是个意外,死机才是正常的,我分析可能是由于字符对齐、编译器优化等等才会没死机,致使第7个内存位置是可读写的位置。因为SerialNum的大小是7,此时该数组里面没有‘\0’,当使用C库函数strlen(SerialNum)时,至少在前7个字节中找不到结束标识‘\0’,故j>=7,没死机你很万幸,但完全是错误的!因为strlen会继续找下去直到碰到‘\0’才停止,你想想会如何呢?会碰到不可读的内存,此时会出现硬件错误!
页: [1] 2
查看完整版本: 问一个C语言上的问题