仍然不明白指向C中数组的数组的指针

正如标题所说,我很密集。 我试图在堆上分配空间来存储uint64_t数组的值。 (它可以是任何types的数字,但这是我用来区分价值观和指针)我在这里得到了我的一个问题的答案。 我想我明白。 我想要做的是获取一个指向数组数组的指针,然后在运行时为数组赋值。

编辑:美国东部时间下午12:15更新。 为了节省读者,我在下面留下了原来的问题,并根据评论和回答将问题缩小到以下内容。 这是我的C代码:

#include "stdafx.h" #include <stdlib.h> #include <stdint.h> #define NBRPTR 3 int main() { uint64_t (*LngArr3)[NBRPTR]; // pointer to array of 3 uint64_t uint64_t s; // subscript // WHen the next line of code is not commented, I get the following message: // Error C2440 '=': cannot convert from 'uint64_t *' to 'uint64_t (*)[3]' // LngArr3 = (uint64_t *)calloc(NBRPTR, sizeof(LngArr3[0])); LngArr3 = (uint64_t(*)[NBRPTR])calloc(NBRPTR, sizeof(*LngArr3)); // this compiles fine printf("&lngarr3=%p\n", &LngArr3); printf("LngArr3 =%p\n", LngArr3); printf("*LngArr3=%llu\n", *LngArr3); for (s = 0; s < NBRPTR; s++) { // The following line causes: Error C3863 array type 'uint64_t [3]' is not assignable // LngArr3[s] = s; *LngArr3[s] = s; printf("lngarr3s=%llu ", LngArr3[s]); } putchar('\n'); return 0; } 

我的输出如下:

 &lngarr3=002BFE88 Lngarr3 =0042E8C0 *LngArr3=4384960 lngarr3s=4384960 lngarr3s=4384984 lngarr3s=4385008 

我有下面的问题:我是新的,真的不明白:在calloc演员做什么? 此外,lngarr3的值似乎是由地址24分隔的地址,而不是像我所希望的数字0,1,2。 如何在运行时将值分配给LngArr3数组的3个元素? 与我所告诉的相反,如果赋值是(*LngArr3)[s] = s;那么它没有任何区别(*LngArr3)[s] = s; 而不是以上。 我已经尝试了这两种方法,唯一的区别是生成的地址。

我正在运行VS 2015社区版; 以x86模式编译。

================================================== =========================

为了历史的目的,我已经把原来的问题留下如下。 我的Visual Studio C代码如下:

 #include "stdafx.h" #include <stdlib.h> #include <stdint.h> #define NBRPTR 3 #define NBRSAVPTR 2 int main() { uint64_t (* LngArr1)[NBRPTR]; // pointer to array of 3 uint64_t uint64_t (* LngArr2)[NBRPTR]; // pointer to array of 3 uint64_t uint64_t * (SavPtrArr[NBRSAVPTR]); // array of 2 pointers, hopefully pointing to above uint64_t * PtrLngArr[NBRPTR]; // array of 3 pointers to uint64_t uint64_t s; // subscript (uint64_t *) SavPtrArr[0] = (uint64_t *) malloc(NBRPTR * sizeof(LngArr1[0])); printf("&savptrarr0=%p\n", &SavPtrArr[0]); printf("savptrarr0 =%p\n", SavPtrArr[0]); printf("*savptrarr0=%llu\n", *SavPtrArr[0]); for (s = 0; s < NBRPTR; s++) { // get compile time error: "uninitialized local variable 'LngArr1' used" on next 2 lines // *LngArr1[s] = s; // printf("%llu ", LngArr1[s]); // get compile time warning: "'printf': %u in format string conflicts with // argument 1 of type 'unint64_t' *" on above line // is it trying to print an address instead of a value? } putchar('\n'); (uint64_t *) SavPtrArr[1] = (uint64_t *) calloc(NBRPTR, sizeof(LngArr2[0])); printf("&savptrarr1=%p\n", &SavPtrArr[1]); printf("savptrarr1 =%p\n", SavPtrArr[1]); printf("*savptrarr1=%llu\n", *SavPtrArr[1]); for (s = 0; s < NBRPTR; s++) { // get compile time error: "uninitialized local variable 'LngArr2' used" on next 2 lines // *LngArr2[s] = s; // printf("%llu ", *LngArr2[s]); } putchar('\n'); for (s = 0; s < NBRSAVPTR; s++) free(SavPtrArr[s]); putchar('\n'); putchar('\n'); for (s = 0; s < NBRPTR; s++) { // the next line gives *PtrLinArr[s] values of the same 20 digits of garbage numbers (uint64_t *)PtrLngArr[s] = (uint64_t *)calloc(1, sizeof(PtrLngArr[0])); // the next line gives all three *PtrLinArr[s] values of 0 // (uint64_t *)PtrLngArr[s] = (uint64_t *)calloc(NBRPTR, sizeof(PtrLngArr[0])); printf("&ptrlngarrs=%p\n", &PtrLngArr[s]); printf("ptrlngarrs =%p\n", PtrLngArr[s]); printf("*ptrlngarrs=%llu\n", *PtrLngArr[s]); putchar('\n'); free(PtrLngArr[s]); } return 0; } 

