【问题标题】:pointer behaviour inside function函数内部的指针行为
【发布时间】:2017-10-23 16:50:35
【问题描述】:

我不明白函数在作为参数传递时如何改变指针的状态。例如,在这段代码中 -

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void inc(int* a) {
    a++;
}

void change(int* a) {
    a[0] = 2;
    a[1] = 3;
}

int main() {

    int* a = (int*) malloc(2 * sizeof(int));
    a[0] = 1;
    a[1] = 2;

    printf("%d \n",*a);
    inc(a);
    printf("%d \n",*a);

    change(a);
    return 0;
}

据观察,当我尝试使用函数inc() 时,指针不会增加。 但与此同时,change() 确实改变了指针的值。

你能解释一下为什么inc() 不起作用吗?

【问题讨论】:

  • c 中的所有内容都是按值传递的。对于这两个函数,都制作了a 的本地副本。在inc 中,您只需增加该本地副本,当您离开时更改就会丢失。在 change 中,您使用方括号取消引用 a 指针的本地副本,因此对该取消引用所做的更改在函数之外仍然存在。
  • "change() 确实改变了指针的值" - 它改变了 指向 对象。

标签: c++ c pointers


【解决方案1】:

inc 确实改变了传递给它的指针的值 - 但传递给它的是原始指针值的副本,因此原始值保持不变。

change 不会改变指针本身,它会改变指针所指向的内容。

如果您希望 inc 更改原始指针,您必须将其更改为返回递增指针的函数,然后将其分配给原始指针:

int* inc(int* ip) {
  return ++ip;
}

然后在main:

a = inc(a);

或者您可以重写inc 以将指针作为参数,然后将原始指针的地址传递给它,如下所示:

void inc(int** ipp) {
  *ipp = *ipp + 1;
}

然后从main 调用它为:

inc(&a);

祝你好运。

【讨论】:

    【解决方案2】:

    这是画一些照片的好地方。当你写

    int* a = (int*) malloc(2 * sizeof(int));
    

    您会得到如下所示的设置:

    +---------+      +---------+---------+
    | addr X  | ---> |  ?????  |  ?????  |
    +---------+      +---------+---------+
     pointer a
      in main
    

    a[0]a[1] 赋值后,如下所示:

    +---------+      +---------+---------+
    | addr X  | ---> |    1    |    2    |
    +---------+      +---------+---------+
     pointer a
      in main
    

    现在,假设您致电 inc(a)。这会将指针a 的副本传递给inc 函数。由于指针是唯一被复制的东西,现在看起来像这样:

    +---------+      +---------+---------+
    | addr X  | ---> |    1    |    2    |
    +---------+      +---------+---------+
     pointer a            ^
      in main             |
                          |
    +---------+           |
    | addr X  |-----------+
    +---------+
     pointer a
       in inc
    

    请注意,现在有两个名为 a 的指针,但它们不是同一个指针。这就像如果你有两个朋友叫 Zoe - 他们有相同的名字,但他们不是同一个人。

    inc,你写的

    a++;
    

    这意味着“将指针 a 前进以指向它当前指向的 int 之后的下一个 int。”这看起来像这样:

    +---------+      +---------+---------+
    | addr X  | ---> |    1    |    2    |
    +---------+      +---------+---------+
     pointer a                      ^
      in main                       |
                                    |
    +---------+                     |
    | addr Y  |---------------------+
    +---------+
     pointer a
       in inc
    

    注意main 中的a 没有改变,因为我们正在操作a 的副本。再次回想一下 Zoe 的类比——如果你和一个叫 Zoe 的人交谈,这并不意味着你和另一个叫 Zoe 的人交谈。结果,当inc 返回时,a 的副本消失在以太中,我们只剩下这个:

    +---------+      +---------+---------+
    | addr X  | ---> |    1    |    2    |
    +---------+      +---------+---------+
     pointer a
      in main
    

    由于指针没有改变,这就是为什么您在调用inc 之前和之后看到相同的值。

    但是调用change 的工作方式不同。当您最初调用change 时,情况如下所示:

    +---------+      +---------+---------+
    | addr X  | ---> |    1    |    2    |
    +---------+      +---------+---------+
     pointer a            ^
      in main             |
                          |
    +---------+           |
    | addr X  |-----------+
    +---------+
     pointer a
     in change
    

    当你现在写作时

    a[0] = 2;
    

    你是说“跟随名为 a 的指针,看看你在哪里结束,并将值 2 放在那里。这意味着我们看到以下内容:

    +---------+      +---------+---------+
    | addr X  | ---> |    2    |    2    |
    +---------+      +---------+---------+
     pointer a            ^
      in main             |
                          |
    +---------+           |
    | addr X  |-----------+
    +---------+
     pointer a
     in change
    

    a[1] = 3 也意味着“跟随名为a 的指针,在你找到的索引中找到1 处的元素,并将其替换为3。这给出了以下内容:

    +---------+      +---------+---------+
    | addr X  | ---> |    2    |    3    |
    +---------+      +---------+---------+
     pointer a            ^
      in main             |
                          |
    +---------+           |
    | addr X  |-----------+
    +---------+
     pointer a
     in change
    

    现在,change 返回后,我们又回到了mainmain 中的 a 指针没有改变——它仍然在同一个地方寻找——但是它指向的数组的值已经改变了。

    +---------+      +---------+---------+
    | addr X  | ---> |    2    |    3    |
    +---------+      +---------+---------+
     pointer a            
      in main             
    

    总结一下:

    • 指针在 C 中按值传递,这意味着如果将指针传递给函数,则传递的是指针的副本。
    • 因此,如果将指针作为参数的函数更改指针指向的位置,这将不会影响调用函数。
    • 但是,如果一个函数改变了指向的内容,这将反映在调用者中。

    【讨论】:

      【解决方案3】:
      void inc(int* a) {
          a++;
      

      这里a 是按值传递的,因此在inc() 内部更改a 不会反映在外部。

      void change(int* a) {
          a[0] = 2;
          a[1] = 3;
      

      这里a 也是按值传递的,但您可以使用a 更改a 指向的内容,这正是a[0]a[1] 所做的事情。

      【讨论】:

        【解决方案4】:

        a++ 增加局部变量a 的值。也就是步入记忆中的下一个地方。如果你想增加它,你应该使用(*a)++

        符号a[1] 只是隐藏指针算术的语法糖。这真正的意思是*(a+1)。这有一个有趣的副作用。 a[1]1[a] 是一回事

        【讨论】:

          【解决方案5】:

          对于inc 函数,它正在更改参数a。由于 C 中的所有函数参数都是按值传递的,因此这种更改不会反映在调用函数中。

          change 被调用时,它会这样做:

          a[0] = 2;
          a[1] = 3;
          

          与此相同:

          *(a + 0) = 2;
          *(a + 1) = 3;
          

          具体来说,指针a 正在被取消引用。该功能不会改变a,而是a 指向的内容。这就是更改在函数外部可见的原因。

          【讨论】:

            【解决方案6】:

            inc中的代码

            void inc(int* a) {
                a++;
            }
            

            更改指针值的副本,并且不影响传递的参数。要影响参数通过引用而不是值传递:

            void inc(int*& a) {
                a++;
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-11-05
              • 2012-01-02
              • 2012-10-17
              • 1970-01-01
              • 2015-08-22
              相关资源
              最近更新 更多