【问题标题】:Memory of two variables are colliding when used malloc使用 malloc 时两个变量的内存发生冲突
【发布时间】:2021-06-30 13:28:44
【问题描述】:

我正在尝试使用 malloc 学习 C 中的内存分配,并在函数内使用 realloc 增加分配数组的大小。我遇到了这个。当我使用单个变量时,代码运行良好。但是当我为第二个变量分配内存时,它给了我奇怪的输出。

代码如下:

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

# define N 3

void padd(int *a){
    int sizes = 10*sizeof(int);
    a = (void *)realloc(a,sizes);
    a[0] = 10;
    printf("inside func= %d \n",a[0]);
}

int main()
{
    int *d;
    int *pA;
    
    int size = N*sizeof(int);
    pA = (void *)malloc(size);
    //d = (int *)malloc(size);
    
    padd(pA);
    printf("outside func= %d",pA[0]);
    
}

它给了我输出:

inside func= 10
outside func= 10

但是如果我取消注释 //d = (int *)malloc(size);行,它给了我

inside func= 10 
outside func= -1368048824

作为输出。

这里可能有什么问题?

【问题讨论】:

  • a 仅在本地更改。函数返回后realloc()的结果丢失。
  • 好的!有没有正确的方法来增加函数内 pA 的大小?我是 C 的新手。:)
  • 使用指向该指针的指针并赋值,或者返回使用realloc()获得的指针并将其赋值回原来的指针。
  • realloc(a, sizes) 可能会在增加分配的大小时返回原始的a,但这不是必须的。它也可以在失败时返回NULL。如果realloc() 成功(不返回NULL)并返回原始a,您的代码只会按预期运行
  • 一般来说,你不应该转换mallocstackoverflow.com/questions/605845/…的结果

标签: c malloc pass-by-reference dynamic-memory-allocation realloc


【解决方案1】:

如果realloc不能就地扩展一个缓冲区,它将分配一个新缓冲区,将旧缓冲区的内容复制到它,释放旧缓冲区,并返回新缓冲区的地址(或@987654322 @如果不能满足请求);因此,a 的值可以在padd 中更改。但是,该更改仅应用于形式参数a - 实际参数pA 不受影响。

根据行为,它看起来如果你分配d,它会立即分配在pA之后,这样pA就无法扩展,所以realloc正在创建一个新缓冲区并释放旧缓冲区,并且旧缓冲区在main 中的printf 语句之前被覆盖。

您需要编写padd,以便对a 的任何更改都反映在pA 中——要么返回a 的(可能是新的)值,要么传递一个指向pA 的指针:

void padd( int **a )
{
  size_t sizes = 10 * sizeof (int); // see note 1
  int *tmp = realloc( *a, sizes ); // see note 2
  
  if ( tmp )
  {
    *a = tmp;
    (*a)[0] = 10;
    printf( "Inside func, (*a)[0] = %d\n", (*a)[0] );
  }
  else
  {
    printf ( "Inside func, realloc failed!\n" );
  }
}

你会这样称呼它

padd( &pA );

注意 1:sizeof 的类型为 size_t,而不是 int

注意 2:由于 realloc 可能会返回 NULL总是将结果分配给临时值并在分配回原始变量之前对其进行检查,否则您将面临丢失的风险访问您已经分配的内存。此外,对void * 的强制转换是不必要且令人困惑的,因为您将结果分配给int * 变量。除非您将此代码编译为 C++ 或在 ancient K&R C 编译器下编译,否则只需完全关闭强制转换 - 否则,您的强制转换必须与您分配的事物的类型相匹配,即在这种情况下是int *

【讨论】:

    【解决方案2】:

    您的两个程序都有未定义的行为。

    函数参数a

    void padd(int *a)
    

    是函数的局部变量,由指针pA的值初始化,在函数调用中用作函数参数

    padd(pA);
    

    你可以想象函数定义及其调用方式如下

    padd(pA);
    
    //...
    
    void padd( /* int *a */ ){
        int *a = pA;
    
        int sizes = 10*sizeof(int);
        a = (void *)realloc(a,sizes);
        a[0] = 10;
        printf("inside func= %d \n",a[0]);
    }
    

    因此可以看出,在函数 padd 中更改局部变量 a 不会影响存储在指针 pA 中的值,因为该函数处理指针 pA 的值的副本.

    要更改函数内的原始指针pA,您需要通过引用将其传递给函数。

    在 C 中,通过引用传递意味着通过指向对象的指针间接传递对象。因此,取消引用指针,您将直接访问该对象。

    函数的声明和定义方式如下

    int padd( int **a ){
        int sizes = 10*sizeof(int);
    
        int *tmp = realloc( *a, size );
        int success = tmp != NULL;
        
        if ( success )
        {
            *a = tmp;
            ( *a )[0] = 10;
            // or **a = 10;
            printf("inside func= %d \n", ( *a )[0] );
        }
    
        return success;
    }
    

    并且函数可以像这样调用

    if ( padd( &pA () ) printf("outside func= %d",pA[0]);
    

    请注意,调用realloc 时应使用中间变量,因为通常该函数可以返回空指针。所以用空指针重新分配原始指针会导致指针的原始值丢失。

    此外,您应该在不再需要时释放所有动态分配的内存

    free( pA );
    

    【讨论】:

      【解决方案3】:

      您应该从padd 取回新指针:

      int * padd(int * a){
          int sizes = 10*sizeof(int);
          a = (void *)realloc(a,sizes);
          a[0] = 10;
          printf("inside func= %d \n",a[0]);
          return a;
      }
      //...
      int main()
      {
          //...
          pA = padd(pA);
          //...
      }
      

      或者给指针传递一个指针:

      void padd(int **pA){
          int *a = *pA;
          int sizes = 10*sizeof(int);
          a = (void *)realloc(a,sizes);
          a[0] = 10;
          printf("inside func= %d \n",a[0]);
          *pA = a;
      }
      //...
      int main()
      {
          //...
          padd(&pA);
          //...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-17
        • 1970-01-01
        • 2022-01-24
        相关资源
        最近更新 更多