C考试字符数组

3

我正在做去年的C编程考试。我写了以下程序:

该程序(见下文)定义了变量x和y。

它产生了给定的输出结果。请解释为什么变量x的输出中出现了字符“A”。

程序:

#include <stdio.h>
main ()
{
    char x[6] = "12345\0";
    char y[6] = "67890\0";
    y[7]='A';
    printf("X: %s\n",x);
    printf("Y: %s\n",y);
}   

程序输出: X:1A345 Y:67890


它有相当高的分数(7)。我不知道如何详细解释它。我的答案是:

字符数组(y)只分配了6个字符,因此更改第7个字符将更改堆栈中其后面的任何内容。

非常感谢任何帮助!(我只是一年级学生)


5
向你的教师展示这个链接 - Eugene Sh.
1
利用考试题目而不是编程入门。 - Mercurial
1
@EugeneSh。(没错。这种老师应该立即被解雇。) - The Paramagnetic Croissant
我对堆栈在内存中的布局不太了解,但如果输出是由于 y[7] = A 导致的,那就意味着变量是 反向 排序的。 xy 之前被声明 - 不是吗?这对我来说似乎很奇怪。 - Tamás Szabó
1
@user1717828 www.paulikas.eu/SCC150.pdf - PiDEV
显示剩余7条评论
2个回答

5
您的正式答案应该是这个程序产生了“未定义的行为”。
C语言标准没有定义越界访问操作的结果。
使用“char y[6]”,通过读取或写入“y[7]”,这正是您所做的。
一些编译器可能会选择在堆栈中立即分配数组“x[6]”紧随数组“y[6]”之后。
因此,通过将“A”写入“y[7]”,这个程序确实可能将“A”写入“x[1]”。
但是标准并不规定这一点,因此它取决于编译器的实现。
正如其他人在回答您的问题的评论中暗示的那样,如果这确实是正式考试的题目,那么您可能需要考虑继续在其他地方学习......

1
恕我直言,我不同意“如果这个问题出现在考试中,那就去别的地方学习”的评论。我的老师是个不错的人,我们在C语言入门课程中遇到了一个非常类似的问题。当他把我们的试卷还给我们时,他宣布整个班级都错了,并且他不会计算这道题的分数。在随后的几次考试中也有类似的问题。这就是他让我们记住C语言中一些更为严重的怪癖的方法,直到今天。 - Code Different
3
首先,如果我的陈述听起来有些傲慢或自以为是,我深表歉意。这并非本意。但是恕我直言,如果你的老师在考试中给出类似的问题,然后声称整个班级都错了而将其排除在外,那么要么他不够诚实承认他在提出这样的问题时犯了错误,要么他缺乏足够的知识去理解这个问题本身就是错误的。“解释变量x的输出中为什么会出现字符‘A’”--没有任何保证'A'会出现在x中! - barak manos
我想你理解了我的评论。我们在课程中使用了标准化的C编译器,该编译器将返回与此问题相同的结果。然后他解释说这实际上是未定义的。即使它是多项选择题,我们也应该标记为“未定义”。在随后的测试中,他有意插入了更棘手的问题。任何能够正确指出标准(C89)所说的内容的人都会得到额外的分数。他把许多这样的怪癖钻进了我的脑子里。 - Code Different
我们中的许多人当时认为他是个混蛋,但多年后,我开始理解他为什么那样做。他通过证明这些问题与我们的期望相差甚远来突出了这些问题。教学不仅仅是给分数。 - Code Different
1
@ZoffDino:我承认我从未听过“标准化C编译器”的术语。可能有这样的东西,也可能没有。但无论如何,这样的编译器不会改变C语言本身的标准。而且该标准并未定义本地变量的分配-不是它们在堆栈中的顺序,也不是它们应该首先在堆栈上分配的事实。事实上,我不确定标准甚至是否定义了堆栈是什么。编写仅适用于一个编译器而不一定适用于其他编译器的代码是一个严重的缺陷,这可能导致你处理极其困难的错误! - barak manos
2
归根结底,你的老师可能会给你一个类似的问题,并期望你回答“未定义的行为”,但手头上的问题明确说明字符 'A' 出现在数组 x 中,并不一定是真的。 - barak manos

2

在C语言中,经典的堆栈溢出问题。通过调试器的帮助,您会发现在原始赋值之后,您的框架堆栈将如下所示:

67890\012345\0

y指向字符6y[7]表示在此之后的第7个位置(2)。因此,y[7] = 'A'替换了字符2。

在C标准中,访问数组超出边界是未定义的,这是C语言中需要注意的另一个怪异之处。一些参考资料:


但是 xy 之前声明。它们不应该在内存中按相同顺序吗? - Tamás Szabó
你知道什么是*堆栈(stack)吗?后进先出。这就是为令yx之前的原因。 - Code Different
Zoff Dino,谢谢。如果我们改变x[7] = 1会发生什么?那将超出堆栈并更改程序代码吗? - PiDEV
@PiDev 这对于这个小例子可能没有影响。但对于更复杂的程序,它可能会导致段错误。要真正理解它,你需要了解C语言的内存布局: http://www.geeksforgeeks.org/memory-layout-of-c-program/ - Code Different
@Tamás Szabó,即使在x声明在y之前,C也不要求先寻址x的内容再寻址y。编译器可能一天这样做,另一天就会以不同的方式编译。为了让x y有一定的顺序,请将它们放入一个结构中。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接