【问题标题】:How to return a 2D array from a function in C?如何从 C 中的函数返回二维数组?
【发布时间】:2011-07-09 06:31:59
【问题描述】:

我是一名 Ruby 程序员,最终为 C 开发了一个代码生成器。这就像让一辆豪华轿车拖一辆 1960 年代的卡车。不管怎样。

这是我认为应该有效但无效的方法。

float[][] pixels()
{
  float x[][]= { {1,1},{2,2} };
  return x
}

void drawLine(float x[][2])
{
  //drawing the line
}

//inside main
drawLine(pixels());

我把头撞在桌子上,试图让这件事发挥作用。请帮忙。

【问题讨论】:

标签: c arrays return


【解决方案1】:

在 C 中,指针和数组密切相关。此外,您通常需要将数组的大小作为单独的变量传递。让我们开始吧:

#include <stdio.h>

float** createArray(int m, int n)
{
    float* values = calloc(m*n, sizeof(float));
    float** rows = malloc(m*sizeof(float*));
    for (int i=0; i<m; ++i)
    {
        rows[i] = values + i*n;
    }
    return rows;
}

void destroyArray(float** arr)
{
    free(*arr);
    free(arr);
}

void drawLine(const float** coords, int m, int n);

int main(void)
{
    float** arr = createArray(2,2);
    arr[0][0] = 1;
    arr[0][1] = 1;
    arr[1][0] = 2;
    arr[1][1] = 2;
    drawLine(arr, 2, 2); 
    destroyArray(arr);
}

【讨论】:

  • 我刚刚尝试了这个代码-sn-pand 得到:“错误:从 'void*' 到 'float*' 的无效转换”在 createArray.You 需要添加一个演员:“float * 值 = (float*)calloc(mn, sizeof(float));" ..浮点数相同*
  • @Alex 您是否可能像编译 C++ 代码一样编译它?它是有效的 C 和无效的 C++。
  • float** 是二维浮点数组的“类型”吗?
【解决方案2】:

感谢大家的回答,尤其是对数组指针关系的详细解释。

我将数组封装在一个结构中

 struct point_group1 {
        float x[3];
        float y[3];
};

struct point_group1 pixels(){
    struct point_group1 temp;

    temp.x[0] = 0.0;
    temp.x[1] = 1.0;
    temp.x[2] = -1.0;

    temp.y[0] = 0.0;
    temp.y[1] = 1.0;
    temp.y[2] = 1.0;

    return temp;    
}



struct point_group1 points1  = pixels();
axPoly(points1.x, points1.y ,3, 0.0);

【讨论】:

  • 这是一个很好的解决方案,请注意,如果这些是大型数组并且您的编译器不擅长优化,您最终可能会创建不必要的副本。
【解决方案3】:

C/C++ 中,当您将数组传递给函数时,它会衰减为指向数组第一个元素的指针。因此,在pixels() 函数中,您将返回堆栈分配变量的地址。返回变量的地址不再有效,因为在pixels() 返回时,堆栈分配的变量超出范围。因此,您应该使用动态存储的变量(即使用 malloc、calloc)。

因此,对于二维数组,您可以使用float** arrayVariable;。此外,如果你将它传递给一个函数,你应该注意它有多少行和列。

int rows, columns;

float** pixels()
{
    // take input for rows, columns
    // allocate memory from free store for the 2D array accordingly
    // return the array
}

void drawLine( float** returnedArrayVariable )
{
  //drawing the line
}

由于二维数组是自己管理资源的,它应该使用 free 将资源返回到免费存储中。

【讨论】:

  • 我猜你希望我在像素函数中使用 malloc。然后我需要记住释放它。
【解决方案4】:
float (*pixels(void))[2] 
{
  static float x[2][2]= { {1,1},{2,2} };
  return x;
}

void drawLine(float (*x)[2])
{
  //drawing the line
  //x[0][0];
}

//inside main
drawLine(pixels());

【讨论】:

  • 这里只有你一个正确的答案!可惜你什么都没解释。如果您添加了一些解释,请随时给我发表评论,如果我认为它很好,我会检查并投票。
【解决方案5】:

最简单的方法可能是在 main 中声明 float 数组并让 pixels 填充它:

#define PIXEL_X_SIZE 2
#define PIXEL_Y_SIZE 2

int pixels(float x[][PIXEL_X_SIZE], int len) {
    /* I don't know if you want the logic of this method to ever change,
       but this will be roughly equivalent to what you do above */
    if (len < PIXEL_Y_SIZE) {
        /* the length of the passed array is too small, abort */
        return -1;
    }

    x[0][0] = x[0][1] = 1;
    x[1][0] = x[1][1] = 2;
    return 0;
}

void drawLine(float x[][PIXEL_X_SIZE]) {
    /* this will work fine */
}

int main() {
    float pixel_array[PIXEL_Y_SIZE][PIXEL_X_SIZE];
    pixels(pixel_array, PIXEL_Y_SIZE);
    drawLine(pixel_array);
}

您也可以使用mallocfree 并将您的像素存储在堆上,但如果这将是更大的像素数组,则确实没有必要,它只会增加额外的复杂性以确保您的内存总是得到正确分配和释放。

【讨论】:

  • 你的方法很好。我唯一担心的是,由于我们的应用程序预计在嵌入式设备上运行,代码审查清单要求最小化全局变量。代码将有数百个类似像素的函数。
  • @Akshar 我不使用任何全局变量...我 #define 了几件事,但如果你真的想要你可以在任何地方重复 2s,但你正在为自己做准备任何时候这些值发生变化和/或如果有人得到一个新的大小错误,就很难调试错误。
猜你喜欢
  • 2014-12-19
  • 2021-03-29
  • 2021-12-04
  • 1970-01-01
  • 2012-12-14
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
相关资源
最近更新 更多