Return 这种创建二维数组的奇怪方法的函数类型

Return type of function for this odd way of creating 2D array

此问题的来源参考:

我使用了引用 post 的答案中显示的代码的改编来创建字符串数组:

char (*string)[rows] = malloc(sizeof(char [rows][cols]));
memset(string, 0, sizeof(char [rows][cols]));

我意识到对于非常大的数组,此方法不是最佳方法,因为在尝试分配时单个大块连续内存变得非常昂贵。但是在创建中小型阵列时,这些优势可能会很有吸引力。例如。此方法仅使用对 malloc() 的一次调用来分配一个连续的块内存,因此在使用它时只需要对 free() 进行一次调用,使其成为我所见过的更多惯用方法的理想替代方法. (多次调用 malloc()free() 的用户)

所以,我想把它封装成一个函数,但至今没发现return兼容什么类型:

T  CreateStringArray(int rows, int cols)
{
    char (*string)[rows] = malloc(sizeof(char [rows][cols]));
    memset(string, 0, sizeof(char [rows][cols]));

    return T;
}

什么形式的 T 可以使用此函数?

您可以尝试类似的方法:

void * CreateStringArray(int rows, int cols)
{
    char (*string)[cols] = malloc(sizeof(char [rows][cols]));
    memset((void*)string, 0, sizeof(char [rows][cols]));

    return string;
}

int main()
{
    char (*p)[4] = (char (*)[4])CreateStringArray(3, 4);
}

请注意,char (*string)[cols] 应定义为 cols 而不是 rows。因为 string 是指向 cols 元素的一维数组的指针。

分机:

关于为什么使用 cols 而不是 rows 的详细信息:

数组名在使用时是指向其第一个元素的指针。比如int arr[5],这里arr就是指向a[0].

的指针

虽然 int a[rows][cols],这里 a 不是指向 a[0][0] 的指针,而是指向其 a[0] 的指针,其类型为 int (*)[cols]

要理解这一点,你得想一想C是如何在内存中存储一​​个多维数组的?它实际上是逐行存储为一维数组。

例如int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; 存储为 1 2 3 4 5 6,这里 a[0]{1, 2, 3} 所以指向 a[0] 的指针是指向 {1, 2, 3} 的指针,它是指向数组的指针3 个整数,可以写成 int (*)[3] => 通常它是 `int (*) [cols]'

如果我理解正确,函数应该return函数内分配的指针,

指针的类型为char (*)[cols],但是当声明函数时,函数的return类型对变量cols一无所知。

在这种情况下,函数应该声明为

void * CreateStringArray(int rows, int cols) )
{
    char (*string)[rows] = malloc(sizeof(char [rows][cols]));
    memset(string, 0, sizeof(char [rows][cols]));

    return string;
}

在调用者中你可以写

char ( *string )[cols] = CreateStringArray( rows, cols );

你会 喜欢 到 return char (*)[rows],但这是一个可变修改的类型,并且只有对象(不是函数)声明没有链接(与所有函数不同)在块或函数原型范围内可以具有可变修改类型 (C17 6.7.6.2/2)。

因此,您可以为函数的 return 类型做的最好的事情是 char *void *

但是,您可以使用宏对其进行修补:

void *CreateStringArray_func(int rows, int cols)
{
    char (*string)[rows] = malloc(sizeof(char [rows][cols]));
    memset(string, 0, sizeof(char [rows][cols]));

    return string;
}

#define CreateStringArray(rows, cols) \
    ((char (*)[rows]) CreateStringArray_func(rows, cols))

但在那种情况下,我可能只会使用

#define CreateStringArray(rows, cols) calloc(rows, cols)

后者也可以加cast,但我以不对分配函数的结果进行cast的原则省略