Pwn 基础之C/C++(七):输入输出、类型转换与函数指针
本篇目标:掌握常用 I/O,理解 C 的类型转换规则,并学会阅读函数指针。
预计阅读时间:20 分钟。
1. printf 格式输出
常见格式:
| 格式 | 对应类型或用途 |
|---|---|
%d |
int 十进制 |
%u |
unsigned int |
%x |
无符号十六进制 |
%c |
字符 |
%s |
C 字符串 |
%p |
指针 |
%zu |
size_t |
%ld |
long |
%lld |
long long |
%f |
浮点输出 |
int number = 100;
char text[] = "hello";
printf("number = %d\n", number);
printf("hex = 0x%x\n", number);
printf("text = %s\n", text);
printf("address = %p\n", (void *)&number);
格式说明符必须与实际参数类型匹配。
2. scanf
int value;
printf("Input: ");
if (scanf("%d", &value) == 1) {
printf("value = %d\n", value);
}
必须传 &value,因为 scanf 需要知道目标变量地址才能写入结果。
返回值表示成功完成了多少项转换,应检查它,而不是默认输入永远有效。
3. getchar 与 putchar
int ch = getchar();
if (ch != EOF) {
putchar(ch);
}
getchar 返回 int,因为除了所有 unsigned char 值之外,还需要表示特殊值 EOF。
4. 使用 fgets 读取一行
char buffer[64];
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
printf("input: %s", buffer);
}
fgets 最多读取容量减一的字符,并补上字符串结束符。读取到的换行符通常会保留。
移除换行:
#include <string.h>
buffer[strcspn(buffer, "\n")] = '\0';
5. 文件操作
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("fopen");
return 1;
}
char buffer[128];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}
fclose(file);
常见模式:
| 模式 | 含义 |
|---|---|
r |
只读 |
w |
写入并覆盖原内容 |
a |
追加 |
rb |
二进制只读 |
wb |
二进制写入 |
成功打开后要在合适的路径调用 fclose。
6. 隐式与显式转换
隐式转换:
int value = 10;
double result = value;
显式转换:
double value = 3.14;
int integer = (int)value;
转换为整数后小数部分被舍弃。
7. 整数提升
比 int 小的整数类型参与算术运算时,通常先提升:
char a = 10;
char b = 20;
int result = a + b;
表达式不是简单地始终按原来的 char 类型计算。
8. 有符号与无符号混合
int signed_value = -1;
unsigned int unsigned_value = 1;
比较或运算前会进行通常算术转换,负的有符号值可能被转换成很大的无符号值。
阅读表达式时按顺序确认:
- 操作数原始类型;
- 整数提升后的类型;
- 两侧统一后的类型;
- 最终位模式如何解释。
建议开启警告:
gcc -Wall -Wextra -Wconversion program.c -o program
9. 指针类型转换
void *raw = pointer;
int *number = (int *)raw;
转换不会改变地址中的字节,只会改变编译器对目标的解释。使用前仍要保证地址、类型、大小和对齐都符合要求。
10. 函数指针
int add(int a, int b)
{
return a + b;
}
int multiply(int a, int b)
{
return a * b;
}
声明:
int (*operation)(int, int);
含义是:operation 指向一个接收两个 int、返回 int 的函数。
operation = add;
printf("%d\n", operation(2, 3));
operation = multiply;
printf("%d\n", operation(2, 3));
11. 用 typedef 简化函数指针
typedef int (*BinaryOperation)(int, int);
BinaryOperation operation = add;
回调示例:
int calculate(int a, int b, BinaryOperation operation)
{
return operation(a, b);
}
函数指针常用于回调、事件处理、状态机和通用算法。
本篇练习
- 用
fgets读取一行并移除换行。 - 读取文本文件并逐行输出。
- 观察
-1与无符号整数比较时的结果。 - 编写加、减、乘三个函数,用函数指针选择操作。
- 使用
typedef定义比较函数类型。
本篇小结
- 格式化 I/O 必须匹配真实类型;
- 输入函数的返回值需要检查;
fgets适合按容量读取一行;- 类型转换会改变数值的解释或表示;
- 函数也有地址,函数指针可以保存和调用它。
下一篇
下一篇学习预处理、编译、链接、未定义行为与 GDB 调试。

说些什么吧!