0

我有以下代码,我预计会失败,但似乎工作正常。我对为什么这不会导致某种分段错误感到困惑。

#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: %d\n",i,(table->entries)[i].foo);
    }
}

我本来预计,由于我只为 table->entries 中的一个条目分配了足够的空间,因此访问 0 以外的任何索引都将超出范围。但是当我运行这个程序时,它打印出 5 作为索引 5 处条目的 foo 值,其余的为 0,这是正确的行为。为什么这没有失败?

4

5 回答 5

2

别人会说得更好,但未定义的行为是未定义的。

它没有定义。它可能会起作用。可能不会。

这一切都取决于这些内存位置中的内容。

你写了一个糟糕的位置。你读了一些其他的。你碰巧没有击中任何太重要的东西。

您在 malloc'ed 区域之外写了一个单词。也许如果你做了更多的计算会导致麻烦,因为你写入了 malloc 的数据结构。也许不吧。

于 2013-10-01T02:01:48.183 回答
1

正在越界访问,但这只会调用“未定义的行为”。当您调用“未定义的行为”时,任何事情都可能发生。一种可能是程序崩溃;另一个是程序没有崩溃并且看起来还可以。两者皆有可能;它有时甚至可能崩溃,有时不崩溃。

如果您尝试更多的内存分配,或者尝试释放内存,您将更有可能看到事情出错了。但是,即使这样也不能保证;您可能错过了所有敏感信息(malloc()et al 使用这些字节来确定分配了哪些内存,哪些没有分配)。

你可以写:

table->entries[i].foo

你不需要括号(table->entries)[i].foo,尽管它们是无害的,只是它们表明一个新手正在编码。

于 2013-10-01T02:03:43.343 回答
0

它没有失败,因为尽管您正在写入未分配的内存,但该内存完全位于合法的 HEAP 空间内。但是由于您没有向内存管理器声明您正在使用该内存空间,未来malloc()可能会尝试分配到同一区域,并且您将获得重叠的缓冲区和未定义的行为。

于 2013-10-01T02:04:05.453 回答
0

这是未定义的行为,您正在访问不是“您的”的内存位置。你在内存中写了一些不是你分配的东西,破坏了那个内存位置。

于 2013-10-01T02:04:23.137 回答
0
#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: %d\n",i,(table->entries)[i].foo);
    }
}

首先,需要将 (void*) 类型转换为使用时需要的指针类型malloc。其次,您只分配条目指针,这意味着,当您使用 (table->entries)[5].foo 时,您可能会非法访问内存,因此这是一种危险的行为。最后,您需要foo在打印之前进行初始化。你需要遵守规则,不要写那样的代码。

于 2013-10-01T02:14:48.897 回答