C语言 为什么代码的输出是8,5,5而不是8,8,5?

avwztpqn  于 2023-06-21  发布在  其他
关注(0)|答案(2)|浏览(171)
#include<stdio.h>
#include<stdlib.h>

void f(int x, int* y, int **z)
{
    *z = malloc(sizeof(int));
    **z = 4;
    **z += 1;
    x += 2;
    *y += 3;
}

int main()
{
    int x = 5;
    int *y = &x;
    int **z = &y;
    f(x, y, z);
    printf("%d, %d, %d", x, *y, **z);
    return 0;
}

所以,这是我对这个问题的看法-
首先在main中z和y指向x,x是5。当函数被调用时,新的变量x,y,z被创建为它们的类型,函数中的y,z最终指向main中的x。现在z被指向堆中的一个int空间。这里指向堆的z的值变为5。然后函数中的x变为7,在函数的最后一行 *y+=3使main中的x值递增(使其变为8)。
现在控制流返回到主控制器
并且x应该是main中的x,也就是8,y应该是8,因为它指向main中的x。并且z应该是5,因为它指向堆。
我哪里做错了?

icnyk63a

icnyk63a1#

fz指向mainy,而不是fymainyfy是不同的变量,即使它们在某个时间具有相同的值。改变一个不会改变另一个。
我将说明当我们一行一行地(或多或少地)执行程序时发生了什么。但首先,我将重命名f的参数以避免混淆。

void f(int a, int* b, int **c)
{
    *c = malloc(sizeof(int));
    **c = 4;
    **c += 1;
    a += 2;
    *b += 3;
}

1.之后

int x = 5;
int *y = &x;
int **z = &y;

我们有

int **z @ 3000     int *y @ 2000      int x @ 1000
+-----------+      +-----------+      +-----------+
| 2000   --------->| 1000   --------->|         5 |
+-----------+      +-----------+      +-----------+

(All发明的地址确切的数字是不相关的)。
1.我们称之为f。这会将mainxyz复制到fabc

int **z @ 3000     int *y @ 2000      int x @ 1000
+-----------+      +-----------+      +-----------+
| 2000   ------+-->| 1000   ------+-->|         5 |
+-----------+  |   +-----------+  |   +-----------+
     ||        |        ||        |        ||
     ||        |        ||        |        ||
    copy       |       copy       |       copy
     ||        |        ||        |        ||
     VV        |        VV        |        VV
int **c @ 6000 |   int *b @ 5000  |   int a @ 4000
+-----------+  |   +-----------+  |   +-----------+
| 2000   ------+   | 1000   ------+   |         5 |
+-----------+      +-----------+      +-----------+

1.之后

*c = malloc(sizeof(int));

我们有

int @ 7000
                                      +-----------+
                                 +--->| ????????? |
                                 |    +-----------+
                                 |
int **z @ 3000     int *y @ 2000 |    int x @ 1000
+-----------+      +-----------+ |    +-----------+
| 2000   ------+-->| 7000   -----+ +->|         5 |
+-----------+  |   +-----------+   |  +-----------+
               |                   |
int **c @ 6000 |   int *b @ 5000   |  int a @ 4000
+-----------+  |   +-----------+   |  +-----------+
| 2000   ------+   | 1000   -------+  |         5 |
+-----------+      +-----------+      +-----------+

记住c指向mainy
1.之后

**c = 4;
**c += 1;
a += 2;
*b += 3;

我们有

int @ 7000
                                      +-----------+
                                 +--->|         5 | (4+1)
                                 |    +-----------+
                                 |
int **z @ 3000     int *y @ 2000 |    int x @ 1000
+-----------+      +-----------+ |    +-----------+
| 2000   ------+-->| 7000   -----+ +->|         8 | (5+3)
+-----------+  |   +-----------+   |  +-----------+
               |                   |
int **c @ 6000 |   int *b @ 5000   |  int a @ 4000
+-----------+  |   +-----------+   |  +-----------+
| 2000   ------+   | 1000   -------+  |         7 | (5+2)
+-----------+      +-----------+      +-----------+

1.然后,回到main,我们打印x*y(anon块)和**z(同样,通过*y的anon块)。

ni65a41a

ni65a41a2#

首先,f中的x += 2由于按值传递语义而毫无意义,并且永远不会再次使用,所以让我们摆脱它。

void f(int x, int* y, int **z)
{
    *z = malloc(sizeof(int));
    **z = 4;
    **z += 1;
    *y += 3;
}

z是指向y的指针。当我们解引用它并赋值时,我们正在赋值给main* 中的y *。Thaty现在指向某个大小适合int的内存块。我们的函数参数y没有被改变。
我们现在将4分配给该内存块,然后将其递增1main中的y现在是5
y函数参数仍然指向main中的x,所以当我们解引用它并添加3时,它现在是8
main中的z仍然指向y,因此也是5
因此,8, 5, 5被打印。
C中的按值传递语义是这里真实的的关键。我想如果我们看一下,这是否会更容易理解:

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

void f(int a, int* b, int **c)
{
    *c = malloc(sizeof(int));
    **c = 4;
    **c += 1;
    a += 2;
    *b += 3;
}

int main()
{
    int x = 5;
    int *y = &x;
    int **z = &y;
    f(x, y, z);
    printf("%d, %d, %d", x, *y, **z);
    return 0;
}

相关问题