何时在指针赋值中使用 *?

use*_*013 -1 c memory arrays variables pointers

因为我在学习 CI 时经常看到指针。

我知道一个指针保存了内存中不同位置的十六进制值。所以指针就是例如:0x7fff5fbff85c

每个指针也是不同的类型。

int var = 10;
int *ptr = &var;
Run Code Online (Sandbox Code Playgroud)

这里的ptr指向var的位置。要获得 var 的值,我必须使用*ptr. 喜欢

printf("Var = %d", *ptr);
Run Code Online (Sandbox Code Playgroud)

将打印 `Var = 10;

但是,如果我对指针进行非内联声明,例如:

int var = 10;
int *ptr;
ptr = &var;
Run Code Online (Sandbox Code Playgroud)

*当我实际将内存地址分配给指针时,我不必在第三行中使用。但是当我得到一个带指针的函数时:

int var = 10;
void assignPointer(int *ptr) {
*ptr = 10;
}
Run Code Online (Sandbox Code Playgroud)

等一下!在我写这篇文章时,我意识到指针有两种不同的分配:

*ptr = 10;
Run Code Online (Sandbox Code Playgroud)

ptr = &var;
Run Code Online (Sandbox Code Playgroud)

有什么不同?在第一种情况下,我是否首先取消引用指针,将 10 分配给其持有的位置?在第二种情况下,我将实际位置分配给指针。

我有点困惑何时使用 * 何时不使用赋值。

如果我正在处理数组,为什么我需要指针呢?

int array[];
Run Code Online (Sandbox Code Playgroud)

这里的“array”已经保存了十六进制内存位置。这不使它成为一个指针吗?所以如果我想为数组分配一些东西,我不会写:

*array = [10, 2];
Run Code Online (Sandbox Code Playgroud)

首先我取消引用,然后我分配。

我迷路了 :(

编辑:也许有点不清楚。我不知道当你使用指针时什么时候必须使用 * 什么时候不用。携带十六进制的所有内容都是指针,对吗?数组的变量名携带它的十六进制内存位置。那么为什么它不是一个指针呢?

EDIT2:谢谢你们帮了我很多!

Joh*_*ode 5

我不知道当你使用指针时什么时候必须使用 * 什么时候不用。携带十六进制的所有内容都是指针,对吗?数组的变量名携带它的十六进制内存位置。那么为什么它不是一个指针呢?

最后一件事 - 数组的名称不是指针;它不会在任何地方存储地址。当你定义一个数组时,它的布局或多或少如下:

         +---+                
    阿尔: | | arr[0] 增加地址
         +---+ |
         | | arr[1] |
         +---+ |
          ... |
         +---+ |
         | | arr[n-1] V
         +---+

没有存储的对象预留arr从数组元素中分离arr[0]通过arr[n-1]。C 不存储任何元数据,例如长度或起始地址作为数组对象的一部分。

相反,有一条规则表示如果数组表达式出现在您的代码中并且该表达式不是sizeof或 一元运算&符的操作数,它将被转换(“衰减”)为指针表达式,并且指针表达式的值将是数组第一个元素的地址。

所以鉴于声明

T arr[N]; // for any type T
Run Code Online (Sandbox Code Playgroud)

那么以下是正确的:

         +---+                
    arr: |   | arr[0]        Increasing address
         +---+                       |
         |   | arr[1]                |
         +---+                       |
          ...                        |
         +---+                       |
         |   | arr[n-1]              V
         +---+

表达式 arr&arr以及&arr[0]所有产率相同的(所述阵列的所述第一元素的地址是相同的数组的地址),但它们的类型都不尽相同; arr并且&arr[0]有类型T *,而&arr有类型T (*)[N](指向N元素数组的指针T)。

携带十六进制的所有内容都是指针,对吗?

十六进制只是二进制数据的一种特殊表示;它本身不是一种类型。并不是所有可以用十六进制写入或显示的东西都是指针。我可以将值分配0xDEADBEEF给任何 32 位整数类型;这并没有使它成为一个指针。

指针的确切表示可能因架构而异;它甚至可以在同一架构上的不同指针类型之间变化。对于平面内存模型(如任何现代桌面架构),它将是一个简单的整数值。对于分段架构(如旧的 8086/DOS 时代),它可以是页 # 和偏移量的一对值。

指针可能没有用于存储它的类型那么宽。例如,旧的摩托罗拉 68000 只有 24 条地址线,因此任何指针值都只有 24 位宽。然而,为了让生活更轻松,大多数编译器使用 32 位类型来表示指针,不使用高 8 位(2 的幂很方便)。

我不知道当你使用指针时什么时候必须使用 * 什么时候不用。

很简单——当你想引用指向的实体时,使用*; 当您想引用指针本身时,请将其关闭。

另一种看待它的方式——表达式 *ptr等价于表达式var,所以任何时候你想引用你的内容var都可以使用*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
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,以下是正确的:

 p == &var
*p == var
Run Code Online (Sandbox Code Playgroud)

如果我写一些东西*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
}
Run Code Online (Sandbox Code Playgroud)

的值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 );
Run Code Online (Sandbox Code Playgroud)

此时您可能会问,“为什么我使用星号 inint *p = &x而不是 in p = y?” 在第一种情况下,我们将声明 p为指针并在同一操作中对其进行初始化,并且*声明语法需要 。在这种情况下,我们写的是p,而不是*p。这将等同于写作

int *p;
p = &x;
Run Code Online (Sandbox Code Playgroud)

还要注意,在声明中,*绑定到变量名,而不是类型说明符;它被解析为int (*p);.

C 声明基于表达式的类型,而不是对象。如果p是指向 an 的指针int,并且我们想要引用指向的值,我们使用*运算符来取消引用它,如下所示:

x = *p;
Run Code Online (Sandbox Code Playgroud)

表达式 的类型*pint,所以声明写成

int *p;
Run Code Online (Sandbox Code Playgroud)