【问题标题】:How to make a function returning a dynamically-allocated two-dimensional array?如何使函数返回动态分配的二维数组?
【发布时间】:2019-04-05 11:13:56
【问题描述】:

我试图从一个函数返回一个连续的内存分配数组,但我不断收到错误。

编译器返回警告说return from incompatible pointer type [-Wincompatible-pointer-types]

谁能告诉我我做错了什么?

int *test() {
    size_t rows, cols;
    // assign rows and cols
    rows = 3;
    cols = 3;
    int count = 0;

    int (*arr)[cols] = malloc(sizeof *arr * rows);
    if (arr) {
        // do stuff with arr[i][j]
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; j++) {
                arr[i][j] = count;
                count++;
            }
            /* code */
        }
    }
    return arr;
}

int main() {    
    size_t rows, cols;
    // assign rows and cols
    rows = 3;
    cols = 3;
    int count = 0;

    int (*arr)[cols] = malloc(sizeof *arr * rows);
    arr = test();

    int i = 0;
    int j = 0;

    for (i = 0; i < rows; ++i) {
        for (j = 0; j < 3; ++j)
            printf("%d ", arr[i][j]);
        printf("\n");
    }
    free(arr);
}

它应该返回一个二维数组,但返回一个错误,并且在 ubuntu 上使用 gcc

【问题讨论】:

  • 你的编译器是什么?
  • 代码 int *test() 声明 test 以返回 int *,但 arr 声明为 int (*arr)[cols],因此 return arr 返回 int (*)[cols]。 C 中没有办法返回指向可变长度数组的指针。相反,test 可以返回一个 void *,然后调用者将其转换为正确的类型。
  • 顺便说一句,永远不要在 C 中声明带有空参数列表的函数,如 int *test()。这是一种旧的声明风格,不应该在新代码中使用,因为它缺乏类型检查功能。要声明不带参数的函数,请使用(void) 作为其参数列表。如果函数接受参数,请在参数列表中列出它们及其类型。
  • 这也适用于main。不要使用int main()main 应使用 int main(void)int main(int argc, char *argv[]) 或您的实现支持的其他形式声明。

标签: c arrays multidimensional-array signature


【解决方案1】:

你的分配函数很好,除了一些细节:

  • 您应该将rowscols 作为参数传递
  • 您应该对ij 使用类型size_t,并迭代到rowscols,而不是硬编码边界。
  • 您应该在malloc(sizeof *arr * rows); 中使用括号以提高可读性: malloc(sizeof(*arr) * rows);
  • 您应该返回 &amp;arr[0][0]arr[0] 以确保类型正确。

问题是您不能将test 的返回类型定义为指向参数第二维的二维数组的指针。因此,分配arr = test(); 的类型错误无法修复。您可以通过将返回值转换为 (int (*)[cols]) 或简单地 (void *) 来解决这个缺点。

这是修改后的版本:

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

int *test(size_t rows, size_t cols) {
    int (*arr)[cols] = malloc(sizeof(*arr) * rows);
    if (arr) {
        // initialize the matrix
        size_t count = 0;
        for (size_t i = 0; i < rows; i++) {
            for (size_t j = 0; j < cols; j++) {
                arr[i][j] = count;
                count++;
            }
            /* code */
        }
        return &arr[0][0];
    }
    return NULL;
}

int main() {
    // assign rows and cols
    size_t rows = 3;
    size_t cols = 3;

    int (*arr)[cols] = (int (*)[cols])test(rows, cols);

    if (arr) {
        for (size_t i = 0; i < rows; i++) {
            for (size_t j = 0; j < cols; j++)
                printf("%d ", arr[i][j]);
            printf("\n");
        }
        free(arr);
    }
    return 0;
}

输出:

0 1 2 3 4 5 6 7 8

【讨论】:

  • 比我的回答更优雅,但是,您仍然需要将int * 转换为(int (*)[cols]) 的演员表。 @EricPostpischil 有什么想法吗?
  • @GuillaumeD:可以通过让test 返回void * 来避免演员阵容,但这也不优雅。
  • @chqrlie 谢谢它帮助了我,但我仍然不明白它背后的逻辑,你能给我一个参考或一些我可以从中学习的资源吗?我想对它有更好的了解。 t
  • @WeezKhan: @WeezKhan: test 分配一个二维数组,该数组本质上是一个数组 cols * rows* ints. The type int (*arr)[cols]` 将该数组的映射指定为一个数组cols 整数的数组。您不能将test 定义为返回此类型,因为cols 是一个变量。因此,您可以返回指向第一个 int 的指针,并使用它来初始化 main() 中具有相同类型 int (*arr)[cols] 的指针,但您需要如示例中所示的强制转换。
【解决方案2】:

如果全部你需要的是

从函数返回一个连续的内存分配数组

你可以忽略这个答案。

如果您尝试使用动态分配的连续内存块对二维容器(如矩阵)建模,您可以定义 struct 并传递它:

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

typedef struct {
    int rows, cols;
    int values[];      // I'm using a Flexible Array Member here.
} iMat;

iMat *alloc_matrix(int rows, int columns)
{
    assert(rows > 0  &&  columns > 0);
    iMat *tmp = malloc(sizeof *tmp + sizeof *(tmp->values) * rows * columns);   
    if (tmp)
    {
        tmp->rows = rows;
        tmp->cols = columns;
    }
    return tmp;
}

void fill_matrix_iota(iMat *m, int start)
{
    if ( m )
        for (size_t i = 0, n = m->rows * m->cols; i < n; ++i)
            m->values[i] = start + i;
}

void print_matrix(iMat *m, int width)
{
    if (m)
    {
        for (int i = 0, k = 0; i < m->rows; ++i)
        {
            for(int j = 0; j < m->cols; ++j, ++k)
            {
                printf("%*.d", width, m->values[k]);
            }
            putchar('\n');
        }
    }
}

iMat *make_transposed(iMat *m)
{
    if ( !m )
        return NULL;
    iMat *tmp = alloc_matrix(m->cols, m->rows);
    if ( tmp )
    {
        for (int i = 0; i < m->rows; ++i)
        {
            for(int j = 0; j < m->cols; ++j)
            {
                tmp->values[j * m->rows + i] = m->values[i * m->cols + j];
            }
        }        
    }
    return tmp;
}

int main(void)
{    
    iMat *a = alloc_matrix(3, 4);
    if (!a)
        exit(EXIT_FAILURE);

    fill_matrix_iota(a, 1);
    print_matrix(a, 3);

    iMat *b = make_transposed(a);
    if (!b)
    {
        free(a);
        exit(EXIT_FAILURE);
    }
    putchar('\n');
    print_matrix(b, 3);

    free(b);
    free(a);

    return EXIT_SUCCESS;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    相关资源
    最近更新 更多