printf与格式说明符中&的用法及代码报错原因咨询
为啥修改printf参数后C程序从崩溃变“正常”?顺便聊聊printf和&的正确用法
嘿,咱们先把你这两段代码的问题拆明白,再把printf和&的用法说透——其实第二段代码只是“看起来正常”,本质上还是有大坑的!
一、两段代码的问题根源
第一段代码崩溃的核心原因
先看第一段代码的关键错误:
char a; scanf("%s", &a); printf("U have to %s", a);
这里有两个致命问题:
%s是给字符串用的,你却用来操作单个字符:C语言里的字符串是char数组,还得带个\0结尾符。你用%s往单个char变量a里读内容,输入的字符串(哪怕只是一个字符+结束符)都会溢出a的1字节内存,直接触发未定义行为——这已经给程序崩溃埋了雷。printf的参数和格式符不匹配:%s要求传入的是字符串的首地址(char*类型),但你传的是单个char变量a的值。printf会把这个值当成内存地址去访问,这肯定是非法内存操作,程序直接崩掉毫不意外。
第二段代码“正常”的本质——只是运气好
第二段代码把printf的参数改成了&a:
printf("U have to %s", &a);
这里&a是取a的内存地址(类型是char*),刚好匹配%s要求的指针类型,所以printf不会因为参数类型不匹配直接崩溃。但注意:这不是正确写法! 你用scanf("%s", &a)的时候,输入的字符串已经溢出了a的内存,属于未定义行为——这次没崩只是运气好,换个编译器、操作系统,或者输入更长的内容,程序照样会崩溃,甚至搞乱其他变量的数据。
二、printf与&的正确用法
1. &到底是干啥的?
&是取地址运算符,作用是拿到变量的内存地址,返回的是指针类型:
- 在
scanf里必须用&(除了字符串数组):比如scanf("%d", &num),因为scanf需要通过地址去修改原变量的值,如果你不传地址,它只能拿到变量的副本,根本改不了原变量。 - 在
printf里几乎不用&:除非你要输出变量的内存地址本身(这时候要用%p格式符,比如printf("a的地址是%p", &a)),或者像你那样强行凑类型(但这是错误用法)。
2. printf格式符和参数的匹配规则
每个格式说明符都对应固定的参数类型,乱配就出问题:
%c:对应单个char变量,比如printf("输入的字符是%c", a)(a是char类型)%s:对应char*指针(字符串首地址),比如定义char str[20] = "hello";,然后printf("%s", str);(数组名本身就是首地址,不用加&)%d:对应int变量,比如printf("数字是%d", num)%p:专门用来输出内存地址,这时候才需要传&变量
给你写两个正确的版本
如果只是要读单个字符:
#include <stdio.h> #include <stdlib.h> int main() { char a; printf("What? \t"); scanf("%c", &a); // 用%c读单个字符,必须传&a拿地址 printf("U have to %c", a); // 用%c输出单个字符,直接传a的值 return 0; }
如果要读字符串:
#include <stdio.h> #include <stdlib.h> int main() { char a[20]; // 定义足够大的数组存字符串(要留位置给结束符) printf("What? \t"); scanf("%s", a); // 数组名a就是首地址,不用加& printf("U have to %s", a); // 直接传数组名,匹配%s return 0; }
内容的提问来源于stack exchange,提问作者Just Zac
相关产品推荐
相关产品推荐

