我有以下一段代码,我希望它会失败,但似乎工作正常。 我很困惑为什么这不会导致某种分段错误。
#include <stdio.h>
#include <stdlib.h>
struct entry {
int foo;
};
struct table {
int size;
struct entry* entries;
};
typedef struct table *Table;
typedef struct entry Entry;
int main() {
Table table = malloc(sizeof(struct table));
table->entries = malloc(sizeof(struct entry) * 1);
(table->entries)[5].foo = 5;
for (int i = 0; i < 10; i++) {
printf("Entry #%d: %dn",i,(table->entries)[i].foo);
}
}
我本以为,由于我只为表>条目中的一个条目分配了足够的空间,因此访问 0 以外的任何索引都是越界的。 但是当我运行这个程序时,它会打印出 5 作为索引 5 处条目的 foo 值,其余为 0,这是正确的行为。 为什么这没有失败?
其他人会说得更好,但未定义的行为是未定义的。
它没有定义。它可能会起作用。未必。
这完全取决于这些内存位置中的内容。
你写了一个不好的位置。你读了一些其他的。你碰巧没有撞到任何东西太重要了。
你写了一个字,远远超过了你的错误区域。也许如果你做了更多的计算这会造成麻烦,因为您写入了 Malloc 的数据结构。也许不是。
您正在越界访问,但这只会调用"未定义的行为"。 当您调用"未定义的行为"时,任何事情都可能发生。一种可能性是程序崩溃;另一个是程序没有崩溃并且看起来没问题。 任何一种都是可能的;它有时甚至可能崩溃,有时不崩溃。
如果您尝试了更多的内存分配,或者尝试释放内存,你更有可能看到事情出了问题。 但是,即使这样也不能保证;您可能错过了所有敏感信息(malloc()
et al 用于确定分配了哪些内存和未分配哪些内存的字节数)。
你可以写:
table->entries[i].foo
你不需要(table->entries)[i].foo
周围的括号,尽管它们是无害的,除了它们表明新手正在编码。
它不会失败,因为尽管您正在写入未分配的内存,但该内存完全位于合法的堆空间内。但是,您没有向内存管理器声明您正在使用该内存空间,未来的malloc()
可能会尝试分配给同一区域,并且您将获得重叠的缓冲区和未定义的行为。
您正在访问不属于"您的"内存位置的未定义行为。您在内存中编写了一些不是由您分配的东西,从而损坏了该内存位置。
#include <stdio.h>
#include <stdlib.h>
struct entry {
int foo;
};
struct table {
int size;
struct entry* entries;
};
typedef struct table *Table;
typedef struct entry Entry;
int main() {
Table table =(table)malloc(sizeof(struct table));
table->entries =(entry*)malloc(sizeof(struct entry) * 10);
(table->entries)[5].foo = 5;
for (int i = 0; i < 10; i++) {
printf("Entry #%d: %dn",i,(table->entries)[i].foo);
}
}
首先,您需要在使用 malloc
时将 (void*) 类型转换为所需的指针类型。其次,你只分配条目指针,这意味着,当你使用(table->entryries)[5].foo 时,你可能会非法访问内存,所以这是一种危险的行为。最后,您需要在打印之前初始化foo
。你需要遵守规则,不要写这样的代码。