我的结果如下:

 &savptrarr0=003BF6EC savptrarr0 =004EE8B0 *savptrarr0=14829735431805717965 &savptrarr1=003BF6F0 savptrarr1 =004F0C50 *savptrarr1=0 &ptrlngarrs=003BF6D8 ptrlgnarrs =004EE8B0 *ptrlgnarrs=18302063723772116992 &ptrlngarrs=003BF6DC ptrlgnarrs =004EE8B0 *ptrlgnarrs=18302063723772116992 &ptrlngarrs=003BF6E0 ptrlgnarrs =004EE8B0 *ptrlgnarrs=18302063723772116992 

首先,我从这个答案了解到,我不应该为malloccalloc投下指针,但是这会给我C2440 '=': cannot convert from 'void *' to 'uint64_t *'的编译时错误C2440 '=': cannot convert from 'void *' to 'uint64_t *' 。 我不知道这是特定于Windows还是Visual Studio。

无论如何,我几乎了解结果。 SavPtrArr包含2个指向不同地址的指针。 元素0的值是垃圾,元素1是0,因为我使用calloc而不是malloc 。 但是我想要做的是在运行时为LngArr1LngArr2的不同的3个元素分配不同的值(而不是在variables的定义中赋值)。 我不知道如何做到这一点,因为我不明白正确的方式来分配一个指向数组的指针的值。

不太重要的问题是为什么指向uint64_t( PtrLngArr )的3个元素指向相同的地址,以及为什么calloc上不同数量的块会影响结果的值。 为什么垃圾在一个案件和0在另一个案件。

我希望这个时间不会太长,但是我想performance出我对此的困惑,为什么结果让我感到惊讶。 任何人都可以更改testing代码,以显示如何分配值的3元素数组? 或者改变它来更好地解释这个东西是如何工作的。 谢谢。

编辑:我也尝试添加下面的行,但它甚至不会编译:

 uint64_t (*LngArr3)[NBRPTR]; // pointer to array of 3 uint64_t (uint64_t *)LngArr3 = (uint64_t *)calloc(NBRPTR, sizeof(LngArr3[0])); printf("&lngarr3=%p\n", &LngArr3); printf("LngArr3 =%p\n", LngArr3); printf("*LngArr3=%llu\n", *LngArr3); for (s = 0; s < NBRPTR; s++) { LgnArr3[s] = s; printf("lngarr3s=%llu", LngArr3[s]); } putchar('\n'); 

我得到了C2106 '=': left operand must be l-value calloc上的C2106 '=': left operand must be l-value ,并以某种方式得到了C2065 'LgnArr3': undeclared identifierLgnArr3[s]值赋值时C2065 'LgnArr3': undeclared identifier

首先,我从这个答案理解,我不应该为malloc和calloc投下指针

这是C的,你必须铸造一个C + +编译器,这就是Visual Studio默认(不知道这一点,请有人纠正我,如果我错了)。

不知道如何做到这一点,因为我不明白正确的方法来分配一个指向数组的指针的值。

对于LngArr1和2,你必须分配实际的int数组,我认为它是缺少的:

 LngArr2 = (uint64_t *) malloc(NBRPTR * sizeof(uint64_t)); 

然后写入int:

 (*LngArr2)[s] = s; 

注意最后一个数组,它是一个指向int的指针数组,所以对于每个指针你必须分配一个int:

 PtrLngArr[s] = (uint64_t *)calloc(1, sizeof(uint64_t)); 

相反,在你的代码中,你分配的指针的大小可能小于uint64_t的大小:

 (uint64_t *)PtrLngArr[s] = (uint64_t *)calloc(NBRPTR, sizeof(PtrLngArr[0])); 

什么是(uint64_t *)…在前面?

从输出来看,你正在编译和运行一个32位的Windows程序。 PtrLngArr[s]的类型是uint64_t * ,所以sizeof(PtrLngArr[0])将是4 (因为在这个程序中所有的指针都是大小4)。 所以PtrLngArr[s]指向一个4字节长的内存区域,通过calloc分配并初始化为全零。

当您打印*PtrLngArr[s] ,会得到PtrLngArr[s]指向的uint64_t值。 但是, sizeof(uint64_t)8 ,但指向的对象只有4个字节长。 这是未定义的行为。

如果相反,你已经设置了PtrLngArr[s] = calloc(1, sizeof(*PtrLngArr[0])) ,你将分配8个字节的内存初始化为全零, *PtrLngArr[s]的值为0

主要是由于Ian Abbott的帮助,在修订后的问题开头的代码与printf的以下更改一起工作。

printf("lngarr3s=%llu ", LngArr3[s]); 需要更改为printf("lngarr3s=%llu ", *LngArr3[s]); 我还是不明白calloc上的演员,但我可以在我的闲暇时间学习。 期望的输出是:

 &lngarr3=0043FCA0 LngArr3 =0055E8C0 *LngArr3=5630144 lngarr3s=0 lngarr3s=1 lngarr3s=2 

谢谢大家。

感谢Ian Abbott和Ilya。 很多意见,但你们两个几乎所有的意见。 一个新的尝试:

 #include "stdafx.h" #include <stdlib.h> #include <stdint.h> #define NBRPTR 3 int main() { uint64_t * foo; uint64_t s; // subscript foo = calloc(NBRPTR, sizeof(foo[0])); // this compiles fine as C code printf("sizeof(foo[0])=%zd\n", sizeof(foo[0])); printf("&foo=%p\n", &foo); printf("foo =%p\n", foo); printf("*foo=%llu\n", *foo); for (s = 0; s < NBRPTR; s++) printf("foos%d ptr=%p ", s, foo[s]); putchar('\n'); for (s = 0; s < NBRPTR; s++) { foo[s] = s; printf("foos=%llu ", foo[s]); } putchar('\n'); return 0; } 

新的结果:

 sizeof(foo[0])=8 &foo=0022F920 foo =0041E8C0 *foo=0 foos0 ptr=00000000 foos1 ptr=00000000 foos2 ptr=00000000 foos=0 foos=1 foos=2 

我几乎满意。 还有更多的问题,我害怕。 可以拥有多少元素? 我能否将#define NBRPTR定义为任意值,而不必改变foo的定义? 另外,为什么* foo和3 foo指针都等于0? 我确定我只分配了24个字节,但是我只是想知道没有出现的指针。

最后我改变了最后一个打印语句来做到这一点:

 printf("foos%d=%llu ", s, foo[s]); 

只是为了打印正在打印的元素。 结果的最后一行变成:

 foos0=0 foos1=4294967296 foos2=8589934592 

我没做这个! 整个事情的方案没有太大的差别。 我的主要问题是前两个。 但是这个新结果有什么理由吗?