[英]Still don't understand pointers to an array of numbers in C
如标题所示,我很稠密。 我试图在堆上分配空间以存储uint64_t数组的值。 (它可以是任何一种数字,但这就是我用来将值与指针区分开的数字。) 在这里,我得到了我的一个问题的答案。 我想我明白。 我想做的是获取一个指向数字数组的指针,然后在运行时将值分配给该数组。
编辑:在美国东部标准时间12:15 pm更新。 为了节省人们阅读的时间,我在下面保留了原始问题,并根据评论和答案将问题缩小到以下内容。 这是我的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上的演员表会做什么? 另外,Ingarr3的值似乎是由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
首先,我从这个答案中了解到我不应该将指针分配给malloc
和calloc
,但是这给了我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
。 但是我要做的是在运行时为LngArr1
和LngArr2
3个不同元素分配不同的值(而不是通过在变量的定义中分配值)。 我不知道该怎么做,因为我不了解将值分配给数组指针的正确方法。
不太重要的问题是,为什么指向uint64_t( PtrLngArr
)的指针的3个元素指向相同的地址,以及calloc
上不同的块数为何会导致结果值有所不同。 为什么在一种情况下为垃圾,在另一种情况下为0。
我希望时间不会太长,但是我想表明我对此感到困惑,以及为什么结果令我感到惊讶。 谁能更改测试代码以显示如何为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 identifier
在分配LgnArr3[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]);
我仍然不了解愈伤组织的角色,但我可以在闲暇时学习。 所需的输出是:
&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
我几乎满意。 恐怕还有更多问题。 foo可以容纳多少个元素? 我可以将#define NBRPTR
定义为任意值,而不必更改foo
的定义吗? 另外,为什么* foo和3个foo指针都等于0? 我确定我总共只分配了24个字节,但是我只是想知道指针没有显示出来。
最后,我更改了最后一个打印语句以执行此操作:
printf("foos%d=%llu ", s, foo[s]);
仅用于打印正在打印的元素。 结果的最后一行变为:
foos0=0 foos1=4294967296 foos2=8589934592
我没有弥补! 在整个方案中,它并没有太大的区别。 我主要遇到的问题是前两个。 但是,这个新结果有什么理由吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.