一、取地址运算符
1. 基本作用:获取变量的内存地址
- 语法:
&变量名
- 返回值:变量在内存中的起始地址(类型为对应指针类型)。
int x = 10;
int* ptr = &x; // ptr 存储 x 的内存地址
这里,&x
返回一个 int*
类型的值(指向 int
的指针),并赋值给指针变量 ptr
。
2. 与指针的关系
- 指针变量:存储内存地址的变量,声明时需指定指向的数据类型。
- 解引用操作符
\*
:与&
互为逆运算,通过地址访问对应内存中的值。
int x = 10;
int* ptr = &x; // ptr 指向 x 的地址
printf("%p\n", ptr); // 输出 x 的地址(如 0x7ffe5360f9c4)
printf("%d\n", *ptr); // 通过指针解引用,输出 10(即 x 的值)
3. 示例:交换两个数的值(函数实现):
void swap(int* a, int* b) {
int temp = *a; // 读取 a 地址处的值
*a = *b; // 将 b 地址处的值写入 a 地址
*b = temp; // 将 temp 的值写入 b 地址
}
int main() {
int x = 10, y = 20;
swap(&x, &y); // 传递 x 和 y 的地址
printf("%d, %d\n", x, y); // 输出 20, 10
}
&x
和&y
将变量地址传递给函数。- 函数内部通过
*a
和*b
直接操作原始内存,实现值的交换。
4. 与数组的关系
数组名在大多数表达式中会隐式转换为指向首元素的指针:
int arr[3] = {1, 2, 3};
int* ptr = arr; // 等价于 int* ptr = &arr[0];
printf("%d\n", *ptr); // 输出 1(首元素的值)
printf("%d\n", *(ptr+1)); // 输出 2(第二个元素的值)
5. 反面教材
混淆 &
和 \*
int x = 10;
int* ptr = &x; // 正确:ptr 存储 x 的地址
int* ptr2 = x; // 错误:无法将 int 赋值给 int*
未正确传递地址
void increment(int* num) {
(*num)++; // 解引用后递增
}
int main() {
int x = 5;
increment(x); // 错误:期望 int*,传入 int
increment(&x); // 正确:传递地址
return 0;
}
二、scanf
scanf
是标准库提供的输入函数,用于从标准输入(通常是键盘)读取格式化数据。
一、基本语法
#include <stdio.h>
int scanf(const char *format, ...);
- 参数:
format
:格式化字符串,指定输入的格式(如%d
表示整数,%f
表示浮点数)。- 可变参数:接收输入值的变量地址(使用
&
运算符获取)。
- 返回值:成功匹配并赋值的输入项数量,遇错误或文件结束符(EOF)时返回
EOF
。
二、常见格式说明符
格式符 | 说明 | 示例输入 |
---|---|---|
%d |
读取十进制整数 | 123 |
%f |
读取浮点数(float) | 3.14 |
%lf |
读取双精度浮点数 | 3.14159 |
%c |
读取单个字符 | a |
%s |
读取字符串(遇空格停止) | hello |
%[^\n] |
读取整行字符串(包括空格) | hello world |
三、示例用法
1. 读取整数
int num;
printf("请输入一个整数: ");
scanf("%d", &num); // 输入 123 → num = 123
2. 读取多个值
int a, b;
printf("请输入两个整数: ");
scanf("%d %d", &a, &b); // 输入 1 2 → a=1, b=2
3. 读取浮点数
变量类型 | scanf 格式说明符 |
示例 |
---|---|---|
float |
%f |
scanf("%f", &num); |
double |
%lf |
scanf("%lf", &num); |
float f;
scanf("%f", &f); // 输入 3.14 → f=3.14
4. 读取字符串
char name[20];
scanf("%s", name); // 输入 hello → name="hello"
// 注意:scanf 遇空格停止,输入 "hello world" 时,name="hello"
5. 读取带空格的字符串
char sentence[100];
scanf("%[^\n]", sentence); // 输入 hello world → sentence="hello world"
6.读取单个字符
#include <stdio.h>
int main() {
char ch;
printf("请输入一个字符: ");
scanf("%c", &ch); // 读取一个字符
printf("你输入的字符是: %c\n", ch);
return 0;
}
需留意缓冲区问题
四、注意事项
1. 地址传递
- 除数组名(本身是地址)外,其他变量必须用
&
获取地址:
int num;
scanf("%d", &num); // 正确
scanf("%d", num); // 错误!未传递地址
2. 输入缓冲区问题
scanf
读取后可能残留换行符\n
,影响后续输入:
char name[20];
int age;
scanf("%d", &age); // 输入 20 后残留 \n
scanf("%s", name); // \n 被读取,name 为空!
解决方案:
// 方法1:在格式字符串中加空格,消耗换行符
scanf(" %s", name); // 空格消耗 \n
// 方法2:手动清除缓冲区
while (getchar() != '\n'); // 消耗所有剩余字符
3. 字符串输入限制
%s
遇空格停止,且不检查数组边界,可能导致缓冲区溢出:
char name[5];
scanf("%s", name); // 输入超过4个字符时会溢出!
安全写法:用 %ns
限制输入长度(n
为最大字符数):
scanf("%4s", name); // 最多读取4个字符,自动留空间给 '\0'
五、高级用法
1. 正则表达式匹配
- 使用
[]
自定义字符集
char str[20];
scanf("%[0-9]", str); // 只读取数字字符,输入 1a2 → str="1"
2. 忽略输入
- 使用
*
丢弃匹配的输入:
int a, b;
scanf("%d %*d %d", &a, &b); // 输入 1 2 3 → a=1, b=3(2被忽略)
六、与其他输入函数的对比
函数 | 特点 | 适用场景 |
---|---|---|
scanf |
格式化输入,支持多种类型 | 结构化数据输入 |
fgets |
读取整行,安全(指定缓冲区大小) | 读取含空格的字符串 |
getchar |
读取单个字符 | 字符处理、菜单选择 |
三、C 语言和 Python 在处理字符与整数相加机制
1. C 语言:字符本质是整数
在 C 中,字符型(char
)本质上就是 1 字节的整数,存储的是字符的 ASCII 码值。因此,字符与整数的加减运算是直接对 ASCII 码进行数值运算。
#include <stdio.h>
int main() {
char c = 'A'; // ASCII码为65
int num = c + 1; // 65 + 1 = 66
printf("%d\n", num); // 输出:66
printf("%c\n", num); // 输出:B(ASCII码66对应的字符)
return 0;
}
关键点
- 字符
'A'
直接参与加法运算时,会被隐式转换为整数 65。 - 运算结果(整数)可以通过
%c
格式说明符转换回字符输出。
2. Python:字符串不可变,需显式转换
在 Python 中,字符用长度为 1 的字符串表示,字符串是不可变对象,不能直接与整数相加。若要实现类似 C 语言的字符运算,需通过 ord()
和 chr()
函数进行显式转换:
ord(c)
:将字符转换为 ASCII 码值(整数)。chr(n)
:将整数转换为对应的 Unicode 字符。
c = 'A'
num = ord(c) + 1 # ord('A') 返回65,65 + 1 = 66
print(num) # 输出:66
print(chr(num)) # 输出:B(ASCII码66对应的字符)
错误示例
直接将字符串与整数相加会报错:
c = 'A'
print(c + 1) # 报错:TypeError: can only concatenate str (not "int") to str
3. 为什么会有这种差异?
- C 语言是静态类型语言,设计之初就允许对字符进行数值运算,这与底层硬件表示(ASCII 码)直接对应。
- Python是动态类型语言,字符串是高级抽象数据类型,需要通过函数显式转换,以保持类型安全。
4.总结
特性 | C 语言 | Python |
---|---|---|
字符本质 | 1 字节整数(ASCII 码) | 长度为 1 的字符串对象 |
加法运算 | 直接对 ASCII 码进行数值运算 | 不允许字符串与整数相加,需显式转换 |
示例 | 'A' + 1 → 66(整数) |
'A' + 1 → 报错 |
转换函数 | 隐式转换,%c 格式说明符 |
ord() 和 chr() |
评论区