我得到运行时检查失败#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;
}
答案 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
类型名称,使用类型名称这样的指针会混淆代码并使其不易读取和维护。