当具有指针数组的结构被 malloc 时,是否存在潜在的数据损坏
Is there potential data corruption when a struct with an array of pointers is malloc'd
我想接受三个任意长度的双打缓冲区。下面是一个简短的例子
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 %lf\n", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
printf("%lf %lf %lf %lf\n", data->foo[1][0], data->foo[1][1],
data->foo[1][2], data->foo[1][3]);
printf("%lf %lf %lf %lf %lf\n", data->foo[2][0], data->foo[2][1],
data->foo[2][2], data->foo[2][3], data->foo[2][4]);
return 0;
}
我担心的是,如果我以上述方式 malloc Data
,我 运行 有损坏数据的风险。如果我在不知道大小的情况下为指向双缓冲区的指针数组(或本质上是任意大小的双精度二维数组)在堆上分配内存,数据是否以任何方式受到保护?我觉得 运行 有覆盖数据的可能性。我的想法是否正确?这编译并打印,但我不确定我是否相信它在更大规模的实施中。
当然 malloc()
本身不会增加数据损坏的风险。如果所讨论的结构是在堆栈上分配的自动变量,那么无论存在什么风险,至少都会有同样大的风险。
您似乎真正要问的是数据结构本身,基本上是指针。是的,如果您有一个指针,则可以通过该指针尝试在指针指向的对象范围之外进行无效的内存访问。 C 不提供针对此类尝试的保护;它通过声明尝试执行此类操作的程序的行为未定义来解决此问题。
程序员有责任确保他的程序不会尝试这样的操作。对于指向数组的指针,通常通过单独跟踪指向数组的长度,或者用不能作为普通数据出现的标记值标记数组的末尾来解决该问题。
只要您没有分配错误的值,就不会发生数据损坏。您必须了解数据的存放位置以及有效时间。例如:
/* !!!! 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 %lf\n", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
printf("%lf %lf %lf %lf\n", data->foo[1][0], data->foo[1][1],
data->foo[1][2], data->foo[1][3]);
printf("%lf %lf %lf %lf %lf\n", data->foo[2][0], data->foo[2][1],
data->foo[2][2], data->foo[2][3], data->foo[2][4]);
return 0;
}
这不是个好主意:
data
是堆分配的,"lives" 直到您调用 free
bar1..3
是堆栈分配的,只存在于 initData()
内部
data->foo
指向 bar1..3
并且只在 initData()
内部有效
printf
-调用可能有效(尚未测试)但它是损坏的代码
正确使用 C 是最困难的任务。当您使用 linux 进行开发时,您应该查看 valgrind 以捕获这些类型的错误(我的示例中的错误很明显,但它可以真的很难)
我想接受三个任意长度的双打缓冲区。下面是一个简短的例子
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 %lf\n", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
printf("%lf %lf %lf %lf\n", data->foo[1][0], data->foo[1][1],
data->foo[1][2], data->foo[1][3]);
printf("%lf %lf %lf %lf %lf\n", data->foo[2][0], data->foo[2][1],
data->foo[2][2], data->foo[2][3], data->foo[2][4]);
return 0;
}
我担心的是,如果我以上述方式 malloc Data
,我 运行 有损坏数据的风险。如果我在不知道大小的情况下为指向双缓冲区的指针数组(或本质上是任意大小的双精度二维数组)在堆上分配内存,数据是否以任何方式受到保护?我觉得 运行 有覆盖数据的可能性。我的想法是否正确?这编译并打印,但我不确定我是否相信它在更大规模的实施中。
当然 malloc()
本身不会增加数据损坏的风险。如果所讨论的结构是在堆栈上分配的自动变量,那么无论存在什么风险,至少都会有同样大的风险。
您似乎真正要问的是数据结构本身,基本上是指针。是的,如果您有一个指针,则可以通过该指针尝试在指针指向的对象范围之外进行无效的内存访问。 C 不提供针对此类尝试的保护;它通过声明尝试执行此类操作的程序的行为未定义来解决此问题。
程序员有责任确保他的程序不会尝试这样的操作。对于指向数组的指针,通常通过单独跟踪指向数组的长度,或者用不能作为普通数据出现的标记值标记数组的末尾来解决该问题。
只要您没有分配错误的值,就不会发生数据损坏。您必须了解数据的存放位置以及有效时间。例如:
/* !!!! 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 %lf\n", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
printf("%lf %lf %lf %lf\n", data->foo[1][0], data->foo[1][1],
data->foo[1][2], data->foo[1][3]);
printf("%lf %lf %lf %lf %lf\n", data->foo[2][0], data->foo[2][1],
data->foo[2][2], data->foo[2][3], data->foo[2][4]);
return 0;
}
这不是个好主意:
data
是堆分配的,"lives" 直到您调用free
bar1..3
是堆栈分配的,只存在于initData()
内部
data->foo
指向bar1..3
并且只在initData()
内部有效
printf
-调用可能有效(尚未测试)但它是损坏的代码
正确使用 C 是最困难的任务。当您使用 linux 进行开发时,您应该查看 valgrind 以捕获这些类型的错误(我的示例中的错误很明显,但它可以真的很难)