我想要三个任意长度的双缓冲区。以下是的简短示例
struct Data
{
double *foo[3];
};
int main(void)
{
double bar1[] = {1.0, 2.0, 3.0};
double bar2[] = {1.0, 2.0, 3.0, 4.0};
double bar3[] = {1.0, 2.0, 3.0, 4.0, 5.0};
struct Data *data = (struct Data*)malloc(sizeof(struct Data));
data->foo[0] = bar1;
data->foo[1] = bar2;
data->foo[2] = bar3;
printf("%lf %lf %lfn", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
printf("%lf %lf %lf %lfn", data->foo[1][0], data->foo[1][1],
data->foo[1][2], data->foo[1][3]);
printf("%lf %lf %lf %lf %lfn", data->foo[2][0], data->foo[2][1],
data->foo[2][2], data->foo[2][3], data->foo[2][4]);
return 0;
}
我担心的是,如果我以上面的方式对Data
进行malloc,我将面临数据损坏的风险。如果我在不知道大小的情况下,在堆上为指向双缓冲区的指针数组(或者本质上是任意大小的双缓冲区二维数组)分配内存,那么数据是否受到了任何保护?我觉得它可能会覆盖数据。我的想法正确吗?这是编译和打印的,但我不确定在更大规模的实现中是否信任它。
只要没有分配错误的值,就不会出现数据损坏。您必须了解数据的存在位置以及有效期。例如:
/* !!!! broken code ahead !!!! */
struct Data
{
double *foo[3];
};
void initData(struct Data* data) {
double bar1[] = {1.0, 2.0, 3.0};
double bar2[] = {1.0, 2.0, 3.0, 4.0};
double bar3[] = {1.0, 2.0, 3.0, 4.0, 5.0};
data->foo[0] = bar1;
data->foo[1] = bar2;
data->foo[2] = bar3;
}
int main(void)
{
struct Data *data = (struct Data*)malloc(sizeof(struct Data));
initData(data);
printf("%lf %lf %lfn", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
printf("%lf %lf %lf %lfn", data->foo[1][0], data->foo[1][1],
data->foo[1][2], data->foo[1][3]);
printf("%lf %lf %lf %lf %lfn", data->foo[2][0], data->foo[2][1],
data->foo[2][2], data->foo[2][3], data->foo[2][4]);
return 0;
}
这将是一个坏主意:
data
是堆分配的,并且在调用free
之前一直"存在"bar1..3
为堆栈分配,仅位于initData()
内部data->foo
指向bar1..3
,仅在initData()
内部有效printf
-调用可能有效(尚未测试),但它是损坏的代码
正确处理这一点是C最困难的任务。当你使用linux进行开发时,你应该研究valgrind来捕捉这些类型的错误(我的例子中的错误很明显,但它可能会变得非常困难)
当然,malloc()
本身不会增加数据损坏的风险。如果有问题的结构是在堆栈上分配的自动变量,那么无论存在什么风险,都至少同样大。
你真正想问的似乎是数据结构本身,基本上是指针。是的,如果您有一个指针,那么可以在指针所指向的对象的边界之外,通过该指针尝试无效的内存访问。C对此类企图不提供任何保护;它通过声明尝试这种操作的程序的行为是未定义的来解决这个问题。
程序员有责任确保他的程序不会尝试这样的操作。对于指向数组的指针,通常通过单独跟踪指向数组的长度,或者通过用不能显示为正常数据的哨兵值标记数组的末尾来解决该问题。