在C89中,以下代码可以正常工作:
typedef struct{
int size;
int **ptr;
}foo;
int main()
{
foo *var;
var = malloc(sizeof(foo) + 2 * sizeof(int*));
int a = 3, b = 6;
var->ptr[0] = &a;
var->ptr[1] = &b;
printf("%d %d\n", (*var->ptr[0]), (*var->ptr[1]));
return 0;
}
执行时显示:3 6
但如果我更换
var = malloc(sizeof(foo) + 2 * sizeof(int*));
与
var = malloc(sizeof(foo));
var = realloc(var, sizeof(foo) + 2 * sizeof(int*));
它在没有任何警告的情况下进行编译,但我在以下行中遇到了分段错误:
var->ptr[0] = &a;
我真的不知道我做错了什么,所以我很感激任何输入。我是初学者,所以如果我的错误很明显,我会道歉。
谢谢。
答案 0 :(得分:5)
我认为您的声明是错误的。以下行假定ptr
指向某些内存,而实际上它根本没有初始化!
var->ptr[0] = &a;
如果您的编译器支持它,那么它不应该更像是这样:
typedef struct{
int size;
int* ptr[0];
}foo;
否则,请将ptr[0]
更改为ptr[1]
,并根据结构已包含一个元素的事实调整计算。
注意:写入错误的地址后,结果将是未定义的。你有一个问题但它只会出现在一个案例中。在这两种情况下,问题仍然存在。
答案 1 :(得分:2)
我想说这在C89中也是错误的。
malloc(sizeof(foo) + 2 * sizeof(int*));
的分配超出了你的需要,但不是你想象的那样。
+-------+------------+---------+--------+
| size | ptr | int* | int* |
+-------+------------+---------+--------+
| sizeof foo | 2 * sizeof(int*) |
如您所见,var->foo
仍然未初始化,无论多少额外字节
你已经分配了,所以
var->ptr[0] = &a;
var->ptr[1] = &b;
将会失败。
你应该做的是:
var = malloc(sizeof *var);
var->ptr = malloc(2 * sizeof *var->ptr);
var->ptr[0] = &a;
var->ptr[1] = &b;
然后它看起来像这样
| int | | int |
+-----+ +-----+
| a | | b |
+-----+ +-----+
^ ^
| |
| |
+-------+------------+ points to +---------+--------+
| size | ptr | ------------> | int* | int* |
+-------+------------+ +---------+--------+
| sizeof foo | | 2 * sizeof(int*) |
不要忘记检查malloc
的返回值并释放内存
之后。
修改强>
可行的是:
var = malloc(sizeof(foo) + 2 * sizeof(int*));
var->ptr = (int**) ( ((char*) var) + sizeof *var );
您可以将var->pointer
设置为指向struct
的内存。而
这可能有用,我认为它非常难看,我会拒绝承诺
与此类似的同事。
答案 2 :(得分:1)
问题在于,您没有指定ptr
指向任何内容,因此它指向随机内存,ptr[index]
的任何访问都是未定义的行为。
更改ptr
的声明,例如Jonathan建议的答案是最安全的选择,例如:
typedef struct{
int size;
int* ptr[1]; // or 0 if your compiler supports it
}foo;
int main()
{
foo *var;
var = malloc(offsetof(foo, ptr));
if (var) {
var->size = 0;
...
}
foo *newvar = realloc(var, offsetof(foo, ptr) + (2 * sizeof(int*)));
if (newvar) {
var = newvar;
var->size = 2;
int a = 3, b = 6;
var->ptr[0] = &a; // <-- OK!
var->ptr[1] = &b; // <-- OK!
printf("%d %d\n", *(var->ptr[0]), *(var->ptr[1]));
}
free(var);
return 0;
}
但是,如果由于某种原因,您无法更改ptr
的声明(例如foo
与现有API一起使用),那么您可以改为:< / p>
typedef struct{
int size;
int **ptr;
}foo;
int main()
{
foo *var = malloc(sizeof(foo));
if (var) {
var->size = 0;
var->ptr = NULL; // <-- add this!
...
}
foo *newvar = realloc(var, sizeof(foo) + (2 * sizeof(int*)));
if (newvar) {
var = newvar;
var->size = 2;
var->ptr = (int**)(var + 1); // <-- add this!
int a = 3, b = 6;
var->ptr[0] = &a; // <-- OK!
var->ptr[1] = &b; // <-- OK!
printf("%d %d\n", *(var->ptr[0]), *(var->ptr[1]));
}
free(var);
return 0;
}
在后一种情况下,请确保每次要(重新)分配ptr
时执行相同的var
分配。我会将这个逻辑包装在一组辅助函数中,例如:
typedef struct{
int size;
int **ptr;
}foo;
foo* createFoo(int size)
{
foo *var = malloc(sizeof(foo) + (size * sizeof(int*)));
if (var) {
var->size = size;
var->ptr = (int**)(var + 1);
}
return var;
}
foo* resizeFoo(foo **var, int newSize)
{
foo *newvar = realloc(*var, sizeof(foo) + (newSize * sizeof(int*)));
if (newvar) {
newvar->size = newSize;
newvar->ptr = (int**)(newvar + 1);
*var = newvar;
}
return newvar;
}
int main()
{
foo *var = createFoo(0);
...
if (resizeFoo(&var, 2)) {
int a = 3, b = 6;
var->ptr[0] = &a; // <-- OK!
var->ptr[1] = &b; // <-- OK!
printf("%d %d\n", *(var->ptr[0]), *(var->ptr[1]));
}
free(var);
return 0;
}
答案 3 :(得分:0)
您需要修复结构:
typedef struct{
int size;
int *ptr;
}foo;
代码:
var = malloc(sizeof(foo));
var->ptr = malloc(2 * sizeof(int));
int a = 3, b = 6;
// store a and b in array, not their addresses
var->ptr[0] = a;
var->ptr[1] = b;
假设你想在数组中输入2个条目。当然,忽略了我没有测试malloc()
的结果的事实。
如果您想调整数组大小,只需重新分配var->ptr
而不是var
。
答案 4 :(得分:0)
在Visual Studio,Windows 10中,两个示例都不起作用。这是因为在两种情况下结构都是未初始化的。
箭头操作:
foo->bar
是简写:
(*foo).bar
因此,如果“foo”struct变量未初始化,则取决于编译器,结构中的指针将指向内存中的随机位置。
因此,当您使用箭头运算符时:
var->ptr[0] = &a;
你做的是:
(*var).ptr[0] = &a;
所以,基本上,你试图将“a”的地址写入内存中你不应该访问的位置。这就是您遇到分段错误的原因。
但是,如果你改为初始化它:
int goodmemorylocation = 0;
var->ptr = &goodmemorylocation; // You change the location of your pointer to an accessible location in memory
然后你的代码适用于我的系统中的两种情况。
也许,在你的系统中,你使用malloc的第一个例子,以某种方式指向你内存中的正确地址。这就是它运作的原因。