Use*_*291 110 c arrays malloc allocation multidimensional-array
在一个项目中,有人推动了这一行:
double (*e)[n+1] = malloc((n+1) * sizeof(*e));
Run Code Online (Sandbox Code Playgroud)
据推测,这会创建一个(n + 1)*(n + 1)双倍的二维数组.
据说,我说,因为到目前为止,我没有人问我能告诉我它的作用,确切地说,它起源于何处或为什么它应该起作用(据称,它确实如此,但我还没有购买它).
也许我错过了一些明显的东西,但如果有人能够向我解释上述内容,我会很感激.因为就个人而言,如果我们使用我们真正理解的东西,我会感觉好多了.
Som*_*ude 87
该变量e是指向n + 1类型元素数组的指针double.
使用dereference运算符e为您提供基类型,e即" n + 1类型元素数组double".
所述malloc呼叫简单地取碱型的e(如上所述),并得到它的大小,通过相乘n + 1,并且该大小传递给malloc函数.基本上分配一个元素数组的n + 1数组.n + 1double
Lun*_*din 56
这是您应该动态分配2D数组的典型方法.
e是一个指向类型数组的数组指针double [n+1].sizeof(*e)因此给出了指向类型的类型,它是一个double [n+1]数组的大小.n+1此类阵列分配空间.e此数组数组中的第一个数组.eas e[i][j]访问2D阵列中的各个项目.我个人认为这种风格更容易阅读:
double (*e)[n+1] = malloc( sizeof(double[n+1][n+1]) );
Run Code Online (Sandbox Code Playgroud)
Joh*_*ode 39
这个成语自然地脱离了一维数组分配.让我们从分配一些任意类型的一维数组开始T:
T *p = malloc( sizeof *p * N );
Run Code Online (Sandbox Code Playgroud)
简单吧?该表达 *p有型T,所以sizeof *p给出了相同的结果sizeof (T),所以我们要为某个分配足够的空间N的-元素阵列T.这适用于任何类型T.
现在,让我们T用类似的数组类型替换R [10].然后我们的分配成为
R (*p)[10] = malloc( sizeof *p * N);
Run Code Online (Sandbox Code Playgroud)
这里的语义与1D分配方法完全相同 ; 所有改变的是类型p.而不是T *,它现在R (*)[10].表达*p具有类型T是类型R [10],因此sizeof *p等效于sizeof (T)这相当于sizeof (R [10]).所以我们为Nby 10元素数组分配了足够的空间R.
如果我们想要的话,我们可以更进一步; 假设R它本身就是一个数组类型int [5].替换为R我们获得
int (*p)[10][5] = malloc( sizeof *p * N);
Run Code Online (Sandbox Code Playgroud)
相同的交易 - sizeof *p是相同的sizeof (int [10][5]),我们最终分配一个连续的大块内存,足以容纳一个Nby 10by 5数组int.
那就是分配方面; 接入方面怎么样?
请记住,[]下标操作定义在指针运算方面:a[i]被定义为*(a + i)1.因此,下标运算符[] 隐式地取消引用指针.如果p是指向的指针T,则可以通过使用一元运算*符显式解除引用来访问指向的值:
T x = *p;
Run Code Online (Sandbox Code Playgroud)
或者使用[]下标运算符:
T x = p[0]; // identical to *p
Run Code Online (Sandbox Code Playgroud)
因此,如果p指向数组的第一个元素,则可以通过使用指针上的下标来访问该数组的任何元素p:
T arr[N];
T *p = arr; // expression arr "decays" from type T [N] to T *
...
T x = p[i]; // access the i'th element of arr through pointer p
Run Code Online (Sandbox Code Playgroud)
现在,让我们再次执行替换操作并替换T为数组类型R [10]:
R arr[N][10];
R (*p)[10] = arr; // expression arr "decays" from type R [N][10] to R (*)[10]
...
R x = (*p)[i];
Run Code Online (Sandbox Code Playgroud)
一个明显的区别; 我们p在应用下标运算符之前显式解除引用.我们不想下标p,我们要下标到什么p 点(在这种情况下,数组 arr[0]).由于一元*比标低优先级[]运营商,我们必须使用括号明确组p用*.但请记住,从上面*p也是p[0]如此,所以我们可以用它代替
R x = (p[0])[i];
Run Code Online (Sandbox Code Playgroud)
要不就
R x = p[0][i];
Run Code Online (Sandbox Code Playgroud)
因此,如果p指向2D数组,我们可以p像这样索引到该数组:
R x = p[i][j]; // access the i'th element of arr through pointer p;
// each arr[i] is a 10-element array of R
Run Code Online (Sandbox Code Playgroud)
以这种相同的结论如上而代R以int [5]:
int arr[N][10][5];
int (*p)[10][5]; // expression arr "decays" from type int [N][5][10] to int (*)[10][5]
...
int x = p[i][j][k];
Run Code Online (Sandbox Code Playgroud)
如果指向常规数组,或者它指向通过分配的内存,则它的工作方式相同. pmalloc
这个成语有以下好处:
T **arr = malloc( sizeof *arr * N );
if ( arr )
{
for ( size_t i = 0; i < N; i++ )
{
arr[i] = malloc( sizeof *arr[i] * M );
}
}
Run Code Online (Sandbox Code Playgroud)
free.同样,对于零碎的分配方法也不是这样,你必须在解除分配arr[i]之前解除分配arr.
有时候,零碎的分配方法是可取的,例如当你的堆碎片非常碎片而且你不能将你的内存分配为一个连续的块时,或者你想要分配一个"锯齿状"的数组,其中每一行可以有不同的长度.但总的来说,这是更好的方法.