C/C++中取地址符&的语义

本文详细解析了C语言中&符号的作用,不仅介绍了如何获取变量地址,还深入探讨了解引用操作符(*)和地址操作符(&)的不同用法及组合使用时的行为表现。

在C语言中,&符号大家一定很熟悉吧。

它除了可以作为按位运算“与”之外还有更常用的功能——取变量地址。

我们首先看下面一个简单的例子:

#include <stdio.h>

int main(void)
{
    int a = 0;

    int *p = &a;

    printf("The value is: %d/n", *p);

    return 0;
}

上面代码中,指针p指向变量a的地址。在C/C++中,每个变量都有其相应的地址,通过在变量标识符前加&符号即可获得变量的地址

那么我们这么写可以吗?int *p = &0x01000;

这显然不行。因为对于一个数值常量,它是没有地址的。而变量之所以有地址就是因为要有一个存储单元对变量进行标识(当然,变量也可以直接映射到某个寄存器)。

我们再看下面的代码:

#include <stdio.h>

int main(void) 
{ 
    int a = 0; // &a = 0x0012ff60 
    int *p = &*(int*)0x0012ff60; 
    printf("The value is: %d/n", *p); 
    return 0; 
}

 上面代码又是怎么回事呢?

先前已经调查过变量a的地址——0x0012ff60,那么这里的指针p实际上也是指向变量a的地址。

首先,将0x0012ff60作为int*,这时它与&a是等价的。

然后*(int*)0x0012ff60表示取变量a的内容。

最后,&*(int*)0x0012ff60表示再脱去*(int*)0x0012ff60的解引用,相当于又变为(int*)&a。

因此,这里的&与第一个例子中的&是不同的语义。这里的&不是取地址,因为一个*(int*)0x0012ff60不是变量,它是没有地址的。每一个变量标识符在编译期间,编译器会为它们创建一个符号表,其中存放着变量标识符相应的各种属性,如类型、地址标识等。地址标识在连接后即可确定逻辑地址值。简而言之,&作为取地址操作,当且仅当&后面跟着的是变量或函数标识符。所以这里的&表示脱去解引用

由此我们可以得出:&作为取地址操作时,其行为结果是在编译时就被确定的;而*,解引用操作(或取内容)操作,其行为结果只能在运行时才可被确定

再看下面的例子,加深印象:​​​​​​​

#include <stdio.h>


int main(void)
{
    int a = 0;

    int *p = &*&*&a;

    printf("The value is: %d/n", *p);

    return 0;
}

不过,&符号不象解引用*能用多次,它只能放在变量标识符或一次解引用前。下面举一个例子

int main(void)
{
    int a = 100;
    int *p = &a;
    int **pp = &p;
    int **qq = &*&*pp;    // OK
    int **rr = *&*&pp;    // OK
    int **ss = &&**pp;    // ERROR
}


由于经过一次&来脱去解引用之后,当前表达式就不为左值。而&必须放在一个左值前,因为只有左值才能确保引用是有效的,呵呵。

在C++中,&还可以表示引用,这个就不多说了。​​​​​​​

#include <iostream>
using namespace std;


int main(void)
{
    int a = 0;

    int &r = a;

    cout << "The value is: " << r << endl;

    return 0;
}

在C语言中,函数参数中使用取地址符`&amp;`可能导致编译错误,原因在于`&amp;`符号在C语言中有特定的语义,通常用于获取变量的地址。如果在函数参数中错误地使用了`&amp;`,编译器将无法正确解析参数类型,从而报错。 例如,以下代码会导致错误: ```c void func(int &amp;a); // 错误:C语言不支持引用传递 ``` 该写法实际上是C++中的引用传递语法,在C语言中并不被支持。C语言中函数参数的传递是按值传递的,若需传递变量的地址,应使用指针类型作为参数[^1]。 ### 正确使用方式 在C语言中,若希望函数能够修改调用者提供的变量,应使用指针作为函数参数。例如: ```c void func(int *a) { *a = 10; } int main() { int x = 5; func(&amp;x); // 将x的地址传递给func return 0; } ``` 在上述代码中,`func`接受一个指向`int`类型的指针,函数内部通过解引用操作修改了外部变量`x`的值。此时,调用`func(&amp;x)`是合法的,因为`&amp;x`表示取变量`x`的地址,并将其作为指针参数传递给函数。 ### 常见错误与解决方法 1. **错误地在函数定义中使用`&amp;`**: ```c void func(int &amp;a) { } // 错误:C语言不支持引用 ``` 解决方法是将参数改为指针类型,并在调用时传递地址: ```c void func(int *a) { *a = 20; } int main() { int x = 10; func(&amp;x); return 0; } ``` 2. **在函数声明或定义中省略参数名称,仅保留类型和`&amp;`**: ```c void func(int &amp;) { } // 错误:语法不合法 ``` 正确做法是使用指针类型并提供参数名称: ```c void func(int *a) { } ``` 3. **误将`&amp;`用于非地址操作的上下文**: 例如: ```c int a = 5; int b = &amp;a; // 错误:类型不匹配 ``` 正确做法是使用指针变量存储地址: ```c int a = 5; int *b = &amp;a; // 正确:b指向a的地址 ``` ### 总结 C语言中不存在引用传递机制,所有参数都是按值传递。若希望函数能够修改外部变量,应使用指针作为参数,并在调用时使用`&amp;`运算符获取变量地址。直接在函数参数列表中使用`&amp;`而不配合指针类型是非法的,会导致编译错误。 ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值