我已经阅读了一个类似的问题(why this code works in C),但它实际上并没有解释为什么这段代码实际上有效:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct example
{
char length[2];
} STRUCT;
int main (void)
{
STRUCT test;
strcpy(test.length, "********");
puts(test.length);
return 0;
}
我正在使用CodeBlocks来编译它,所以我想它是在我的字符串中分配更多的空间来存储默认的额外星号......我真的不知道。也许我只是幸运,但每次我运行它都有效。
在我上面展示的示例(链接)中,他将2个元素放在2的数组中,这里我使用了比字符串可以处理的更多空间,或者可以。或者可以。
答案 0 :(得分:3)
C不检查数组边界。 Ricky Mutschlechner在评论中指出,它会导致缓冲区溢出和未定义的行为。
答案 1 :(得分:1)
这是未定义行为的一个例子(正如人们在评论中提到的那样)。
至于为什么这有效,它很可能是由于堆栈对齐。因此,当您声明STRUCT test
时,即使它只需要堆栈上的两个字节,编译器也会将堆栈对齐(通过向结构添加额外的填充),因此在{{1}之后获得额外的未使用空间} {,test
写入。因为程序的其他任何部分都没有使用这个空间,所以它给人一种没有问题的工作幻觉。
答案 2 :(得分:1)
你很幸运。
结构只被声明为两个字节长,但编译器或运行时可能会分配更多,或者只是不关心struct
之后的内存位置 - 事实是{{1将覆盖strcpy
之后的内存,如果在更大的上下文中使用,它最终会覆盖一些对其他东西至关重要的内存,它会根据你的内存类型产生灾难性的错误已被覆盖以及它被用于什么。
在你的情况下,程序只是退出,所以机会(幸运的是)没有人会使用你已经损坏的内存。
答案 3 :(得分:0)
它的工作原理是因为写入(但未分配)的内存未被此应用程序的其他部分使用。我不知道内存分配的工作原理以及大块的大小。 只需搜索更多细节。
它不会使操作系统崩溃,但会导致最坏的分段错误。
答案 4 :(得分:0)
它只是溢出你的堆栈,因为测试是在堆栈上。 目前它可能不会导致任何问题,但如果你在堆栈上声明一些更多的变量以及测试,那可能会导致一些问题
答案 5 :(得分:0)
您正在写入位于test.length
之后的堆栈内存中。为了更好地说明问题,我在代码中添加了两行:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct example
{
char length[2];
} STRUCT;
int main (void)
{
STRUCT test;
unsigned int foo = 42;
strcpy(test.length, "********");
puts(test.length);
printf("%u", foo);
return 0;
}
您可能希望printf打印42,但变量foo
会被strcpy覆盖。实际输出是,例如在gcc上,以下(你可以测试它here):
********
707406378