2014-06-23 257 views
1

我在用于从设备检索数据的供应商API方面遇到问题。如在供应商的文档建议的电话会议的工作版本看起来像下面这样:cArray [] []指针阵列投射

int dataArray[15][20]; 
getData(15, 20, (int*) dataArray); 

的调用签名被描述为:

void getData(xSize, ySize, int*); 

我很感兴趣,有这个功能将数据复制到INTS的连续数组与动态大小,像下面这样:

int *flatDataArray = (int*) malloc(xSize * ySize * sizeof(int)); 

我有一个很难得到呼叫权限,以及内存设计缺陷是有些diffi崇拜调试:(

我想我的误解是围绕如何表示一个int数组,以及将它转换为(int *)时会发生什么。在这个例子中是int **类型的“dataArray”,还是其他的?如果是这样,你是否必须构造一个指向flatDataArray的指针数组才能使上述函数正常工作?

+0

指针可用于遍历1维数组,但指向指针的指针不能用于迭代2维数组,这仅仅是数组的数组。建议阅读:[comp.lang.c常见问题](http://www.c-faq.com/)的第6部分。 –

+0

@KeithThompson我相信,只要指针知道它指向一个*类型的n元素的数组,而不仅仅指向一个类型变量的指针。 – ThoAppelsin

+1

问题是什么?函数将指针加倍而不是指向双精度数组的指针。 – this

回答

2

由于演员阵容,第一行“有效”。

鉴于:

int dataArray[15][20]; 
getData(15, 20, (int*) dataArray); 

表达值类型dataArray独立是int (*)[20]。一个指向数组的指针20 int。这是有道理的,因为按照C标准,数组的表达式值是它的第一个元素的地址和所述相同的指针类型。那么,阵列中的第一个“元素”(dataArray就是int[20]),指针类型为int(*)[20]

也就是说,相同的规则适用于该数组数组中的第一个数组。总之,这将工作:

int dataArray[15][20]; 
getData(15, 20, dataArray[0]); 

就像dataArray是导致int (*)[20]类型的第一个元素(数组)的地址的表达式,即阵列中的第一阵列同样具有表达值,它是地址第一个元素,int,并且与该地址关联的类型为int *碰巧,这是阵列数组的第一个数组的第一个元素。在底层系统的线性内存背景下,它正在运行,它最终会解析到相同的地址(其中dataArray放置在内存中)。这是与该地址相关联的类型,取决于它如何设计,是不同的。不管类型如何,底层内存背景都是相同的:一个300 int的连续序列。下面的全部返回的地址将是相同的;只有不同的类型(并在注释中注明)

&dataArray   // int (*)[15][20] 
dataArray    // int (*)[20] 
dataArray[0]   // int * 
&dataArray[0][0]  // int * 

并且不,这些不是唯一的组合。我至少离开了一个。看看你是否可以找出缺少的东西。

不管怎么说,作为分配你在这里:

int *flatDataArray = malloc(xSize * ySize * sizeof(int)); 

的作品,因为你只是建立一个xSize by ySize线性背景。因为这是C,以下也将工作,利用VLA(可变长度数组)的语言的特征:

int (*arr2D)[ySize] = malloc(xSize * sizeof(*arr2D)); 

假设xSize的数量,并且ySize的数量你寻求(我看起来错了一半的时间,这就是为什么我更喜欢monikers“row”和“col”)。上面的配置说“分配给我空间xSizeint[ySize]件事”。在代码的好处是,你可以解决这个问题,就像你阵列的二维数组(这是它到底是什么):

arr2d[i][j] = value; 

0..(xsize-1)0..(ysize-1)任何ij,就像你/可以像你正常宣布一样。这个(VLA)是C做的一件事情,C++没有做到这一点(但是再次说明,C++中有很多容器可以用一种不同的方式解决这个问题,所以它不是一个真正公平的比较)。

祝你好运。

+0

这个答案真棒谢谢! – meawoppl

1

对于一个2维数组声明如下:

double dataArray[15][20]; 

平整出来的版本,简直是以下几点:

dataArray[0]; 

如果你是存储第一的这个地址双指针(地址变量)为双精度

double * flatDataArray = dataArray[0]; 

下面的循环,例如,由于访问每一个元件以邻接方式,这样的事实,他们已在多维邻接的并且从未:

for (int i = 0; i < 15 * 20; i++) { 
    dataArray[0][i]; // alternatively: flatDataArray[i]; 

作为每编辑:更改所有doubleint,或任何你想要的类型。

说,这是的char S,这里怎么会变成什么样子,什么dataArray*dataArray**dataArray将类似于:

char0 char1 ... char14 char15 char16 ... char29 ... char299 
// >        dataArray       < 
// >  *dataArray  < >       <    
// > < > < 
// ^the **dataArray 

dataArray可能得不到解除引用更多,两次最大。通过使用**dataArray的地址,您的手上就会有*dataArray。类似于*dataArray。不适用于dataArray,在这种情况下,您宁可简单地使用&dataArray

&dataArray每一个,dataArray*dataArray将具有相同的值,这是char0的地址,或跨越从char0char14阵列,或阵列的跨越从char0-char14char285-char299阵列。

**dataArray将具有char0的值。

其他三种有什么区别?那么,他们指向不同的类型,因此增加他们会有不同的解释。怎么样,当你增加一个整数的指针,你提前4个字节,而不是1

如果你碰巧由1递增&dataArray,像&dataArray + 1,你会提前300个字节(300 * sizeof(char))这是类似。如果您恰好将dataArray加1(这是*dataArray的地址),则会提前15个字节,依此类推。

如果您恰好将*dataArray增加1,即**dataArray,char0的地址,则会提前1个字节。现在,这里是:

  • *dataArraydataArray[0]
  • 递增1是dataArray[0] + 1
  • 那提领将*(dataArray[0] + 1)
  • 简写是dataArray[0][1]
  • 说我们是更增加它,总共15次
  • dataArray[0][15]

似乎是非法的,不是吗?好吧,事实并非如此,因为这部分内存仍在为你分配的部分。事实上,你可以远至dataArray[0][299]。它只意味着提前299个字节,并访问该位置,并且该位置都是您的。

疯了,不是吗?我写了这么多关于它的更疯狂。我甚至不确定这是否会回答你的问题......我想因为getData(15, 20, dataArray[0]);getData(15, 20, *dataArray);这样的电话会更合理,但我怀疑那里的类型转换会失败。

我希望这至少对某人有意义。

+0

非常感谢彻底。在这个答案和评论之间,我想我有我需要将这一切全部整理在一起。重要的见解是,根据供应商如何实现该功能,传递的指针可以具有两种语义之一。我相信,因为在编译时API的大小不为人所知,所以在指针运算下必须有一些手册。 – meawoppl

0

此代码是罚款:

int dataArray[15][20]; 
getData(15, 20, (int*) dataArray); 

和它的作品,因为你是个指针为int观看整个对象dataArray;并且由于dataArray确实包含整数,所以没有任何别名违规。

这将是未定义的行为,编写getData(15, 20, dataArray[0]);,因为在这种情况下,您使用的指针只是20个int的数组,这是dataArray的第一个元素,所以您不允许溢出这20个int。 (编号:C99 6.5。6#8)

我对具有这种功能将数据复制到双打的邻接阵列与动态大小

intdouble是不同的,所以可以不通过任何种类的阵列的double到这个函数(正如你已经描述过函数一样;如果这个函数实际上需要void *然后根据一些以前的函数调用输出数据,那将是不同的)。除非API还包含一个指向double的函数,否则您必须检索int,然后将它们转换为double。例如,

int array1[xSize][ySize]; 
getData((int *)int_array); 

double array2[xSize][ySize]; 
for (size_t ii = 0; ii < xSize; ++ii) 
    for (size_t jj = 0; jj < ySize; ++jj) 
     array2[xSize][ySize] = array1[xSize][ySize]; 

最后一行执行值变换从intdouble

在C数组中可以有这样的运行时间尺寸。 (实际上在2011年,这被改为可选功能,以前它是标准的)。如果您使用的编译器不再支持这种类型的数组,您可以使用malloc

如果两个维度在编译时都不知道,那么你必须malloc一维数组,然后找出偏移量;例如

int *array1 = malloc(xSize * ySize * sizeof *array1); 
getData(array1); 

double *array2 = malloc(xSize * ySize * sizeof *array2); 
for (size_t ii = 0; ii < xSize * ySize; ++ii) 
    array2[ii] = array1[ii]; 

// what was previously array1[4][6] 
array2[4 * ySize + 6]; 

NB。 void getData(xSize, ySize, int*);不是有效的呼叫签名。呼叫签名将具有数据类型而不是变量名称。您可以在包含的头文件中找到函数声明来访问此API。