将realloc用于函数中

4

我想咨询关于realloc的问题。

以下代码可以正常工作(没有警告):

#include <stdio.h>
#include <stdlib.h>

int main ()
{
    int num=10;
    int *vet;
    int i;

        for (i=0; i<num; i++)
    {
        /* allocate memory of vet to contains (i+1) int */
        vet = (int*) realloc ( vet, (i+1) * sizeof(int) );
    
        /* write numbers in the allocated memory */
        vet[i] = 321 + i;
    }

    /* print test, if all works I must see:
    | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | */
    printf ("| ");
    for (i=0; i<num; i++)
        printf ("%d | ", vet[i]);
    printf ("\n");

    return 0;
}

但是带有函数的相同程序却无法运行!编译器返回以下警告:

In function ‘main’:
14:10: warning: ‘vet’ is used uninitialized in this function [-Wuninitialized]

代码如下:
#include <stdio.h>
#include <stdlib.h>

void memoria (int *, int);

int main ()
{
    int *vet, num=10;

    memoria (vet, num);

    /* print test, if all works I must see:
    | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | */
    int i;
    printf ("| ");
    for (i=0; i<num; i++)
        printf ("%d | ", vet[i]);
    printf ("\n");

    return 0;
}

void memoria (int *vet, int num)
{
    int i;

    for (i=0; i<num; i++)
    {
        /* allocate memory of vet to contains (i+1) int */
        vet = (int*) realloc ( vet, (i+1) * sizeof(int) );
    
        /* write numbers in the allocated memory */
        vet[i] = 321 + i;
    }
}

有人能告诉我为什么吗?非常感谢!

哦,而且在主函数中使用“随机”malloc的相同代码可以正常工作(与该函数一起)...

#include <stdio.h>
#include <stdlib.h>

void memoria (int *, int);

int main ()
{
    int *vet, num=10;

    /* ADDED MALLOC */
    vet = (int*) malloc (1);

    memoria (vet, num);

    /* print test, if all works I must see:
    | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | */
    int i;
    printf ("| ");
    for (i=0; i<num; i++)
        printf ("%d | ", vet[i]);
    printf ("\n");

    return 0;
}

void memoria (int *vet, int num)
{
    int i;

    for (i=0; i<num; i++)
    {
        /* allocate memory of vet to contains (i+1) int */
        vet = (int*) realloc ( vet, (i+1) * sizeof(int) );
    
        /* write numbers in the allocated memory */
        vet[i] = 321 + i;
    }
}

1
将您的函数更改为接受int **vet,然后从main中调用memoria(&vet,num);。此外,不要将malloc或realloc的结果强制转换,因为它可能会使有价值的诊断信息无声,而且看起来很糟糕。 - Brandin
3
以下代码运行正确(没有警告):第一段代码中也使用了未初始化的变量“vet”。 - BLUEPIXY
1
使用gcc版本4.8.1,没有任何警告(已测试)! - ᴜsᴇʀ
1
@user malloc和realloc会给出一个新的指针,因此您的函数必须能够更改“第一个元素”的起始位置。 - Brandin
1
一些警告,例如未使用的变量,只有在使用优化器时才会生成。它不必是-O3,但您需要在命令行上使用某种形式的-O - Jonathan Leffler
显示剩余5条评论
3个回答

6

你这样写的方式:

int *vet, num=10;

memoria (vet, num);

你在 memoria 中所做的更改不会被发送回到 main。为了理解这一点,你可以尝试将 num 的值改变,而不是改变 memoria 的值,然后检查 main 中的值。此时,main 中的值仍然是 10。变量 vetnum 是通过 值传递 的方式传递的,因此它们在 main 中保留了其原始值。
绕过这个问题最常用的两种方法是:传递 vet 的地址,这样就可以在 memoria 中进行修改;或者返回一个新的 vet 值。
第一种方法的代码如下:
memoria( & vet, num ) ;

void memoria (int **vet, int num)
{
  * vet= realloc( * vet, ... ) ;

或者,您可以改变memoria的返回类型。
vet= memoria( vet, num ) ;

int * memoria( int * vet, int num)
{
  ...
  return vet ;
}

它们都有各自的优缺点。第二种形式可能更容易理解,适合那些不是指针专家的人。

malloc/realloc漏洞

如果你在mainmemoria中添加printf来显示vet的值,就能轻松看出最后一个示例的工作原理。如果可以的话,realloc()将新内存放置在旧指针的同一位置。在您的简单测试用例中,分配器可以轻松完成这个操作,因此内存保持在同一位置。如果代码更加复杂,调用realloc()会移动指针,然后你会在之后的main中看到崩溃。


1
谢谢你的回答!num是按值传递的,这很好,因为我不想改变它,但是vet呢?通过memoria(vet, num);我传递给函数一个指针,对吗? - ᴜsᴇʀ
1
@用户。是的,您传递了一个指针,但是您的函数 在自身内部更改 该指针(vet = realloc(vet,...)),但未将修改后的指针返回给 main() - Roddy
2
谢谢,现在我明白了!但是怎么解决这个问题呢?(还有为什么我发布的最后一段代码有效?) - ᴜsᴇʀ
感谢您提供的新答案部分,_malloc/realloc fluke_。 - ᴜsᴇʀ
1
@woolstar。如果我想在第一个表单函数中使用scanf,该怎么办?sscanf (buff, "%d", vet[i]);不起作用! - ᴜsᴇʀ
1
是的,因为vet不再是一个int * - woolstar

3

注意解决以下几个问题,就可以继续进行了。

你的main函数没有返回实际指向某个对象的vet。请想办法将vet返回给你的main vet

int *vet = NULL; //better bet for realloc() in this case
vet= memoria (vet, num);

相应地更改原型以返回指针,并记得在定义中返回vet

int* memoria(int*, int);

现在来谈谈realloc()函数。根据ISO C规范:

如果指针ptr是一个空指针,那么realloc()函数将相当于为指定大小调用malloc()函数。

如果指针ptr不匹配之前由calloc()、malloc()或realloc()返回的指针,或者该空间之前已被调用free()或realloc()函数释放,则行为是未定义的。

希望这能帮到您。


1
非常感谢!那么,例如对于一个结构体 struct example *e;,是一样的对吗?你知道我贴出的最后一段代码为什么能够工作吗?谢谢! - ᴜsᴇʀ
还有一个问题:如果我想用void函数解决这个问题怎么办? - ᴜsᴇʀ
1
是的。在你最后的代码片段中,vet 只是一个指针,它指向你已经分配的内存块。你将这个指针传递给了一个重新分配它的函数。realloc() 返回一个新的指针值,其值可能与旧的指针值相同,也可能不同。而你的旧内容却被保留了下来! - Gil
如果你要在一个void函数中重新分配相同的内存,恐怕我们不能不处理一些未定义的行为。 - Gil

1

你正在将未初始化的vet*传递给realloc。realloc()类似于free(),因为它会分配全新的内存(它会释放旧的分配)。因此,任何传递给realloc()的指针都必须是有效的堆指针或空指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接