程序入门

> 写出第一个C程序,搞懂main函数、头文件、man手册、printf缓冲区。


一、创建第一个项目(VSCode + WSL)

1. 打开WSL终端

打开VSCode里面WSL终端

2. 新建文件

在VSCode左侧目录新建 main.c → 输入以下代码:

#include <stdio.h>

int main(void)
{
    printf("Hello World!\n");
    return 0;
}
VSCode新建main.c

3. 编译 & 运行

复制
gcc main.c -o hello
./hello
VSCode运行main.c

看到 Hello World! 说明环境OK。


二、程序基本结构拆解

部分 作用
#include <stdio.h> 引入标准输入输出头文件
int main(void) 程序唯一入口
printf("Hello World!\n"); 向标准输出打印字符串
return 0; 告诉操作系统"正常结束"

1. 头文件是什么?

声明函数、宏、类型,供编译器检查

查man手册可快速确认需要哪个头文件:

man 3 printf
VSCode运行main.c

顶部即显示:#include <stdio.h>

#include <stdio.h>

int printf  (                        const char *format, ...); // 默认把数据按照format的格式输出到标准输出文件中
int fprintf (FILE *stream,           const char *format, ...); // 往指定的文件流中输出stream
int dprintf (int fd,                 const char *format, ...); // 往指定的文件中输出fd 
int sprintf (char *str,              const char *format, ...); // 往指定的地址中输出
int snprintf(char *str, size_t size, const char *format, ...); // 【推荐】功能与sprintf一样但是多了大小控制,可以避免越界的错误

通过函数原型分析所需的参数

int printf(const char *format, ...);
/*参数分析:
    format -->格式控制符,通过格式控制符进行回溯并解析得到正确的数据  %d  %c %s %f ....*/
栈空间图

2. main函数细节

有且仅有一个,返回类型必须是 int

两种写法:

int main(void) { ... }      // 无参数
int main(int argc, char *argv[]) { ... } // 带命令行参数

return 0; 代表正常退出,非0表示异常


三、printf缓冲区实验

1. 行缓冲现象

#include <stdio.h>
int main(void)
{
    printf("123");     // 无`\n`,不会立即显示
    while(1);          // 死循环,程序不退
    return 0;
}
VSCode运行main.c

运行结果:屏幕无输出

原因:stdout行缓冲,遇到\n缓冲区满才刷新

2. 强制刷新

#include <stdio.h>
int main(void)
{
    printf("123");
    fflush(stdout);    // 立即刷新
    while(1);
}
VSCode运行main.c

此时立刻看到123


四、关于格式控制符

基本格式控制符

格式控制符 含义 适用数据类型(示例) printf 示例 输出结果(示例)
%d 有符号十进制整数 int, short printf("%d", 10); 10
%i 有符号十进制整数 (与 %d 基本相同) int, short printf("%i", -5); -5
%u 无符号十进制整数 unsigned int printf("%u", 10); 10
%o 无符号八进制整数 (不输出前缀 0) unsigned int printf("%o", 10); 12
%x 无符号十六进制整数(小写字母) (不输出前缀 0x) unsigned int printf("%x", 255); ff
%X 无符号十六进制整数(大写字母) (不输出前缀 0X) unsigned int printf("%X", 255); FF
%f 单精度浮点数(小数形式) float printf("%f", 3.14); 3.140000
%lf 双精度浮点数(小数形式) (在 printf 中 %f%lf 无区别) double printf("%f", 3.14); 3.140000
%e 以指数形式输出浮点数(小写 e) float, double printf("%e", 300.0); 3.000000e+02
%E 以指数形式输出浮点数(大写 E) float, double printf("%E", 300.0); 3.000000E+02
%g 自动选择 %f%e 中更短的一种格式(不输出无意义的0) float, double printf("%g", 3.0); 3
%G 自动选择 %f%E 中更短的一种格式(不输出无意义的0) float, double printf("%G", 0.0003); 0.0003
%c 单个字符 char printf("%c", 'A'); A
%s 字符串 char * (字符串指针) printf("%s", "Hi"); Hi
%p 输出指针地址(以十六进制形式) void * (任何指针) int a; printf("%p", &a); 0x7ffd42a1b23c (地址值)
%% 输出一个百分号 % (无) printf("%%"); %

附加格式修饰符

基本语法: %[flags][width][.precision]specifier

修饰符 含义 示例 输出结果(示例)
%md 输出宽度为 m,不足宽度用空格填充,右对齐 printf("%5d", 10); 10
%-md 输出宽度为 m,不足宽度用空格填充,左对齐 printf("%-5d", 10); 10
%0md 输出宽度为 m,不足宽度用 0 填充 printf("%05d", 10); 00010
%m.nf 输出宽度为 m,保留 n 位小数 printf("%8.2f", 3.14159); 3.14
%.nf 只指定保留 n 位小数,宽度不限 printf("%.3f", 3.14); 3.140
%*.*f 宽度和小数位数由参数指定 printf("%*.*f", 8, 2, 3.14); 3.14

重要注意事项

  1. scanfprintf 的区别

    • scanf 中,%f 用于读取 float 类型,而 %lf 用于读取 double 类型
    • printf 中,%f%lf 对于 double 类型没有区别
  2. 输出结果的变异性

    • 表格中的"输出结果"是典型示例
    • 实际输出可能因编译器、系统环境或参数的不同而略有差异
    • 特别是地址值 (%p)、浮点数精度等可能会有不同表现

五、man手册常用命令

命令 含义
man 1 printf 查看Shell命令printf
man 2 open 查看系统调用open
man 3 printf 查看库函数printf
man 4 null 查看特殊设备文件
man 5 passwd 查看文件格式和配置文件
man 6 intro 查看游戏相关
man 7 signal 查看系统信号和宏定义
man 8 mount 查看系统管理命令
man 9 EXT4 查看内核相关文档
man -f printf 列出所有分册包含printf

九大分册详解:

分册 内容类型 典型示例
1 用户命令(可执行程序) ls, gcc, printf
2 系统调用(内核接口) open, read, fork
3 库函数(C标准库) printf, malloc, fopen
4 特殊文件(设备文件) null, zero, random
5 文件格式(配置文件) passwd, fstab, hosts
6 游戏 已废弃,很少使用
7 杂项(协议/文件系统) signal, tcp, udp
8 系统管理(管理员命令) mount, ifconfig, useradd
9 内核例程(内核API) 内核开发者使用

嵌入式开发常用分册:

  • 1、2、3 - 日常开发必备
  • 5、7 - 配置文件和协议参考
  • 8 - 系统管理和调试
posted @ 2025-10-11 10:13  jaknio  阅读(7)  评论(0)    收藏  举报