为啥我在 C 中的多维动态分配不起作用?
Posted
技术标签:
【中文标题】为啥我在 C 中的多维动态分配不起作用?【英文标题】:Why is my multi-dimensional dynamic allocation in C not working?为什么我在 C 中的多维动态分配不起作用? 【发布时间】:2011-03-21 06:30:24 【问题描述】:我一直试图找出我在 C 中分配和使用多维动态分配数组的问题。我非常感谢任何帮助。
我尝试了两种方法。第一个:
cdr = (double ***) malloc(NUM_REGIONS * sizeof(double **));
for(i=0; i<NUM_REGIONS; i++)
cdr[i] = (double **) malloc(numRatings * sizeof(double *));
for(j=0; j<numRatings; j++)
cdr[i][j] = (double *) malloc(remQuarters * sizeof(double));
第二个:
tempPtr1 = (double *) malloc(NUM_REGIONS * numRatings * remQuarters * sizeof(double) );
tempPtr2 = (double **) malloc (NUM_REGIONS * numRatings * sizeof(double *));
cdr = (double ***) malloc(NUM_REGIONS * sizeof(double **));
for(i=0; i< NUM_REGIONS; i++)
cdr[i] = tempPtr2 + i;
for(j=0; j < numRatings; j++) cdr[i][j] = tempPtr1 + i * NUM_REGIONS + j;
两者都不起作用。在这两种情况下,每个 cdr[i] 最终都指向同一个地方。我第一次进入“i”循环时,所有 cdr[i](即 cdr[0]、cdr[1]、cdr[2] 等)都设置为相同的值。随后的循环不会改变它们中的任何一个。
我怀疑运算符优先级有问题,或者我解引用错误,但我无法弄清楚。
谢谢。
更新
我整理了以下简化的代码,似乎可以正常工作。但是,虽然输出完全符合预期,但当我在调试器中单步执行时,我仍然会遇到同样的奇怪行为。我开始认为我的代码的根本问题可能在其他地方,而我刚刚被调试器的问题转移(或者可能只是因为我对输出的误解)。是否有已知原因导致 Visual Studio 中“cdr[0]”、“cdr[1]”等的手表无法显示我期望的内容?
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#define NUM_REGIONS 50
void printArray(double *inVec, int len)
int i;
for(i=0; i<len; i++) printf("%f\t",inVec[i]);
printf("\n");
int main(array<System::String ^> ^args)
int numRatings = 25, remQuarters = 100, i, j, k;
double ***cdr;
char dummy;
cdr = (double ***) malloc(NUM_REGIONS * sizeof(double **));
for(i=0; i<NUM_REGIONS; i++)
cdr[i] = (double **) malloc(numRatings * sizeof(double *));
for(j=0; j<numRatings; j++)
cdr[i][j] = (double *) malloc(remQuarters * sizeof(double));
for(i=0; i<NUM_REGIONS; i++)
for(j=0; j<numRatings; j++)
for(k=0; k<remQuarters; k++)
cdr[i][j][k] = 100*i + 10*j +k;
for(i=0; i<5; i++) printf("%f\t",cdr[1][1][i]);
printf("\n");
for(i=0; i<5; i++) printf("%f\t",cdr[3][1][i]);
printf("\n");
for(i=0; i<5; i++) printf("%f\t",cdr[1][3][i]);
printf("\n");
for(i=0; i<5; i++) printf("%f\t",cdr[i][i][i]);
printf("\n");
printArray(cdr[1][1], 5);
printArray(cdr[3][3], 5);
scanf("%c", &dummy);
return 0;
再次感谢所有反馈。
【问题讨论】:
我试过你的第一个 sn-p。它和我一起工作。而且 cdr[i] 每次都是一个新位置,没有任何问题。 我的猜测是:你的 numRatings 变量等于 0 或未初始化 @stacker, cdr 被声明为 double ***cdr;声明中还有一些其他变量,但这不重要,不是吗? @Ben,numRatings 等于 27。在调试器中显示良好。 @Mark 因为它被声明为***指针,所以编译器无法找出你的第一个索引的行有多大,因此 ssegiv 答案是要走的路。 您确定这不能正常工作吗?你看到了什么地址?你确定地址完全一样吗?您的第一种方法似乎是有效的,我的测试证实了这一点。 【参考方案1】:很久以前在大学时,我得出结论,应该用一维数组来模拟 C 中的多维数组。第一个需要分配一个足够大的缓冲区来容纳所有元素。对于将是ncolumns*nrows*sizeof(element)
的二维数组。然后通过将多维索引转换为一维索引来访问数组元素。对于二维数组,访问 A(i,j) 将转换为 bufA[i*ncolumns+j]
。
【讨论】:
这确实发生在我身上,可能就是我最终要走的路。我只是认为数组表示法更容易阅读和理解。但我想只有当它有效时才重要!【参考方案2】:问题在于您的取消引用。 cdr[i][j]
不会做你想做的事。当您分配cdr[i]
时,您将在该索引处放置一个指针。但是,cdr[i][j]
不会取消引用 cdr[i]
。它假定您有一个矩形内存块,并将适当的值添加到 cdr 以确定cdr[i][j]
的位置。您可能必须使用 *
s 手动解除引用。
【讨论】:
?!?我一直使用这种技术来制作参差不齐的数组。 它的行为完全符合预期。在这种情况下,cdr[i][j] != cdr[i*rowlen+j]
。在问题中,cdr
的类型为 double ***
。这使得cdr[i]
的类型为double **
,而cdr[i][j]
的类型为double *
。语法正确。【参考方案3】:
我很难弄清楚你到底遇到了什么问题。
我为一个多维双精度数组尝试了以下方法并且没有问题:
int i, j;
int rows = 5;
int columns = 10;
int z_axis = 5;
double ***cdr = malloc(rows * sizeof(double **));
for (i = 0; i < rows; i++)
cdr[i] = malloc(columns * sizeof(double *));
for (j = 0; j < columns; j++)
cdr[i][j] = malloc(z_axis * sizeof(double));
有关此问题的详细信息,请参阅 c-faq:http://c-faq.com/aryptr/dynmuldimary.html
【讨论】:
【参考方案4】:cdr
应该是什么?一个双精度的 3D 数组(这是我假设的,基于你的 sn-p)?指向双精度指针的二维数组?还是指向二维双精度数组的指针?
假设第一个:
#include <stdlib.h>
int main(void)
double ***cdr = malloc(sizeof *cdr * NUM_REGIONS);
if (cdr)
size_t i;
for (i = 0; i < NUM_REGIONS; i++)
cdr[i] = malloc(sizeof *cdr[i] * numRatings);
if (cdr[i])
cdr[i][j] = malloc(sizeof *cdr[i][j] * remQuarters);
return 0;
需要注意的几点:
-
不要转换
malloc()
的返回值。从 C89 开始,您不需要(void 指针被隐式转换为目标指针类型),如果您忘记包含 stdlib.h 或在范围内没有 malloc()
的原型,则强制转换将抑制有用的“分配的不兼容类型”诊断。
对正在分配的对象使用sizeof
运算符,而不是类型表达式。如果目标对象的类型发生变化,这可以保护您;我认为它也有助于提高可读性。
这应该有效;你应该有一个相当于
的双精度 3D 数组double cdr[NUM_REGIONS][numRatings][remQuarters];
【讨论】:
我可以看到更多的上下文会有所帮助。我不清楚 double 的 3D 数组与指向 double 的 2D 指针数组有何不同。我试图获得两者的特征。最终,我试图发送cdr[region][rating]
作为指向函数的双倍指针。该函数将double *cdr1
作为参数,然后将所有remquarters 值作为cdr1[i]
循环。那有意义吗?另外,感谢您提供的一般“良好的内务管理”说明。
是的,这是有道理的。通过简单地将 cdr 声明为 3D VLA(如果您有可用的 C99 编译器;如果没有,您将被分段分配卡住),您可能会省去一些麻烦。请记住,在大多数情况下,数组表达式的类型从“T 的 M 元素数组”“衰减”到“指向 T 的指针”。如果你将cdr
声明为一个3D数组,比如double cdr[X][Y][Z];
,那么表达式cdr[i][j]
的类型就是“Z-element array of double”,但是当你把它传递给一个函数时,它会“衰减”输入“双倍指针”。【参考方案5】:
事实证明,所编写的代码是有效的(尽管正如一些人指出的那样,它确实有改进风格的空间)。我将代码中的真正问题跟踪到一些对于缓冲区来说太大的文件输入(这对我来说是错误检查的一个教训)。
调试器给出了一些奇怪的输出,让我专注于这部分代码。我仍然不明白为什么我的调试器会在其他人没有的情况下这样做,但我会改天处理。
【讨论】:
以上是关于为啥我在 C 中的多维动态分配不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥是 Ctrl+.当我将它绑定到 Emacs 中的命令时不起作用?