理解不同C指针赋值之间的差异

理解不同C指针赋值之间的差异,c,pointers,variable-assignment,C,Pointers,Variable Assignment,我试图理解两种指针赋值之间的区别 uint8_t pInputByte[byteCount]; uint8_t* pNextInputBytes = pInputByte; 在本例中,由于pInputByte[byteCount]是一个数组,第二行是否将该数组的地址写入pnputbyte?为了澄清只调用数组变量名而不返回其地址 我的另一个问题是,如果我们按照以下方式编写,操作会有什么不同 uint8_t pInputByte[byteCount]; uint8_t* pNextInputByt

我试图理解两种指针赋值之间的区别

uint8_t pInputByte[byteCount];
uint8_t* pNextInputBytes = pInputByte;
在本例中,由于pInputByte[byteCount]是一个数组,第二行是否将该数组的地址写入pnputbyte?为了澄清只调用数组变量名而不返回其地址

我的另一个问题是,如果我们按照以下方式编写,操作会有什么不同

uint8_t pInputByte[byteCount];
uint8_t* pNextInputBytes;
pNextInputBytes = &pInputByte;

表达式中使用的数组指示符(很少有例外)转换为指向其第一个元素的指针

来自C标准(6.3.2.1左值、数组和函数指示符)

3除非它是sizeof运算符或一元数的操作数& 运算符,或是用于初始化数组的字符串文字 类型为“”的数组“”的表达式转换为 类型为“指向类型的指针”且指向初始值的表达式 数组对象的元素,并且不是左值。如果数组对象 已注册存储类,行为未定义

因此,在本宣言中

uint8_t* pNextInputBytes = pInputByte;
用作初始值设定项的数组被转换为指向其第一个元素的指针,其类型为
int*
。此值被分配给声明的指针

在这份声明中

pNextInputBytes = &pInputByte;
这里应用了一元运算符&用于数组类型的对象。因此表达式
&pInputByte
的类型是
uinmt8\u t(*)[byteCount]
。但在赋值的左侧有一个类型为
uint8\u t*
的对象。没有从一种类型到另一种类型的隐式转换。因此编译器将发出一个错误

相反,你可以写作

uint8_t pInputByte[byteCount];
uint8_t (*pNextInputBytes )[byteCount];
pNextInputBytes = &pInputByte;
为了更清楚,请为数组类型引入typedef名称

typedef uint8_t T[byteCount];
然后可以按照以下方式声明数组和指向数组的指针

T pInputByte;
T *pNextInputBytes = &pInputByte;
现在,如果要用指针声明中的typedef名称T替换定义的类型,那么您将得到

uint8_t ( *pNextInputBytes )[byteCount] = &pInputByte;
要查看两个指针之间的差异,其中一个指针的类型为
uint8\u t*
,另一个指针的类型为
uint8\u t(*)[字节数]
,请编写以下演示程序

#include <stdio.h>
#include <stdint.h>

int main(void) 
{
    size_t byteCount = 10;
    uint8_t pInputByte[byteCount];
    uint8_t *pNextInputBytes1 = pInputByte;
    uint8_t ( *pNextInputBytes2 )[byteCount] = &pInputByte;

    printf( "sizeof( *pNextInputBytes1 ) = %zu\n", sizeof( *pNextInputBytes1 ) );
    printf( "sizeof( *pNextInputBytes2 ) = %zu\n", sizeof( *pNextInputBytes2 ) );

    return 0;
}
请注意,数组名称中使用的前缀
p
会使代码的读取器感到困惑。

1。
在这种情况下,由于
pInputByte[byteCount]
是一个数组,第二行是否将该数组的地址写入
pnputbyte

不是数组的地址,而是数组第一个元素的地址。但基本上你是对的

为了澄清只调用数组变量名而不返回其地址

当数组未与索引元素
[i]
一起使用时,该数组将衰减为指向第一个元素的指针,并返回该第一个元素的地址,除非用户在注释中提到,当它是索引元素时。引用自ISO/IEC 9899:2011(C11)


2. 我的另一个问题是,如果我们按照以下方式编写,操作会有什么不同:

第三条线是问题。您需要省略符号和运算符
&
,以便在没有任何警告的情况下正确编译它:

pNextInputBytes = pInputByte;
但是,如果你把打字错误混在一起,两种代码是等价的,是的


顺便说一下,当
p
代表“指针”(我只能推测)时,您不应该在
pInputByte
前面加上
p

  • uint8\u t pInputByte[byteCount];
    uint8_t*pnputbytes=pInputByte

  • 在本例中,我们分配数组的地址,该地址指向数组中的第一个元素。例如,当您尝试访问数组的第一个元素时,您可以说*PNEXEIPUTBYTES,对于下一个元素*(PNEXEIPUTBYTES+1)-+1会将您带到数组中第二个元素的地址

  • uint8\u t pInputByte[byteCount];
    uint8_t*pn字节;
    pnputbytes=&pInputByte


  • 在本例中,我们获取数组的地址,但它指向整个数组。i、 e.如果pInputByte[5],则&pInputByte将指向5个元素的整个数组。因此,当您尝试像(pndeputbytes+1)那样递增时,地址实际上会跳5个地址。这在多维数组中很有用。假设双数组[5][4]是二维数组。这里,“array”是指向4 int数组的指针,但是“&array”是指向5行数组的指针,4 int数组“

    第二个应该得到一个编译器警告,因为
    uint8\u t*
    uint8\u t(*)[]
    非常不同。后者是指向数组的指针,而不是指向值的指针。此外,数组声明为您分配内存,裸指针需要分配或分配现有值(这是您在第一个示例中正确执行的操作)。“不与索引元素一起使用的数组
    [i]
    衰减为指向第一个元素的指针。它返回第一个元素的地址。“--这是不正确的。该标准并没有说当一个数组被索引时没有数组衰减,而是说@exnihilo感谢您的提示。我已经把它编辑好了。
    uint8_t pInputByte[byteCount];
    uint8_t* pNextInputBytes = pInputByte;
    
    uint8_t pInputByte[byteCount];
    uint8_t* pNextInputBytes;
    pNextInputBytes = &pInputByte;
    
    pNextInputBytes = pInputByte;