分配连续的记忆

时间:2012-10-27 23:21:11

标签: c arrays unix memory

我正在尝试在C中分配大量连续内存并将其打印给用户。我这样做的策略是创建两个指针(一个指向double的指针,一个指向指向double的指针),malloc中的一个指向整个大小(m * n),在这种情况下是指向double的指针。然后malloc第二个大小为m。最后一步是迭代m的大小并执行指针运算,以确保大数组中双精度数的地址将存储在连续的内存中。这是我的代码。但是当我打印出地址时,它似乎并不是连续的(或以任何顺序)。如何正确打印出双打的内存地址(所有这些都是0.0的值)?

/* correct solution, with correct formatting */


/*The total number of bytes allocated was:  4
0x7fd5e1c038c0 - 1
 0x7fd5e1c038c8 - 2
 0x7fd5e1c038d0 - 3
 0x7fd5e1c038d8 - 4*/

 double **dmatrix(size_t m, size_t n);

int main(int argc, char const *argv[])
{
    int m,n,i;
    double ** f;
    m = n = 2;  
    i = 0;

    f = dmatrix(sizeof(m), sizeof(n));

    printf("%s %d\n", "The total number of bytes allocated was: ", m * n);
    for (i=0;i<n*m;++i) {
        printf("%p - %d\n ", &f[i], i + 1);
    }
    return 0;
}

double **dmatrix(size_t m, size_t n) {

    double ** ptr1 = (double **)malloc(sizeof(double *) * m * n);
    double * ptr2 = (double *)malloc(sizeof(double) * m);

    int i;
    for (i = 0; i < n; i++){
        ptr1[i] = ptr2+m*i;
    }


    return ptr1;
}

2 个答案:

答案 0 :(得分:13)

请记住,记忆只是记忆。听起来很陈词滥调,但很多人似乎都认为C中的内存分配和内存管理是一种神奇的巫术。它不是。在一天结束时,你会分配你需要的任何内存,并在你完成后释放它。

首先从最基本的问题开始:如果您需要&#39; n&#39; double值,你会如何分配它们?

double *d1d = calloc(n, sizeof(double));
// ... use d1d like an array (d1d[0] = 100.00, etc. ...
free(d1d);

足够简单。下一个问题,分为两部分,第一部分与内存分配无关(尚):

  1. 大小为double的2D数组中有多少m*n个值?
  2. 我们如何分配足够的内存来容纳所有人。
  3. 数目:

    1. m * n二维矩阵中有m*n个双打
    2. 分配足够的内存来保存(m * n)双打。
    3. 看起来很简单:

      size_t m=10;
      size_t n=20;
      double *d2d = calloc(m*n, sizeof(double));
      

      但是我们如何访问实际元素?一点点数学是有序的。了解mn,您可以轻松完成此操作

      size_t i = 3; // value you want in the major index (0..(m-1)).
      size_t j = 4; // value you want in the minor index (0..(n-1)).
      d2d[i*n+j] = 100.0;
      

      有更简单的方法吗?在标准C中,;在C ++中。标准C支持非常方便的功能,可以为声明动态大小的可索引数组生成正确的代码:

      size_t m=10;
      size_t n=20;
      double (*d2d)[n] = calloc(m, sizeof(*d2d));
      

      不能强调这一点:标准C支持这一点,C ++不支持。如果您正在使用C ++,那么您可能想要编写一个对象类来为您完成所有操作,因此除此之外不会被提及。

      那么上面的实际做什么?首先,显而易见的是,我们仍在分配之前分配的相同数量的内存。也就是说,m*n元素,每个sizeof(double)都很大。但是你可能会问自己,&#34;那个变量声明是什么?&#34;这需要一点解释。

      这有明显的区别:

      double *ptrs[n];  // declares an array of `n` pointers to doubles.
      

      和此:

      double (*ptr)[n]; // declares a pointer to an array of `n` doubles.
      

      编译器现在知道 wide 每行是如何(n每行加倍),所以我们现在可以使用 two 索引:

      size_t m=10;
      size_t n=20;
      double (*d2d)[n] = calloc(m, sizeof(*d2d));
      d2d[2][5] = 100.0; // does the 2*n+5 math for you.
      free(d2d);
      

      我们可以将其扩展到3D吗?当然,数学开始看起来有点奇怪,但它仍然只是计算成一个巨大的“块”公羊。首先是“做你自己的数学”#34;方式,用[i,j,k]索引:

      size_t l=10;
      size_t m=20;
      size_t n=30;
      double *d3d = calloc(l*m*n, sizeof(double));
      
      size_t i=3;
      size_t j=4;
      size_t k=5;
      d3d[i*m*n + j*m + k] = 100.0;
      free(d3d);
      

      你需要盯着数学中的一分钟来真正凝聚它如何计算实际上那块大块的double值。使用上述维度和所需的索引,&#34; raw&#34; index是:

      i*m*n = 3*20*30 = 1800
      j*m   = 4*20    =   80
      k     = 5       =    5
      ======================
      i*m*n+j*m+k     = 1885
      

      所以我们正在击中那个大线性区块中的第1885个元素。让我们做另一个。怎么样[0,1,2]?

      i*m*n = 0*20*30 =    0
      j*m   = 1*20    =   20
      k     = 2       =    2
      ======================
      i*m*n+j*m+k     =   22
      

      即。线性阵列中的第22个元素。

      现在应该很明显,只要你保持在数组的自定义范围内,i:[0..(l-1)], j:[0..(m-1)], and k:[0..(n-1)] 任何有效的索引三重奏都将在线性数组中找到一个唯一的值,而不是其他< em>有效三重奏也将找到。

      最后,我们使用与之前使用2D数组相同的数组指针声明,但将其扩展为3D:

      size_t l=10;
      size_t m=20;
      size_t n=30;
      double (*d3d)[m][n] = calloc(l, sizeof(*d3d));
      d3d[3][4][5] = 100.0;
      free(d3d);
      

      同样,所有这一切确实是我们之前手工做的相同数学,但让编译器为我们做。

      我意识到可能有点太多了,但这很重要。如果它是最重要的,你有连续的内存矩阵(比如将矩阵输入到OpenGL等图形渲染库中),你可以使用上述技术相对轻松地完成它。

      最后,你可能想知道为什么有人会把指针数组的指针数组到指针数组到第一位的值,如果你能这样做呢?原因很多。假设您正在替换行。交换指针很容易;复制整行?昂贵。假设您正在替换3D数组(m*n)中的整个表格维(l*n*m),甚至更多 - 交换指针:简单;复制整个m*n表? 昂贵。而那个不那么明显的答案。如果行宽度需要在行与行之间独立怎么办(即row0可以是5个元素,row1可以是6个元素)。固定的l*m*n分配根本不起作用。

      祝你好运。

答案 1 :(得分:1)

没关系,我明白了。

  /* The total number of bytes allocated was:  8
    0x7fb35ac038c0 - 1
     0x7fb35ac038c8 - 2
     0x7fb35ac038d0 - 3
     0x7fb35ac038d8 - 4
     0x7fb35ac038e0 - 5
     0x7fb35ac038e8 - 6
     0x7fb35ac038f0 - 7
     0x7fb35ac038f8 - 8 */

double ***d3darr(size_t l, size_t m, size_t n);

int main(int argc, char const *argv[])
{
    int m,n,l,i;
    double *** f;
    m = n = l = 10; i = 0;

    f = d3darr(sizeof(l), sizeof(m), sizeof(n));
    printf("%s %d\n", "The total number of bytes allocated was: ", m * n * l);
    for (i=0;i<n*m*l;++i) {
        printf("%p - %d\n ", &f[i], i + 1);
    }

    return 0;
}

double ***d3darr(size_t l, size_t m, size_t n){

    double *** ptr1 = (double ***)malloc(sizeof(double **) * m * n * l);
    double ** ptr2 = (double **)malloc(sizeof(double *) * m * n);
    double * ptr3 = (double *)malloc(sizeof(double) * m);

    int i, j;
    for (i = 0; i < l; ++i) {
        ptr1[i] = ptr2+m*n*i;
        for (j = 0; j < l; ++j){
            ptr2[i] = ptr3+j*n;
        }
    }

    return ptr1;
}