首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >分配一个连续的内存块

分配一个连续的内存块
EN

Stack Overflow用户
提问于 2016-05-24 16:28:11
回答 3查看 143关注 0票数 1

我尝试使用一个连续的内存块,更多的是我尝试创建一个在编译时不知道的数组(在C99之前),因此这里不涉及variable-length arrays

我带来了以下几个方面:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

int main(void){
    unsigned int row, col,i, j, k;
    int l = 0;

    printf("Give the ROW: ");
    if ( scanf("%u",&row) != 1){
        printf("Error, scanf ROW\n");
        exit(1);
    }

    printf("Give the COL: ");
    if ( scanf("%u",&col) != 1){
        printf("Error, scanf COL\n");
        exit(2);
    }

    int *arr = malloc(sizeof *arr * row * col); /* This doesn't compile with `-pedantic` */
    if(arr == NULL){
        printf("Error, malloc\n");
        exit(3);
    }

    for ( i = 0; i < row ; i++){
        for ( j = 0 ; j < col ; j++){
            arr[i * col + j] = l;
            l++;
        }
    }

    for (k = 0 ; k < (row * col) ; k++){
        printf("%d ",arr[k]);
    }

    free(arr);
}

这给了我以下几点:

代码语言:javascript
复制
Give the ROW: 5
Give the COL: 5
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 

现在我有个问题:

这样做对吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-05-24 16:49:28

在这一行中有一个隐藏的错误:

代码语言:javascript
复制
arr[i * row + j] = k;

正确的索引计算是

代码语言:javascript
复制
arr[i * col + j] = k;

您没有注意到这个问题的原因是rowcol在代码中具有相同的值。例如,如果将row设置为6,将col设置为3,则错误将非常明显。您将为18个ints分配空间,但是当i为5而j为2时,代码将尝试访问位于数组末尾的位置[5*6 + 2],并导致未定义的行为。

这是地址计算的工作原理。下图显示了二维数组(row=6和col=3)实际上是如何在内存中布局的。注意,每一行上的项数等于数组中的列数。因此,每一行的起始索引是列数的倍数。在本例中,由于列数为3,行开始于索引0、3、6、9、.因此,给定二维数组中索引[i][j]的元素,一维数组中的索引是i*col + j

票数 3
EN

Stack Overflow用户

发布于 2016-05-24 16:42:15

这个方法没问题。尺寸在编译时就知道了。

获取15的原因是,arr表示基本地址,所以当您将15添加到arr时,它将给出包含15的块地址,稍后取消引用时,您将得到15。

票数 1
EN

Stack Overflow用户

发布于 2016-05-24 18:35:12

如果您不提前知道维度的数量(1、2、3或更多维度),那么这是唯一可用的方法。如果您知道维度的数量,但不知道它们的值,并且您没有可用的VLA,那么这也是唯一可用的方法。

因为我对编写文档感到厌烦,所以我用这个快速而肮脏的原型演示了如何将一维数组映射到不同维度的数组上:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

/**
 * Compute the offset into a 1D array based on a set of dimensions
 * and indices, and return the element at that offset.  You must pass
 * at least as many indices as number of dimensions; any extra indices
 * will not be processed.  
 *
 * Inputs:
 *    a       -- 1D array of data
 *    ndims   -- number of dimensions to map array onto
 *    dims    -- dimension sizes
 *    ...     -- index values
 *
 * Outputs: none
 *
 * Returns: value at desired index
 */
int access( const int * restrict a, size_t ndims, const size_t * restrict dims, ... )
{
  va_list ap;
  va_start( ap, dims );  point to first index value in argument list

  size_t idx = 0;

  /**
   * To find the right index for a given number of dimensions, 
   * we need to compute
   *
   *  d0 x d1:           i * d1 + j             
   *  d0 x d1 x d2:      i * d1 * d2 + j * d1 + k
   *  d0 x d1 x d2 x d3: i * d1 * d2 * d3 + j * d1 * d2 + k * d1 + l
   *
   * The loop below computes these as
   *
   *    i * d1 + j
   *    (i * d2 + j) * d1 + k
   *    (((i * d3 + j) * d2) + k) * d1 + l
   *
   * etc.
   */
  for ( size_t i = 1; i < ndims; i++ )
  {
    idx += va_arg( ap, size_t ); // get next index argument and advance ap
    idx *= dims[i];
  }
  idx += va_arg( ap, size_t );
  va_end( ap );
  return a[idx];
}

int main( void )
{
  int test[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  size_t dims2x5[] = {2, 5};       // for mapping test onto a 2x5 array
  size_t dims3x3[] = {3, 3};       // for mapping test onto a 3x3 array
  size_t dims2x2x2[] = {2, 2, 2};  // for mapping test onto a 2x2x2 array

  for ( size_t i = 0; i < dims2x5[0]; i++ )
    for ( size_t j = 0; j < dims2x5[1]; j++ )
      printf( "test[%zu][%zu] = %d\n", i, j, access( test, 2, dims2x5, i, j ) );

  for ( size_t i = 0; i < dims3x3[0]; i++ )
    for ( size_t j = 0; j < dims3x3[1]; j++ )
      printf( "test[%zu][%zu] = %d\n", i, j, access( test, 2, dims3x3, i, j ) );

  for ( size_t i = 0; i < dims2x2x2[0]; i++ )
    for ( size_t j = 0; j < dims2x2x2[1]; j++ )
      for ( size_t k = 0; k < dims2x2x2[2]; k++ )
        printf( "test[%zu][%zu][%zu] = %d\n", i, j, k, access( test, 3, dims2x2x2, i, j, k ));

  return 0;
}

以及产出:

代码语言:javascript
复制
test[0][0] = 0
test[0][1] = 1
test[0][2] = 2
test[0][3] = 3
test[0][4] = 4
test[1][0] = 5
test[1][1] = 6
test[1][2] = 7
test[1][3] = 8
test[1][4] = 9

test[0][0] = 0
test[0][1] = 1
test[0][2] = 2
test[1][0] = 3
test[1][1] = 4
test[1][2] = 5
test[2][0] = 6
test[2][1] = 7
test[2][2] = 8

test[0][0][0] = 0
test[0][0][1] = 1
test[0][1][0] = 2
test[0][1][1] = 3
test[1][0][0] = 4
test[1][0][1] = 5
test[1][1][0] = 6
test[1][1][1] = 7

这一点也不好看-- access( a, 3, dims2x2x2, i, j, k )并不像a[i][j][k]那样容易阅读。有了一些额外的抽象级别,您可以稍微清理一下,但它总是会感到有点尴尬。当然你也牺牲了一些表演。但是,如果你需要将一个一维数组映射到任意大小的N维数组上,而你甚至事先不知道维数,这是一个可能的解决方案。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37419127

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档