【问题标题】:Using a buffer with malloc使用带有 malloc 的缓冲区
【发布时间】:2012-09-11 23:42:41
【问题描述】:

我正在尝试将三个方形二维数组存储到缓冲区中,因此我使用了一个连续的内存块。如果数组大小是rxr,我的公式是:

buffer = (double*) malloc((r + r + r) * sizeof(double *) + 
    (r*r + r*r + r*r) * sizeof(double));

  if(buffer == NULL) {
    printf("out of memory\n");
    return 0;
  }

  for(i = 0, j = 0; i < r; i++) {
    a[i] = &buffer[j];
    j+=r;
  }

  for(i = 0; i < r; i++) {
    b[i] = &buffer[j];
    j+=r;
  }

  for(i = 0; i < r; i++) {
    c[i] = &buffer[j];
    j+=r;
  }

  a = buffer[j];
  b = buffer[j + r];
  c = buffer[j + r + r];

如你所见,我迷路了。 a、b、c 被声明为双指针(意味着指向数组数组的指针),所以我希望每个都有一个大小为 r 的数组,每个元素都指向它自己的大小为 r 的单独数组。任何想法...

【问题讨论】:

    标签: c malloc buffer


    【解决方案1】:

    您将 malloc'ing 指针与 malloc'ing doubles 本身混淆了。只需像这样分配双打:

    double* all = (double*) malloc( 3*r*r*sizeof(double));
    

    那么你的实际矩阵到哪里去了?

    double *p1 = all;
    double *p2 = &all[r*r];
    double *p3 = &all[2*r*r];
    

    请检查一个错误:) 但关键是你不需要同时 malloc 出双 * 和双。

    【讨论】:

    • 我不知道这个问题的答案,但是将指向矩阵的指针 malloc 也不是很好的风格,因为指针本身就是数组? (这里的评论编辑:你的代码不只是将我的指针设置为每个数组的第一个元素吗?我想要一个指针数组表示行,每个指针指向它自己的数组表示它的列。)
    • 指针不是数组,它们是指针。是的,指针和数组之间有密切的关系,但是如果你 malloced 指针只会分配 sizeof(double *),在 32 位机器上只有 4 个字节。数组的名称可以用作指针,是的,但它指向数组的第一个元素。 p[0]*p 是相同的,可以互换。
    【解决方案2】:

    所以,如果我理解正确的话,你想要的是三个 r x r 数组(abc),但你希望它们三个都连续存储;本质上,后备存储将是一个 3 x r x r 数组。

    如果r 的大小在编译时未知并且您正在使用支持可变长度数组的 C99 或 C11 实现,您可以执行以下操作: p>

    size_t r = ...;
    
    double (*a)[r] = NULL;
    double (*b)[r] = NULL;
    double (*c)[r] = NULL;
    
    double (*backing_store)[r][r] = malloc(3 * sizeof *backing_store);
    if (!backing_store)
    {
      // panic and exit
    }
    
    a = backing_store[0];
    b = backing_store[1];
    c = backing_store[2];
    

    然后您可以使用 abc,就好像它们是 double 的常规 rxr 数组一样:

    a[i][j] = ...;
    printf("%f\n", b[x][y]);
    

    等等。

    完成后,只需释放backing_store

    free(backing_store);
    

    为什么会这样?

    表达式backing_store的类型为“指向r的指针-r的元素数组-double的元素数组。由于表达式backing_store[i]等价于*(backing_store + i),因此下标运算符隐式取消引用指针,所以表达式的类型是“r-元素数组r-元素数组double”。每个backing_store[0]backing_store[1]backing_store[2]都是rx@ 987654352@double 的数组。

    请记住,在大多数情况下,“N-T 的元素数组”类型的表达式被隐式转换(“衰减”)为“指向T”的类型的表达式,其值为数组中第一个元素的地址。

    因此,表达式backing_store[0]从类型“r-元素数组r-元素数组double”转换为“指向r的指针-元素数组double”,即恰好是a的类型,值是第一个子数组的地址(恰好和backing_store一样)。同样,应用下标运算符隐式地取消引用指针,因此a[i][j]a 之后给出ith 数组的jth 元素。

    如果r 在编译时是已知的(即,它是一个常量表达式)那么过程是相同的,你只是不必声明变量r

    #define R ...
    
    double (*a)[R] = NULL;
    double (*b)[R] = NULL;
    double (*c)[R] = NULL;
    
    double (*backing_store)[R][R] = malloc(3 * sizeof *backing_store);
    if (!backing_store)
    {
      // panic and exit
    }
    
    a = backing_store[0];
    b = backing_store[1];
    c = backing_store[2];
    

    如果r 在编译时已知并且您没有可用的可变长度数组(使用不支持的 C89 或 C11 编译器) VLA),那么它会变得有点混乱。这里我们将backing_store 视为double 的一维数组,并计算每个子数组的一维下标:

    double *a = NULL;
    double *b = NULL;
    double *c = NULL;
    
    double *backing_store = malloc(3 * r * r * sizeof *backing_store);
    if (!backing_store)
    {
      // panic
    }
    
    a = backing_store;
    b = backing_store + r * r;
    c = backing_store + 2 * r * r;    
    
    a[i*r+j] = ...;
    printf("%f\n", b[x*r+y]);
    

    同样,您只需要在完成后释放backing_store

    free(backing_store);
    

    不像使用二维下标那样漂亮,但它应该可以工作。

    【讨论】:

      【解决方案3】:

      首先,二维数组通常作为数组的数组而不是作为指向行的指针更好地管理,除非有特殊的理由使用指针。为此,我们可以这样做:

      double (*Memory)[r][r] = malloc(3 * sizeof *Memory);
          // Now Memory points to three r-by-r arrays of double.
      double (*a)[r] = Memory[0];
      double (*b)[r] = Memory[1];
      double (*c)[r] = Memory[2];
      

      但是,如果您想使用指向行的指针,那么您应该为指针分配空间,而不是为元素分配空间。 (如果不这样做,则存在符合 C 标准的问题,尤其是填充和对齐方面。此外,您的代码将 buffer 视为一种类型的数组,doubledouble *。但地址算术您有时需要指向 double [设置元素地址时] 的指针,有时需要指向 double * [将指针地址设置为双精度时] 的指针。)要使用指向行的指针,您可以使用以下命令进行分配:

      double *(*PointerMemory)[r] = malloc(3 * sizeof *PointerMemory);
          // PointerMemory points to three arrays of r elements of pointers to double.
      double (*ElementMemory)[r][r] = malloc(3 * sizeof *ElementMemory);
      

      然后你可以设置指向行的指针:

      // Set a to point to the first array of r elements of pointers to double.
      double *a[r] = PointerMemory[0];
      // Initialize the elements of a to point to rows of the first r-by-r array of double.
      for (i = 0; i < r; ++i)
          a[i] = ElementMemory[0][i];
      
      // Set b for the second array of pointers and the second array of double.
      double *b[r] = PointerMemory[0];
      for (i = 0; i < r; ++i)
          b[i] = ElementMemory[1][i];
      
      // Set c for the third arrays.
      double *c[r] = PointerMemory[0];
      for (i = 0; i < r; ++i)
          c[i] = ElementMemory[2][i];
      

      【讨论】:

        猜你喜欢
        • 2021-10-24
        • 1970-01-01
        • 1970-01-01
        • 2021-07-21
        • 2013-09-26
        • 2012-01-05
        • 1970-01-01
        • 2011-05-04
        • 1970-01-01
        相关资源
        最近更新 更多