c语言scanf为什么要&符号

作者:袖梨 2026-09-09

在前端开发内容学习中,c语言scanf为什么要&符号是常见主题。很多人在阅读时会遇到概念分散、步骤不清和注意点难以归纳的问题。本文按照基础概念、操作流程和关键细节,对相关内容进行整理。

img_6aa0e8780169d30.webp

很多初学者第一次写scanf时都会疑惑:为什么printf里直接写变量名,到了scanf却常常要写&变量名?核心原因其实很简单:printf是把变量里的值拿出来显示,scanf是把用户输入写回变量里。既然要写回去,scanf就必须知道该写到哪块内存,所以普通变量通常要把地址传进去,也就是写&。

scanf为什么需要拿到地址

scanf的任务不是“看一眼变量”,而是把读到的数据存进变量。函数如果要修改外面的变量,就必须知道这个变量在内存中的位置,也就是地址。

例如int a;里,a本身表示变量中当前保存的整数值对应的对象;而&a表示这个变量所在的位置。scanf("%d", &a);的意思,就是把读到的整数写进a对应的内存单元。

所以,标题里的“为什么要用&符号”,最直接的答案就是:因为scanf要写入普通变量,而写入就需要地址。

  • 普通变量名如a,表示要使用这个变量对应的对象。
  • &a表示把变量a的地址传给scanf。
  • scanf拿到地址后,才能把输入结果写回原变量。

为什么printf不用&,scanf却常常要用&

这两个函数的参数用途不同,所以写法也不同。

printf是“读取变量里的值再输出”,它只需要知道值是什么。例如printf("%d", a);,传进去的是a当前保存的内容。

scanf是“读取输入后写入变量”,它需要知道写到哪里。例如scanf("%d", &a);,传进去的是a的地址。

如果把a传给printf,可以理解为“把值交给函数去显示”;如果把&a传给scanf,可以理解为“把位置交给函数去写入”。这就是两者最根本的区别。

  • printf通常接收的是值。
  • scanf通常接收的是可写入目标的地址。
  • 同一个变量,在printf和scanf里传的东西往往不是同一种内容。

不加&会发生什么

如果本来应该传地址,却误写成变量值,scanf就会把这个值当成地址使用。这样一来,它会尝试往错误的内存位置写数据。

结果轻则输入失败、变量内容异常,重则直接出现未定义行为,比如程序崩溃。对初学者来说,这也是scanf最常见、最危险的错误之一。

例如下面写法就是错的:int a; scanf("%d", a);。这里a还不是一个地址,scanf却会把它当地址处理,逻辑上就已经错了。

  • 该传地址时漏写&,本质上是把“值”错当成“地址”传入。
  • 这种错误可能导致结果异常,也可能引发崩溃。
  • scanf参数一旦和格式说明符期待的类型不匹配,就可能出现未定义行为。

结合代码看懂&到底在做什么

下面这段代码只保留最核心的两种情况:一个必须加&的普通整数变量,以及一个不用加&的字符数组。先看主线,再看例外,判断会更清楚。

重点不是背“哪个要加哪个不要加”,而是先问:这个参数传进去后,scanf期望收到的是“某种对象的地址”,还是“一个本身就表示目标地址的东西”。

  • 主线示例

    #include <stdio.h>
    
    int main(void) {
        int age;
        char name[20];
    
        scanf("%d %19s", &age, name);
    
        printf("age = %dn", age);
        printf("name = %sn", name);
        return 0;
    }
  • 对比理解

    int age;
    char name[20];
    
    scanf("%d", &age);   // 正确:%d需要int对象的地址
    scanf("%19s", name); // 正确:name在这里可作为字符序列起始地址使用
    
    scanf("%d", age);    // 错误:把值当地址传了
    scanf("%19s", &name); // 不建议这样理解和书写,类型含义已经不同

例外情况怎么严格判断

很多人学到后面会听到一些简化说法,比如数组常常不加地址符、某些场景里的指针也可能不加地址符。但这类口诀很容易让人机械套用,真正稳妥的判断方法只有一个:先看当前格式说明符到底要求什么类型的目标参数。

拿读取字符串的场景来说,它需要的是一段可写字符区域的起始位置。字符数组在传参时,往往已经能够表示这段区域从哪里开始,所以常见写法里不会再额外补一个地址符。

不过这并不等于只要看到指针或数组就能直接省略地址符。关键仍然是看当前要被修改的对象是谁。如果要写入的是一块字符内容,那么应当提供那块可写区域的起始位置;如果要写入的是某个指针变量本身,那么传入的就应该是这个指针变量的地址。

所以是否加&,不能靠词面判断,也不能死背口诀,而要回到scanf这一刻究竟准备修改哪个对象。

  • 读取字符串时,通常要提供一段真实存在并且允许写入的字符区域起点。
  • 如果一个字符指针还没有指向可写空间,就不能直接把它当成字符串输入的落点。
  • 如果当前要修改的是指针变量本身,那么就要把这个指针变量的地址传给scanf。

理解scanf为什么要加&,关键不是死记语法,而是抓住一条主线:scanf要把输入写回变量,所以普通变量通常必须传地址。至于数组名、字符串这类情况,只是少数需要额外辨别的补充场景。先把“为什么普通变量要加&”弄明白,再看例外,就不容易混乱。

相关文章

精彩推荐