C语言 如果已经分配了内存,那么在函数内的数组中所做的更改是否会保留在主函数或调用函数中?

xwbd5t1u  于 2023-03-07  发布在  其他
关注(0)|答案(2)|浏览(130)

在这个函数定义中,我已经为2D数组的地址取了参数.

void dynamic(int ***a,int r,int c)
{
    *a = (int**)malloc(sizeof(int*)*r);
    for(int i=0;i<r;i++)
    {
        (*a)[i] = (int*)malloc(sizeof(int)*c);
    }

}

我传递的参数如下所示,

dynamic(&a,r1,c1);

如果我直接把二维数组作为参数,那么它就不接受输入。
但是,在这段代码中,在add函数中,我没有取二维数组的地址,而是取二维数组本身,但是所做的更改将被保留。

void add(int **a,int **b,int r,int c,int **sum)
{
      static int i=0,j=0;
      if(i>=r)
      {
          return;// sum;
      }
      else
      {
          if(j<c)
          {
              sum[i][j] = a[i][j]+b[i][j];
              j++;
              add(a,b,r,c,sum);
          }
          j=0;
          i++;
          add(a,b,r,c,sum);
      }
}

但是如果引用add函数,我得到的是垃圾值.

void add(int **a,int **b,int r,int c,int ***sum)
{
      static int i=0,j=0;
      if(i>=r)
      {
          return;
      }
      else
      {
          if(j<c)
          {
              (*sum)[i][j] = a[i][j]+b[i][j];
              j++;
              add(a,b,r,c,sum);
          }
          j=0;
          i++;
          add(a,b,r,c,sum);
      }
}

我试着写一个函数来动态分配一个二维数组,但是没有输入值,我把二维数组的地址传递给动态函数,这次成功了.我对add函数应用了同样的逻辑,但是没有得到正确的结果,当我直接传递二维数组时,它成功了,可能是什么原因.

gojuced7

gojuced71#

此时:

(*sum)[i][j] = a[i][j]+b[i][j];

编译器不知道数组的维数,因为函数:

void add(int **a,int **b,int r,int c,int ***sum)

不提供此类信息,换句话说,指针的指针和二维数组不是同一类型,您不能期望编译器从int **推导出int(*)[dim]int [][dim]
从C99开始,您可以使用VLA(variable-length arrays)来解决此问题:

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

void add(int rows, int cols, int (*a)[cols], int (*b)[cols], int (*sum)[cols])
{
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            sum[row][col] = a[row][col] + b[row][col];
        }
    }
}

int main(void)
{
    int rows = 2, cols = 3;
    int ( *a )[cols] = malloc(sizeof(int) * rows * cols);
    int ( *b )[cols] = malloc(sizeof(int) * rows * cols);
    int (*sum)[cols] = malloc(sizeof(int) * rows * cols);

    srand((unsigned)time(NULL));
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            a[row][col] = rand() % 100;
            b[row][col] = rand() % 100;
        }
    }
    add(rows, cols, a, b, sum);
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            printf("%d + %d = %d, ", a[row][col], b[row][col], sum[row][col]);
        }
        printf("\n");
    }
    free(a);
    free(b);
    free(sum);
    return 0;
}

请注意,在C11中,VLA是可选的

p8ekf7hl

p8ekf7hl2#

调用这两个递归函数的结果没有区别。
然而,这些函数有一个严重的缺点:如果被调用超过一次,则它们将不起作用,因为静态变量i的值在函数调用之后没有被重置为0
同样,将参数sum声明为

int **sum

因为这个函数并不改变作为参数的指针本身,而是改变指针所指向的数据。
使用你的方法,递归函数可以按照下面的演示程序定义。函数被调用两次,以确保在第一次调用函数后,其静态变量被正确重置,并且可以第二次调用函数。
在程序中没有使用动态分配的数组来简化代码。

#include <stdio.h>

void add( int **a, int **b, unsigned int r, unsigned int c, int **sum )
{
    static unsigned int i = 0, j = 0;

    if (i < r && j != c)
    {
        sum[i][j] = a[i][j] + b[i][j];
        if (++j == c)
        {
            j = 0;
            ++i;
        }

        add( a, b, r, c, sum );
    }
    else
    {
        i = 0;
    }
}

int main( void )
{
    enum { r = 2, c = 3 };

    int a0[c] = { 1, 2, 3 };
    int a1[c] = { 4, 5, 6 };
    int * aa[r] = { a0, a1 };
    int ** a = aa;

    int b0[c] = { 10, 20, 30 };
    int b1[c] = { 40, 50, 60 };
    int * bb[r] = { b0, b1 };
    int ** b = bb;

    int s0[c];
    int s1[c];
    int * ss[r] = { s0, s1 };
    int ** sum = ss;

    add( a, b, r, c, sum );

    for (unsigned int i = 0; i < r; i++)
    {
        for (unsigned int j = 0; j < c; j++)
        {
            printf( "%d ", sum[i][j] );
        }
        putchar( '\n' );
    }

    putchar( '\n' );

    for (unsigned int  j = 0; j < c; j++)
    {
        s0[j] = 0;
        s1[j] = 0;
    }

    add( a, b, r, c, sum );

    for (unsigned int i = 0; i < r; i++)
    {
        for (unsigned int j = 0; j < c; j++)
        {
            printf( "%d ", sum[i][j] );
        }
        putchar( '\n' );
    }
}

程序输出为

11 22 33
44 55 66

11 22 33
44 55 66

可以看出,每次调用该函数时,它都能正确工作。
函数的参数rc具有无符号整数类型unsigned int而不是int,因为将它们声明为具有有符号整数类型是没有意义的,尽管通常使用类型size_t而不是类型unsigned int会更好。

相关问题