为啥 &a 在 main() 和其他方法中显示不同的值?

Posted

技术标签:

【中文标题】为啥 &a 在 main() 和其他方法中显示不同的值?【英文标题】:Why &a shows different values in main() and other methods?为什么 &a 在 main() 和其他方法中显示不同的值? 【发布时间】:2022-01-17 05:52:30 【问题描述】:
void f(int a[]);

int main() 
    int a[11];
    printf("1.%x  ", &a);
    f(a);


void f(int a[]) 
    printf("2.%x    ", &a);

输出:

1.e0de4940  2.e0de4928  

但是当 & 被删除时输出将是相同的。 以及为什么不管数组大小相差12?

【问题讨论】:

您了解副本的概念吗? IE。看起来一样,但在其他地方有什么不同吗? 您正在尝试了解该语言的内部工作原理,这在很大程度上取决于您所使用的编译器和平台。基本上,你不应该担心这些事情,因为它们并不重要。无论如何,总有一天你会理解它们。 ;-) C 是按值调用。您正在将指针的副本传递给您的数组,因此您正在打印副本的位置。 a in f 是指向a 的指针的副本(即分配在不同的内存中),因此当您执行&a 时,您会看到不同的值。跨度> 如果您尝试在启用警告并将其视为错误的情况下编译此程序,您将看到此代码产生 2 个错误并拒绝编译。所以总是以这种方式编译你的程序,这会为你指明正确的方向,或者至少提供了一个提示。 【参考方案1】:

主要是printf的调用

int a[11];
printf("1.%x  ",&a);

需要使用转换说明符%p的地方输出数组a的地址。

在函数f内调用printf输出函数的局部变量(参数)a的地址

printf("2.%x    ", &a);

由于int *类型的数组和参数a占用的内存范围不同,所以它们的地址不同。

注意参数a获取main中声明的数组a的第一个元素的地址。所以参数a中存储的地址与main中数组a的地址相同。那是你可以写的

void f(int a[]);

int main() 
    int a[11];
    printf("1.%p  ", ( void * )&a);
    f(a);


void f(int a[]) 
    printf("2.%p    ", ( void * )a);

结果你会得到相同的输出。

您可以简化代码,以便于理解底层内容。

考虑下面的代码sn-p

int a[11];
int *p = a;

如您所见,两个变量 a 和 p 占用不同的内存范围。所以这些 printf 调用会产生不同的结果

printf( "%p\n", &a );
printf( "%p\n", &p );

【讨论】:

【参考方案2】:

main 中,a 是一个数组,&a 是存储该数组的地址。当main调用f时,f(a)中的a会自动转换为a的第一个元素的地址,并将该地址传递给f

f 中,a 是参数,&a 是存储该参数的地址。参数a的值设置为函数调用中传入的值,但&a是参数的地址,是值的副本。不是main中原来的a

【讨论】:

【参考方案3】:

int a[] 在语法上与int* a 相同,它们都是指向整数(也称为 int 数组)的指针。因此正确的方法是没有&

void f(int a[])
    printf("2.%x    ", a);

int main() 
    int a[11];
    printf("1.%x  ",a);
    f(a);

但是当 & 被删除时输出将是相同的。以及为什么不管数组大小相差12?

最初,您有&,它首先打印int a[11] 的地址。 然后将该数组的地址传递给f(),在那里它生成一个不同的指针,该指针也指向相同的地址。但是,这是两个不同的指针,因此当您打印实际指针的地址时,无论它们指向何处,它们显然都是不同的。

12(实际上是24,因为数字是十六进制)的区别是任意的,它只是告诉您这两个指针存储在彼此相距24字节的地址中

【讨论】:

【参考方案4】:

在您的程序中,函数f(int a[]) 中只有一个小错误

void f(int a[]) 
        printf("2.%x    ", &a);

函数f返回函数参数的地址,而不是它指向的地址

