运行时检查失败#2 - 变量'obj'周围的堆栈已损坏

时间:2017-06-08 10:36:13

标签: c buffer-overrun

我得到运行时检查失败#2 - 当我运行以下代码时,在变量'obj'周围堆栈已损坏错误。我知道这是失败的,因为覆盖'obj'的边界会导致损坏堆栈。那么如何防止缓冲区溢出呢。

typedef struct _INFO {
    int Count;
} Info, *InfoPtr;

#define MAX_COUNT               10

//void fn(Info(*obj)[MAX_COUNT])
void fn(Info (*obj)[MAX_COUNT])
{
    for (int i = 0; i < 2; i++) 
    {
        obj[i]->Count = i;
    }
}

int main()
{
    Info    obj[MAX_COUNT];
    fn(&obj);
    return 1;
}

1 个答案:

答案 0 :(得分:5)

使用Info (*obj)[MAX_COUNT],您说obj是指向MAX_COUNT类型Info对象数组的指针。

然后你像obj[i]->Count = i一样使用它,它将obj视为指针Info个对象的数组。即Info *obj][]。不一样的事情。这会导致未定义的行为

解决方案非常简单,不要将指针作为参数传递给数组,并将其视为对象数组而不是指向对象的指针。

typedef struct Info {
    int Count;
} Info;

#define MAX_COUNT               10

void fn(Info *obj, const size_t elems)
{
    for (size_t i = 0; i < elems; i++) 
    {
        obj[i].Count = i;
    }
}

int main()
{
    Info    obj[MAX_COUNT];
    fn(obj, MAX_COUNT);
}

更改最明显的是fn函数声明,它将指针带到Info。那是因为数组自然地衰减到指向它们的第一个元素的指针。我还添加了一个参数来保存数组中的元素数,因此函数知道它。这使得函数更加通用,你可以传递不同大小的不同数组。

我还改为main函数,根本不返回任何内容。由于C99标准,没有显式main的{​​{1}}函数将由编译器隐式地获得return。从return 0函数返回0通常被视为&#34;好的&#34;或者&#34;没有失败&#34;。返回非零值被视为失败或错误。

我还更改了你的结构名称。具有前导下划线后跟大写字母的名称(C或预处理器)由编译器和标准C库保留在所有范围中。此外,结构标记名称位于单独的命名空间中,因此您可以使用与类型名称相同的结构名称(类型别名,由main定义)。我还删除了typedef类型名称,使用类型名称这样的指针会混淆代码并使其不易读取和维护。