我不知道在使用指针时何时必须使用 *,何时不用。带有十六进制的所有内容都是指针,对吗?数组的变量名带有它的十六进制内存位置。那为什么不是指针呢?
最后一件事-数组的名称不是指针;它不会在任何地方存储地址。当您定义一个数组时,它的布局或多或少类似于以下内容:
+---+
回复:| | arr[0] 递增地址
+---+ |
| | arr[1] |
+---+ |
... |
+---+ |
| | arr[n-1] V
+---+
没有为arr 与数组元素arr[0] 到arr[n-1] 分开的对象预留存储空间。 C 不会将任何元数据(例如长度或起始地址)存储为数组对象的一部分。
相反,有一条规则规定,如果数组表达式出现在您的代码中并且该表达式不是sizeof 或一元& 运算符的操作数,它将被转换( "decay") 指向一个指针表达式,指针表达式的值将是数组第一个元素的地址。
所以给定声明
T arr[N]; // for any type T
那么以下是正确的:
Expression Type Decays to Value
---------- ---- --------- -----
arr T [N] T * Address of first element
&arr T (*)[N] n/a Address of array (same value
as above
*arr T n/a Value of arr[0]
arr[i] T n/a Value of i'th element
&arr[i] T * n/a Address of i'th element
sizeof arr size_t Number of storage units (bytes)
taken up by arr
表达式arr、&arr和&arr[0]都产生相同的值(数组的第一个元素的地址与数组的地址),但它们的类型并不完全相同; arr 和 &arr[0] 具有 T * 类型,而 &arr 具有 T (*)[N] 类型(指向 N-T 的元素数组的指针)。
所有带有十六进制的都是指针,对吗?
十六进制只是二进制数据的一种特殊表示;它本身不是一种类型。并不是所有可以用十六进制写入或显示的东西都是指针。我可以将值 0xDEADBEEF 分配给任何 32 位整数类型;这不会使它成为一个指针。
指针的精确表示可能因架构而异;它甚至可以在同一架构上的不同指针类型之间变化。对于平面内存模型(如任何现代桌面架构),它将是一个简单的整数值。对于分段架构(如旧的 8086/DOS 时代),它可能是页面 # 和偏移量的一对值。
指针值 可能没有用于存储它的类型那么宽。例如,旧的摩托罗拉 68000 只有 24 条地址线,所以任何指针值都只有 24 位宽。然而,为了让生活更轻松,大多数编译器使用 32 位类型来表示指针,而没有使用高 8 位(2 的幂很方便)。
我不知道在使用指针时何时必须使用 *,何时不用。
很简单 - 当你想引用 pointed-to 实体时,使用*;当您想引用指针本身时,请不要使用它。
另一种看待方式——表达式*ptr等价于表达式var,所以任何时候你想引用@的contents 987654342@ 你会使用*ptr。
一个更具体的例子可能会有所帮助。假设如下:
void bar( T *p )
{
*p = new_value(); // write new value to *p
}
void foo( void )
{
T var;
bar( &var ); // write a new value to var
}
在上面的例子中,以下是正确的:
p == &var
*p == var
如果我给*p 写东西,我实际上是在更新var。如果我给p 写一些东西,我会将它设置为指向var 以外的东西。
上面的这段代码实际上是为什么指针首先存在的主要原因。在 C 中,所有的函数参数都是通过按值传递;也就是说,函数定义中的形参是与函数调用中的实参分开的对象。对形式参数的任何更新都不会反映在实际参数中。如果我们把代码改成如下:
void bar( T p )
{
p = new_value(); // write new value to p
}
void foo( void )
{
T var;
bar( var ); // var is not updated
}
p 的值已更改,但由于p 与var 是不同的内存对象,var 中的值保持不变。函数更新实际参数的唯一方法是通过指针。
所以,如果你想更新p 指向的东西,写信给*p。如果要设置p 指向不同的对象,请写信给p:
int x = 0, y = 1;
int *p = &x; // p initially points to x
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
*p = 3;
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
p = y; // set p to point to y
printf( "&y = %p, y = %d, p = %p, *p = %d\n", (void *) &y, y, (void *) p, *p );
此时您可能会问,“为什么我在int *p = &x 中使用星号而不在p = y 中使用星号?”在第一种情况下,我们声明 p 为指针并在同一操作中对其进行初始化,并且声明语法需要*。在这种情况下,我们写信给p,而不是*p。相当于写了
int *p;
p = &x;
还要注意,在声明中* 绑定到变量名,而不是类型说明符;它被解析为int (*p);。
C 声明基于表达式 的类型,而不是对象。如果p 是一个指向int 的指针,并且我们想要引用 pointed-to 值,我们使用* 操作符来取消引用它,如下所示:
x = *p;
表达式*p的类型是int,所以声明写成
int *p;