由于掌握 C 中的指针是理解 C 语言的基本方面之一,因此不仅 C 语言本身,但机器架构和 CPU/内存功能的基础知识。

因此,在指针算术和搜索/调试中出错甚至可以驱动 经验丰富的 C 程序员为之疯狂,毫不奇怪,他们在 C++ 中被利用 static_castdynamic_cast 关键字,并在随后的计算机语言中完全删除(隐藏,即..)。

所以,我更进一步,重新编写了您的代码,更好地解释了该错误。

#include <stdio.h>

void  f(int b[]) 
printf("\n func call. print address:    %x", &b);  
void f2(int b[]) 
printf("\n func call. print address(2): %x",  b);  

int main()

  int *j, a[11];

     j = a;   // load address of 'a' array to int pointer 'j'
              // pointer 'j'
              //   j  = address of an array 'a'
              //  &j  = address of 'j' !!
          
     *j = 1;  // value of any 'int' that 'j'
              // points to is 1,so the value              
              // of a[0]= 1 

// ______ print values of 'j', 'a' ______
    // value is from address 'a'
    printf("\n1.) value of number (j)= %d",   *j);
    // int value of address 'a'
    printf("\n1.) value of number (a)= %d",  a[0]);

// ______ print addresses of 'j', 'a' ______
    // address of int variable 'j' that 
    // holds pointer to 'a'
    printf("\n\n2.) addr of number (j)= %x", &j);
    // address of 'a' array
    printf("\n2.) addr of number (a)= %x",   &a);
      
// ______ all of following adressess are the same ______
    // actual pointer (points to 'a' now)
    printf("\n\n3.) addr of 'j'   = %x",     j);
    // address od an array 'a'
    printf("\n3.) addr of 'a'   = %x",       a);
    // address of first int member in array a
    printf("\n3.) addr of 'a[0]'= %x\n", &a[0]);
      
    // ______ print them from function ______ (yours) ..
       f(&j); f(a);    // outputs an address of an argument passed to a function !!!     
          
    // ______ print them from function ______ (changed) ..
       f2(&j); f2(a);  // outputs an address that an argument points to !! 
                          // (holds address of)

      return 0;
  

函数ff2 中的int b[]有意 而不是int a[],因此很明显,参数是压入堆栈的变量的副本 - 不是实际变量 a.

程序输出:

1.) value of number (j)= 1

1.) value of number (a)= 1

2.) addr of number (j)= 5f826328
2.) addr of number (a)= 5f826330

3.) addr of 'j'   = 5f826330
3.) addr of 'a'   = 5f826330
3.) addr of 'a[0]'= 5f826330

 func call. print address:    5f826308
 func call. print address:    5f826308
 func call. print address(2): 5f826328
 func call. print address(2): 5f826330

【讨论】:

【参考方案5】:

原因是 main()f() 将本地参数 a 放在内存中的不同位置,因为在某些时候,main()f() 都在它们的执行中间,并且作为这两个参数都是它们各自定义的函数的局部变量,它们确实是不同的变量(尽管它们的名称相同)

【讨论】:

【参考方案6】:

当您编写int a[] 时,您指的是指针,因为数组是指针。 要引用a 指向的位置,您只需写a。当你写&amp;a 时,你指的是指针本身的内存地址。指针本身的内存地址是不同的,因为您是按值传递指针(内存地址本身),这意味着它们在每个函数中都有一个副本。

【讨论】:

"数组是指针" - 数组是数组,但是数组的名称可以衰减为指针。见1、2。

以上是关于为啥 &a 在 main() 和其他方法中显示不同的值?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用Junit Test而不用普通java main方法来完成测试?

Main 方法在执行过程中等待线程完成。为啥?

java中为啥要把main方法定义为一个static方法

为啥手机编译器class后面默认是Main呢

为啥单例对象创建的scala程序不需要静态main方法?

为啥在 main 方法中使用 SwingUtilities.invokeLater?