繁体   English   中英

仍然不了解C中数字数组的指针

[英]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

首先,我从这个答案中了解到我不应该将指针分配给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个不同元素分配不同的值(而不是通过在变量的定义中分配值)。 我不知道该怎么做,因为我不了解将值分配给数组指针的正确方法。

不太重要的问题是,为什么指向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-valuecallocC2106 '=': 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM