【问题标题】:Is this C code wrong?这个C代码错了吗?
【发布时间】:2009-12-13 12:59:56
【问题描述】:

我知道指针包含变量的地址,例如:

int c = 5;
int *p;  
p = &c;
printf("%d",*p); // Outputs 5.

但是如果我想向函数发送地址怎么办:

void function (int *p)
{
  p++;
}
int c;
function (&c);

当函数被调用时,&c 的值被赋值给int *p。我猜确切的指令是:*p = &c;,但我不明白这是什么意思。

【问题讨论】:

    标签: c


    【解决方案1】:

    我更喜欢写int* p = &c;,也就是说,一个指向int类型的指针被分配了c的地址。

    正如您所注意到的,指针表示法可能会令人困惑,因为这两者是等价的:

    int *p = &c;
    

    int *p;
    p = &c;
    

    希望这会有所帮助!

    编辑:混淆是因为* 既用作取消引用运算符,又用于声明指针。所以当p 包含c 的地址时,*p 解引用指针并返回c 的值。但是当你说int *p = &c; 时,* 是在说“p 是一个指向 int 的指针”,但没有做任何解除引用。

    【讨论】:

      【解决方案2】:

      *p = &c; 表示:

      获取内存中c 的地址,该地址在compile-time 链接时确定(感谢 Mikeage),例如 0x1234举个例子。指向 int 类型的指针,即 *p 被分配给 0x1234,这对我来说听起来不对,我认为你应该这样做,p = &c 然后*p 将具有值指向 地址为c。因此*p 将具有分配给c 的值(这称为取消引用 - 通过将* 放在指针变量之前,您可以获得该值)。

      在你的函数中,你试图增加 p 所指向的值。

      无效函数 (int *p) { *p++; } // 会这样调用 诠释 c = 5; 函数(&c); // 现在 c 将有 6!

      关键是你要通过引用传递,这就是参数&c 所做的。 如果你省略这样的引用传递:

      无效函数(int p) { p++; } // 并像这样调用它 诠释 c = 5; 功能(c); // c 仍然是 5

      现在c 仍为 5,但在函数本身内 c 为 6,但不会传回副本,因为它在函数本身的本地堆栈中递增。

      【讨论】:

      • 为了迂腐,它只是在编译时部分确定;根据结果​​对象的操作系统和/或共享库[我知道这不是一个短语],它可能是可重定位的。但是你仍然会因为为提问者使用正确的详细程度而获得 +1(我当然没有......)
      • @Mikeage:谢谢 :) 那么,在编译时发生在链接之前吗? ;) 你在那儿……也许这个词应该是“在链接时”而不是编译时……感谢您指出! :)
      • 实际上,在加载时;有些情况下它可以在运行时重新定位
      • @Mikeage:谢谢......我打算尽可能简单地解释,而不是迂腐......实际上 - 我从来没有想过......呃! :)
      【解决方案3】:

      我无法真正理解您的问题,但 function 对我来说似乎是错误,而您的意思可能是,

      ++(*p)
      

      否则就是无操作。

      【讨论】:

      • 严格来说,该函数中的p++ 会调用未定义的行为(因为递增 p 会创建指向无效位置的指针)。实际上,在所有普通的 C 编译器上,它什么都不做。
      • 不,没有未定义的行为,因为递增的 p 永远不会离开函数并立即被丢弃。
      • 但是即使计算这样的指针也是未定义的行为,不是吗?
      • 不应该。取消引用指向无效位置的指针是非法的。我们一直使用空指针,只要我们不取消引用它们,它们就很好。
      • @Samir Talwar:不,即使创建无效指针也是未定义的行为。但是,空指针并非无效。 @Alok 和@Steve Jessop:实际上,这种情况没问题,因为您可以创建一个指向数组末尾之后的指针(尽管您不能取消引用它),并且您可以将任何指针视为指向 1 元素数组。
      【解决方案4】:

      如果您希望函数在使用&c 调用时递增c,请编写以下代码:

      void function(int *p) { ++(*p); }
      

      function(int *p) 表示p 是函数参数。所以无论调用者给出什么值,都会被分配给p(而不是*p)。

      p 的类型是int *。也就是说,p 是一个指向 int 的指针。

      如果p 是一个指向int 的指针,那么*p 就是它指向的int。

      c 是一个整数。因此&c是一个指向int的指针,它指向的int是c。因此,如果p&c,那么*p 就是c

      使用我的函数版本,这段代码:

      int c = 5;
      function(&c);
      

      和这段代码一样:

      int c = 5; // same as before
      int *p;    // parameter of the function
      p = &c;    // assign the caller's value to the parameter
      ++(*p);    // body of the function, increments *p, which is the same as c.
      

      与这段代码的作用相同:

      int c = 5;
      ++c;
      

      【讨论】:

        【解决方案5】:

        您确定p++; 是您在函数中的意思吗?这是增加p 指向的位置,而不是增加当前位置的值。如果你想增加值(即让c变成6),那么你想要的是(*p)++;

        【讨论】:

        • 不,它不会“增加 p 指向的位置”,它只是增加 p。
        • 抱歉,我措辞不佳。由于p 是一个指针,递增它会调用指针算法,它将指针有效指向的内存地址移动一个点(更改位置,而不是at i> 那个位置 - 这就是我所说的增加位置的意思,而不是增加该位置的值)。
        【解决方案6】:

        其他人已经回答了您的问题。我将补充一点,这是一种阅读指针声明的有用方法。假设我有以下声明:

        int i;
        

        这真的很容易。这里,i 是一个int。现在,假设我有这个:

        int *pi;
        

        在这里,您可以说pi 是指向int 的指针(这是正确的)。另一种看待它的方式是*pi 是一个 int,即,当您的代码中有*pi 时,*pi 的类型将是int。了解了这一点后,我认为很容易看出++pipi++ 不会增加int,因为pi 是错误的类型。你想要(*pi)++。需要括号是因为在 C 中,运算符++ 的优先级高于一元运算符*。由于您不使用增量的任何副作用,您也可以这样做:++*p

        当然,就像所有的指针一样,pi 必须指向一些有用的东西才能使上述内容有意义。

        【讨论】:

          猜你喜欢
          • 2014-08-19
          • 1970-01-01
          • 2017-12-03
          • 2013-04-04
          • 1970-01-01
          • 2012-09-22
          • 1970-01-01
          • 1970-01-01
          • 2015-02-25
          相关资源
          最近更新 更多