在一个函数中,我使用了malloc:
void name1(struct stos* s)
{
s = malloc (4 * sizeof (int));
}
一切都好。但后来我使用了realloc
void name2(struct stos* s)
{
s->size = 2*(s->size);
s = realloc (s, (s->size + 1) * sizeof (int));
}
我在valgrind中得到无效的free / delete / realloc,realloc返回NULL。
结构声明和其余程序是:
struct stos
{
int top;
int size;
int stk[];
};
void name1(struct stos* s);
void name2(struct stos* s);
int main()
{
struct stos stosik;
struct stos* s;
s = &stosik;
name1(s);
//some operations on the array and int top here
name2(s);
}
我在这里做错了什么?我找了很长时间可能出错的地方,阅读了很多关于指针,malloc / realloc等的文章,但没有结果。如果有人能帮助我,我将非常感激。
答案 0 :(得分:7)
这个问题有点微妙,是由两件事组合造成的。让我们从这里开始:
struct stos stosik;
struct stos* s;
s = &stosik;
name1(s);
首先,让s
指向堆栈上分配的有效内存块(stosik
),然后调用name1
传入s
。让我们来看看name1
的样子:
void name1(struct stos* s)
{
s = malloc (4 * sizeof (int));
}
嗯,我们可以看到name1
接收了一个名为struct stos
的{{1}}的指针;在该函数内部,我们正在分配一些内存并使s
指向它。这是一个问题。
首先,请注意s
已经指向一个有效的内存块。所以在这里使用s
是可疑的。它会导致一个微妙的错误,它实际上会隐藏程序中的真正的错误,这很糟糕。所以,让我们完全删除malloc
:
stosik
现在,如果您运行此程序,则会在致电int main()
{
struct stos* s = NULL;
name1(s);
if(s == NULL)
return -1;
后看到变量name1
仍然指向s
。这里发生了什么?
好吧,我们正在更改NULL
的函数的 LOCAL 副本(即仅存在于s
内的s
)...但是{{在name1
中1}}没有改变!请记住,我们正在将指针传递给s
,但我们通过值传递 。
要做你似乎想做的事情你可以做,你必须将指针传递给main
到name1
(也就是说,传递一个双指针)或者你应该从s
返回name1
的结果作为返回值。让我们看看每个选项:
malloc
name1
从s
调用它需要我们使用“address-of”运算符:
void name1(struct stos **s)
{
/* sanity check */
if(s == NULL)
return;
/* now, allocate enough space for four integers and make
* whatever s points to, point to that newly allocated
* space.
*/
*s = malloc(4 * sizeof(int));
}
main
struct stos *s = NULL;
/* we need to pass a pointer to s into name1, so get one. */
name1(&s);
/* malloc can fail; check the result! */
if(s == NULL)
return -1;
从name1
调用此内容稍微容易一些:
struct stos *name1()
{
return malloc(4 * sizeof(int));
}
将您的代码更改为我在此处显示的内容将解决此问题(但可能还有其他问题),但让我简要介绍其他内容:
由于我们刚刚讨论的问题,您遇到的崩溃部分地突然出现;另一个问题是main
内部正在调用struct stos *s = name1();
/* malloc can fail; check the result! */
if(s == NULL)
return -1;
。但是,您传递到name2
的指针 是您从realloc
或realloc
返回的指针,这是malloc
所期望的。它指向realloc
。因此,代码会导致未定义的行为,之后任何都会发生。
如果你很幸运(看起来你似乎),那么它就会崩溃,如果你不是......那么,谁知道会发生什么?
答案 1 :(得分:1)
如果要在name1中动态分配s,则需要将其声明为name1(struct stos** s)
,并将指针传递给指向已分配内存的指针。
您的main
分配stosik staticaly,这意味着您无需进行任何进一步的动态分配。然后,当你尝试使用name1(静态分配的mem)时,它确实......嗯,某事。我不知道是什么,但肯定不是你所期待的。