C语言内存分配——3维数组
Memory allocation in C language - 3D array
我想为C语言的数据立方体分配内存。我的意思是,我需要分配一个 3D 数组。但是,我的代码 returns 存在分段错误,我不知道为什么。
我相信我的循环是正确的,但事实是,我的代码不起作用。
这是我的代码:
int malloc3dfloat(float ****array, int q, int r, int s) {
// allocate the q*r*s contiguous items
float *p = (float *) malloc(q*r*s*sizeof(float));
if (!p) return -1;
// allocate the row pointers into the memory
(*array) = (float ***) malloc(q*sizeof(float**));
if (!(*array)) {
free(p);
return -1;
}
for (int i=0; i<q; i++)
{
(*array)[i] = (float **) malloc(r*sizeof(float*));
if (!(*array[i]))
{
free(p);
return -1;
}
}
//set up the pointers into the contiguous memory
for (int i=0; i<q; i++)
{
for (int j=0; j<r; j++)
{
(*array)[i][j] = &(p[(i*r+j)*s]);
}
}
return 0;
}
只需使用具有动态存储的可变长度数组。
float (*array)[r][s]=calloc(q, sizeof *array);
就这些了!
现在使用 array[i][j][k]
语法访问单个元素。
int
对比 size_t
数学
int q, int r, int s
...
// v---v Product calculated using int math
// float *p = malloc(q*r*s*sizeof(float));
// Less chance of overflow
float *p = malloc(sizeof (float) * q*r*s);
// or even better
float *p = malloc(sizeof *p * q*r*s);
// ^-------^ Product calculated using wider of size_t and int math
OP 的 malloc3dfloat()
既不分配真正的 3D 也不分配 jagged 数组,而是两者的混合。
分配一个锯齿状的:
// Full out-of-memory handling omitted for brevity
int malloc3dfloat_j(float ****array, int q, int r, int s) {
float ***a = malloc(sizeof *a * q);
if (a == NULL) ...
for (int qi = 0; qi < q; qi++) {
a[qi] = malloc(sizeof a[qi][0] * r);
if (a[qi] == NULL) ...
for (int ri = 0; ri < r; ri++) {
a[qi][ri] = malloc(sizeof a[qi][ri][0] * s);
if (a[qi][ri] == NULL) ...
}
}
*array = a;
return 0;
}
没有注意到您想要 post 中的连续内存!!
如果无论如何这里有用的话,这里有一些代码来制作 3Dtab(并擦除它):
int malloc3dfloatBIS(float ****array, int d1, int d2, int d3) {
if (!(*array = malloc(sizeof(array) * d3)))
return -1;
for (int i = 0; i < d2 ; ++i)
if (!((*array)[i] = malloc(sizeof(array) * d2))) {
while (i)
free ((*array)[i--]);
return -1;
}
for (int i = 0; i < d2 ; ++i)
for (int j = 0; j < d1 ; ++j){
if (!((*array)[i][j] = malloc(sizeof(****array) * d1))){
for (;i;--i){
while (j){
free ((*array)[i][--j]);
}
j = d1;
free ((*array)[i]);
}
return -1;
}
}
return 0;
}
void erase(float ****array, int d1, int d2, int d3) {
for (int i = d2;i ; --i){
int j = d1;
while (j)
free ((*array)[i -1][--j]);
free ((*array)[i - 1]);
}
free (*array);
}
我想到了一个类似于@tsanisl 发布的解决方案。我从来没有这样做过,所以我对如何让它工作有一些疑问,所以我开发了一个简单的程序来展示它:
$ cat ap.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define ARRAY_SSIZE(a) ((ptrdiff_t) ARRAY_SIZE(a))
int main(void)
{
int (*ap)[2][3][5];
int l = 0;
ap = malloc(sizeof(*ap));
printf("%zu\n", sizeof(*ap));
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(*ap); ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE((*ap)[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE((*ap)[0][0]); ++k) {
(*ap)[i][j][k] = l++;
}
}
}
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(*ap); ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE((*ap)[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE((*ap)[0][0]); ++k)
printf("%3i", (*ap)[i][j][k]);
putchar('\n');
}
putchar('\n');
}
}
$ ./a.out
120
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
25 26 27 28 29
我希望它有用:-)
我做了一些进一步的测试来检查是否没有未定义的行为,并检查我正在访问的地址是否连续,但我在这里删除它们以简化代码。
编辑:
我上面的解决方案与@tsanisl 的解决方案略有不同。以下是他的建议。使用您喜欢的那个。两者都很好。
这个更类似于你在函数中得到的,其中数组衰减到指向其第一个元素的指针。
$ cat ap.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define ARRAY_SSIZE(a) ((ptrdiff_t) ARRAY_SIZE(a))
int main(void)
{
int (*ap/*[2]*/)[3][5];
int l = 0;
ap = malloc(sizeof(*ap) * 2);
printf("%zu\n", sizeof(*ap) * 2);
for (ptrdiff_t i = 0; i < 2; ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE(ap[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE(ap[0][0]); ++k) {
ap[i][j][k] = l++;
}
}
}
for (ptrdiff_t i = 0; i < 2; ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE(ap[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE(ap[0][0]); ++k)
printf("%3i", ap[i][j][k]);
putchar('\n');
}
putchar('\n');
}
}
$ ./a.out
120
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
25 26 27 28 29
H.S。已经指出了你的错误。但其他人正确地建议只使用一个指针并避免预计算。然后你可以转到 VLA。我仍然喜欢 chux 版本,但为了获得正确的 malloc()
故障管理,您可以这样做:
#include <stdio.h>
#include <stdlib.h>
// Full out-of-memory handling included
int malloc3dfloat(float ****array, int q, int r, int s)
{
char *p = malloc((sizeof(float**) + (sizeof(float*) + sizeof(float) * s) * r) * q);
if (p == NULL) {
return -1;
}
float ***pq = (void*)(p);
float **pr = (void*)(p + sizeof(float**) * q);
float *ps = (void*)(p + (sizeof(float**) + sizeof(float*) * r) * q);
for (int qi = 0; qi < q; ++qi) {
pq[qi] = pr + qi*r;
for (int ri = 0; ri < r; ++ri) {
pq[qi][ri] = ps + (qi*r + ri)*s;
}
}
*array = pq;
return 0;
}
这很丑,我不得不承认。但是所有指针和值都作为一个 malloc 粘在一起,允许简单的释放和一次检查以验证是否有足够的内存。
性能方面我一无所知,但重新分配真的很容易(只需一个免费的):
int main(void)
{
float ***x;
int res = malloc3dfloat(&x, 3, 4, 2);
for (int q = 0; q < 3; ++q) {
for (int r = 0; r < 4; ++r) {
for (int s = 0; s < 2; ++s) {
x[q][r][s] = rand() % 10;
}
}
}
for (int q = 0; q < 3; ++q) {
for (int r = 0; r < 4; ++r) {
for (int s = 0; s < 2; ++s) {
printf("%f ", x[q][r][s]);
}
printf("\n");
}
printf("---\n");
}
free(x);
return 0;
}
我想为C语言的数据立方体分配内存。我的意思是,我需要分配一个 3D 数组。但是,我的代码 returns 存在分段错误,我不知道为什么。
我相信我的循环是正确的,但事实是,我的代码不起作用。
这是我的代码:
int malloc3dfloat(float ****array, int q, int r, int s) {
// allocate the q*r*s contiguous items
float *p = (float *) malloc(q*r*s*sizeof(float));
if (!p) return -1;
// allocate the row pointers into the memory
(*array) = (float ***) malloc(q*sizeof(float**));
if (!(*array)) {
free(p);
return -1;
}
for (int i=0; i<q; i++)
{
(*array)[i] = (float **) malloc(r*sizeof(float*));
if (!(*array[i]))
{
free(p);
return -1;
}
}
//set up the pointers into the contiguous memory
for (int i=0; i<q; i++)
{
for (int j=0; j<r; j++)
{
(*array)[i][j] = &(p[(i*r+j)*s]);
}
}
return 0;
}
只需使用具有动态存储的可变长度数组。
float (*array)[r][s]=calloc(q, sizeof *array);
就这些了!
现在使用 array[i][j][k]
语法访问单个元素。
int
对比 size_t
数学
int q, int r, int s
...
// v---v Product calculated using int math
// float *p = malloc(q*r*s*sizeof(float));
// Less chance of overflow
float *p = malloc(sizeof (float) * q*r*s);
// or even better
float *p = malloc(sizeof *p * q*r*s);
// ^-------^ Product calculated using wider of size_t and int math
OP 的 malloc3dfloat()
既不分配真正的 3D 也不分配 jagged 数组,而是两者的混合。
分配一个锯齿状的:
// Full out-of-memory handling omitted for brevity
int malloc3dfloat_j(float ****array, int q, int r, int s) {
float ***a = malloc(sizeof *a * q);
if (a == NULL) ...
for (int qi = 0; qi < q; qi++) {
a[qi] = malloc(sizeof a[qi][0] * r);
if (a[qi] == NULL) ...
for (int ri = 0; ri < r; ri++) {
a[qi][ri] = malloc(sizeof a[qi][ri][0] * s);
if (a[qi][ri] == NULL) ...
}
}
*array = a;
return 0;
}
没有注意到您想要 post 中的连续内存!! 如果无论如何这里有用的话,这里有一些代码来制作 3Dtab(并擦除它):
int malloc3dfloatBIS(float ****array, int d1, int d2, int d3) {
if (!(*array = malloc(sizeof(array) * d3)))
return -1;
for (int i = 0; i < d2 ; ++i)
if (!((*array)[i] = malloc(sizeof(array) * d2))) {
while (i)
free ((*array)[i--]);
return -1;
}
for (int i = 0; i < d2 ; ++i)
for (int j = 0; j < d1 ; ++j){
if (!((*array)[i][j] = malloc(sizeof(****array) * d1))){
for (;i;--i){
while (j){
free ((*array)[i][--j]);
}
j = d1;
free ((*array)[i]);
}
return -1;
}
}
return 0;
}
void erase(float ****array, int d1, int d2, int d3) {
for (int i = d2;i ; --i){
int j = d1;
while (j)
free ((*array)[i -1][--j]);
free ((*array)[i - 1]);
}
free (*array);
}
我想到了一个类似于@tsanisl 发布的解决方案。我从来没有这样做过,所以我对如何让它工作有一些疑问,所以我开发了一个简单的程序来展示它:
$ cat ap.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define ARRAY_SSIZE(a) ((ptrdiff_t) ARRAY_SIZE(a))
int main(void)
{
int (*ap)[2][3][5];
int l = 0;
ap = malloc(sizeof(*ap));
printf("%zu\n", sizeof(*ap));
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(*ap); ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE((*ap)[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE((*ap)[0][0]); ++k) {
(*ap)[i][j][k] = l++;
}
}
}
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(*ap); ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE((*ap)[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE((*ap)[0][0]); ++k)
printf("%3i", (*ap)[i][j][k]);
putchar('\n');
}
putchar('\n');
}
}
$ ./a.out
120
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
25 26 27 28 29
我希望它有用:-)
我做了一些进一步的测试来检查是否没有未定义的行为,并检查我正在访问的地址是否连续,但我在这里删除它们以简化代码。
编辑:
我上面的解决方案与@tsanisl 的解决方案略有不同。以下是他的建议。使用您喜欢的那个。两者都很好。 这个更类似于你在函数中得到的,其中数组衰减到指向其第一个元素的指针。
$ cat ap.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define ARRAY_SSIZE(a) ((ptrdiff_t) ARRAY_SIZE(a))
int main(void)
{
int (*ap/*[2]*/)[3][5];
int l = 0;
ap = malloc(sizeof(*ap) * 2);
printf("%zu\n", sizeof(*ap) * 2);
for (ptrdiff_t i = 0; i < 2; ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE(ap[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE(ap[0][0]); ++k) {
ap[i][j][k] = l++;
}
}
}
for (ptrdiff_t i = 0; i < 2; ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE(ap[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE(ap[0][0]); ++k)
printf("%3i", ap[i][j][k]);
putchar('\n');
}
putchar('\n');
}
}
$ ./a.out
120
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
25 26 27 28 29
H.S。已经指出了你的错误。但其他人正确地建议只使用一个指针并避免预计算。然后你可以转到 VLA。我仍然喜欢 chux 版本,但为了获得正确的 malloc()
故障管理,您可以这样做:
#include <stdio.h>
#include <stdlib.h>
// Full out-of-memory handling included
int malloc3dfloat(float ****array, int q, int r, int s)
{
char *p = malloc((sizeof(float**) + (sizeof(float*) + sizeof(float) * s) * r) * q);
if (p == NULL) {
return -1;
}
float ***pq = (void*)(p);
float **pr = (void*)(p + sizeof(float**) * q);
float *ps = (void*)(p + (sizeof(float**) + sizeof(float*) * r) * q);
for (int qi = 0; qi < q; ++qi) {
pq[qi] = pr + qi*r;
for (int ri = 0; ri < r; ++ri) {
pq[qi][ri] = ps + (qi*r + ri)*s;
}
}
*array = pq;
return 0;
}
这很丑,我不得不承认。但是所有指针和值都作为一个 malloc 粘在一起,允许简单的释放和一次检查以验证是否有足够的内存。
性能方面我一无所知,但重新分配真的很容易(只需一个免费的):
int main(void)
{
float ***x;
int res = malloc3dfloat(&x, 3, 4, 2);
for (int q = 0; q < 3; ++q) {
for (int r = 0; r < 4; ++r) {
for (int s = 0; s < 2; ++s) {
x[q][r][s] = rand() % 10;
}
}
}
for (int q = 0; q < 3; ++q) {
for (int r = 0; r < 4; ++r) {
for (int s = 0; s < 2; ++s) {
printf("%f ", x[q][r][s]);
}
printf("\n");
}
printf("---\n");
}
free(x);
return 0;
}