【问题标题】:Declare global contiguous 2d array at runtime. The dimensions are unknown at compile time C在运行时声明全局连续二维数组。尺寸在编译时未知 C
【发布时间】:2016-03-18 07:52:26
【问题描述】:

我想在 C 中声明一个全局二维数组,并在运行时分配 连续 内存,因为在编译时次要维度是未知的。 我想用 2 索引符号 A[i][j] 取消对数组的引用。 如果数组不是全局 c99 表示法“double A[m][n]”会很方便,但在我的情况下不适用。 什么是正确的策略?

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

//TO DO
//DECLARE array here

void fun1() {
    array[3][2] = 42.0;
}

int main(int argc,char *argv[])
{
    int rows = atol(argv[1]);
    int cols = atol(argv[2]);

    //TO DO
    //Allocate memory for array here
    fun1();
    printf("Array[3][2]=%f\n",array[3][2]);

    return(0);
}

【问题讨论】:

  • 您的问题标题为at compile time C,但在帖子本身中您说的是allocate contiguous memory at runtime。那么...是哪一个?
  • 维度通过命令行参数传递,但数组必须声明为全局的。
  • 那你需要在runtime分配;调用程序的命令行参数在编译时显然是未知的。请编辑问题以反映这一点。
  • 我做了一些修改。我希望现在更清楚了。

标签: c dynamic allocation contiguous


【解决方案1】:

不幸的是,C 语言不太可能实现您的要求。

有一个略显丑陋的宏解决方案。由于宏指的是全局数组本身和包含其第二维的全局变量,因此您必须小心不要在使用宏的任何函数中隐藏全局变量。在这里,我使用了以下划线结尾的笨拙名称,以避免重复使用名称。

除此之外,它应该可以工作:

void*  global_array_void_;
size_t global_array_minor_dim_;

#define global_array ((double(*)[global_array_minor_dim_])global_array_void_)    

在你可以使用宏之前,你需要分配它并初始化全局变量:

void init_global_array(int rows, int cols) {
    global_array_minor_dim_ = cols
    global_array_void_ = malloc(rows * cols * sizeof global_array[0][0]);
}

从那时起,您可以像使用常规数组一样使用 global_array

void f(int r, int c, double v) {
    global_array[r][c] = v;
}

Live on coliru.

演员((double (*)[cols])(array_void_)) 中的类型可能并不明显。它表示一个指向colsdoubles 数组的指针,这就是double[][cols] 将衰减为指针的内容。请注意,double[][cols]不会衰减为 double**,这是一种完全不同(且不兼容)的类型。

使用该定义,sizeof global_array[r] 具有正确的值:cols * sizeof(double)。对比一下sizeof argv[i]


执行此操作的更传统方法是使用函数来计算精确索引。这仍然取决于可用的次要维度:

double* global_array;
size_t global_array_minor_dim_;

void init_global_array(int rows, int cols) {
    global_array_minor_dim_ = cols
    global_array_void_ = malloc(rows * cols * sizeof global_array[0][0]);
}

double* global_array_at(int r, int c) {
    return &global_array[r * global_array_minor_dim_ + c];
}

现在您可以使用*global_array_at(r, c) 代替global_array[r][c]。在 C 中,不可能消除 * 并且仍然有赋值工作(在 C++ 中,函数可能返回 double&amp; 而不是 double*),但这可以再次通过宏来解决。

【讨论】:

    【解决方案2】:

    这里有一个示例供您学习:

    #include <stdlib.h>
    void main(void)
    {
        int **f;
        int n = 2, m = 3;
    
        f = (int **)malloc(sizeof(int)*n *m);
    
        f[1][2] = 3;
    }
    

    【讨论】:

    • 您发布的代码无法编译,格式错误并且使用了不好的做法(转换malloc的结果)。
    • 它编译得很好。格式没问题。有一些空白行可以删除,但缩进是正确的。变量名很弱,因为没有上下文,但这是无法避免的。铸造 malloc 是解决购买 OP 问题的一种方法。可能还有其他解决方案。如果您愿意,请随意编写自己的代码。
    • 此外,即使语法错误已修复,它也不起作用。 f[1][2] 编译如果 fint** 但它不引用二维数组中的位置。它期望f[1] 成为指针数组的索引。
    • @nicomp:OP 要求在连续内存中使用二维数组。您正在提供指向一维数组的一维数组,但您不分配或初始化索引数组。所以这不是问题的答案。而且它不起作用。
    • @nicomp:如果通过“正确操作索引”,您的意思是“将f[i][j] 写为f[i*m+j],那么这将起作用(前提是f 被声明为int* 而不是@ 987654331@)。但是 OP 要求提供一个解决方案,您可以在其中编写f[i][j],而您的示例代码实际上使用了f[i][j]。而且,并非巧合,它存在段错误。现在,如果您不同意我的分析,您可以证明通过编辑答案中的代码使其不会出现段错误(理想情况下,不将f[1][2] = 3; 更改为f[1*3+2] = 3;),我很容易出错。这应该很简单,¿no?跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 2012-12-11
    • 1970-01-01
    • 2016-02-21
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多