顶级太阳 发表于 2022-7-8 15:59:56

s1e19测试题2的一点疑问

本帖最后由 顶级太阳 于 2022-7-8 16:02 编辑

小甲鱼在s1e19测试题2中提出要求,指出代码里面的问题。并给出了代码如下。答案里指出这个代码会造成字符串连接过程中超出数组定义的空间。很好奇,抄下来运行了一下,同时增加了一个输出数组的语句,结果让我很是吃惊。
#include<stdio.h>
#include<string.h>
int main()
{
        char str;
        strncat(str,"I love FishC.com!",sizeof(str));
        printf("%s\n",str);
        printf("%ld\n",sizeof(str));

return 0;
}


运行结果如下:


结果中,输出数组结果前面多了一个“@”符号。数组str没有进行初始化,开始考虑是某一个不可预知的初始值,后来考虑是直接连接的,那么程序认为数组里应该是没有数据的,应该是从第一个字符开始填入,也就是str,那么应该没有这个字符存在。不同时段,重复开关机测试结果都是这样。而且下一句测试数组长度,输出为10,表示数组大小并没有改变,人工数了连接进去的字符,也是10个。输出11个字符,这个我可以理解,毕竟连接后,结束符在接入的10个字符的后面。那么问题就集中到了最前面的“@”是怎么来的了。求教,最前面的“@”怎么出现的?


补充一下:我用的系统是虚拟机Ubuntu16.4.6系统。是不是和这个有关?主要是小甲鱼的答案里没有提这方面的事。很不明白。

临时号 发表于 2022-7-8 16:10:58

我运行没有问题

可能真的跟你的虚拟机有关系

风车呼呼呼 发表于 2022-7-8 17:49:31

1.声明了一个数组,那么它的内存大小就是固定的,不要以 %s 打印出 str 看到10个以上的字符,就以为数组变大了。%s 本就是以 str 作为首地址,以 '\0' 作为结束标志,根本不管是否在str的合法空间。

2.内存里不管你是否初始化,都是有数据的,只是你自己不初始化就无法预测到内存里的数据是什么内容,也就是脏数据。所以不存在什么认为数组里没数据,就从str开始连接。

3.strncat() 本质就是连接2个字符串,也就是找到第一个字符串的末尾(即'\0'),将第二个字符串填入后面的内存空间。以 str 为首地址往后找,直到找到 '\0',在你不初始化的情况下,后面10字节空间(即数组合法空间)可能会有 '\0',也可能没有,就算没有也会继续往后找,直到在内存中发现 '\0',将第二个字符串接入。之后你用 %s 打印同理,你看到的原第二字符串的内容,未必就存在那10字节的数组空间中。而原第一字符串的脏数据就会导致第二字符串前乱码的出现

顶级太阳 发表于 2022-7-9 09:23:50

风车呼呼呼 发表于 2022-7-8 17:49
1.声明了一个数组,那么它的内存大小就是固定的,不要以 %s 打印出 str 看到10个以上的字符,就以为数组变 ...

1、我用%s打印str字符串纯粹是为了好奇在没有初始值的情况下会发生什么,并没有感觉数组变大了。我能够理解C语言在这一块做的很不好。
2、所谓脏数据应该是不能预知的,每次程序运行由于分配的地址不同,基本没有相同的可能的数据。那么每次运行程序的时候,这个脏数据应该是不同的(碰上相同的几率应该极小)。
3、同第2.
刚刚看到你的回复后,我第3次关闭了虚拟机,关闭电脑,做到了硬件重启,第4次尝试运行这段代码,得到的结果和前面是一致的。数组值输出得到的还是:@I love Fis
我没有别的意思,只是纯粹的好奇,为什么前面的脏数据一直是一个@,然后紧接着一个结束符‘\0'。

风车呼呼呼 发表于 2022-7-9 12:55:13

顶级太阳 发表于 2022-7-9 09:23
1、我用%s打印str字符串纯粹是为了好奇在没有初始值的情况下会发生什么,并没有感觉数组变大了。我能够理 ...

一直是@,这与不同系统的内存管理有关,也许系统给整个程序分配内存时已经进行了某种初始化。正如我在win10系统下运行,前面的乱码是“烫烫烫烫”一样。
另外,在实际测试之前,也不能断定脏数据就是 @加一个‘\0’,因为脏数据里解释成字符的未必全是可打印字符,有的被解释成非打印字符(如控制字符)你是看不出来的,严谨一点的方法就是把数组里的每个元素单独打印,就会知道原本的 '\0' 前到底有多少字节
页: [1]
查看完整版本: s1e19测试题2的一点疑问