使用 malloc 时两个变量的内存发生冲突

Memory of two variables are colliding when used malloc

我正在尝试使用 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

作为输出。

这里可能有什么问题?

您应该从 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);
    //...
}

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

函数参数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你应该使用一个中间变量,因为通常函数可以return一个空指针。所以用空指针重新分配原始指针会导致指针的原始值丢失。

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

free( pA );

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

根据行为,它 看起来 如果您分配 d,它会在 pA 之后立即分配,这样 pA 可以' 就地扩展,因此 realloc 正在创建一个新缓冲区并释放旧缓冲区,并且旧缓冲区在 main.printf 语句之前被覆盖。

您需要编写 padd,这样对 a 的任何更改都会反映在 pA 中 - return [=] 的(可能是新的)值14=] 或将指针传递给 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可能returnNULL总是将结果赋给一个临时值,并在赋值前检查它回到原来的变量,否则你 运行 失去对你已经分配的内存的访问的风险。此外,强制转换为 void * 是不必要的且令人困惑,因为您将结果分配给 int * 变量。除非您将此代码编译为 C++ 或在 ancient K&R C 编译器下,否则请完全关闭强制转换 - 否则,您的强制转换必须与您正在分配的事物的类型相匹配至,在本例中为 int *.