HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • C 语言入门教程

    • C语言系列教程
    • 第01章 基础概念与编译
    • 第02章 数据类型与变量
    • 第03章 运算符
    • 第04章 输入输出
    • 第05章 流程控制
    • 第06章 数组
    • 第07章 指针
    • 第08章 函数
    • 第09章 构造类型

第01章 C语言基础与编译

1.1 Hello World程序

让我们从最简单的C程序开始:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("Hello world!\n");
    exit(0);
}

程序结构解析

  1. 头文件包含: #include <stdio.h> - 标准输入输出库
  2. 主函数: int main(void) - 程序入口
  3. 函数体: 用花括号{}包围的代码块
  4. 退出程序: exit(0) - 正常退出(返回0表示成功)

1.2 main函数的形式

C语言中main函数有多种形式(可能与编译器有关):

// 标准形式1:无参数
int main(void)
{
    // ...
    return 0;
}

// 标准形式2:带命令行参数
int main(int argc, char **argv)  // 或 char *argv[]
{
    // ...
    return 0;
}

// 其他形式(不推荐)
void main(void);
void main(int argc, char **argv);

参数说明

  • argc: 命令行参数个数(argument count)
  • argv: 命令行参数数组(argument vector)

1.3 程序退出方式

return与exit的区别

int main(void)
{
    printf("Hello world!\n");
    return 0;     // 方式1:返回给父进程(shell)
    // exit(0);   // 方式2:退出程序,返回给父进程
}

查看程序返回值:

$ ./hello
Hello world!
$ echo $?
0

注意事项

⚠️ 如果main函数没有显式返回值:

  • 程序不会报错
  • 但返回值不是默认的0
  • 实际返回的是最后一条语句的返回值
int main(void)
{
    printf("Hello world!\n");  // printf返回字符串长度13
    // 没有return或exit,返回值是13而不是0
}

输出:

$ ./test
Hello world!
$ echo $?
13

1.4 编译过程详解

四个编译阶段

C源文件需要经过4个步骤才能变成可执行文件:

源文件(.c) → 预处理(.i) → 编译(.s) → 汇编(.o) → 链接(可执行文件)

分步编译示例

# 查看源代码
$ cat hello.c
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    printf("Hello world!\n");
    exit(0);
}

# 1. 预处理:展开宏定义、头文件等
$ gcc -E hello.c > hello.i

# 2. 编译:生成汇编代码
$ gcc -S hello.i               # 生成hello.s

# 3. 汇编:生成目标文件
$ gcc -c hello.s               # 生成hello.o

# 4. 链接:生成可执行文件
$ gcc hello.o -o hello

# 执行程序
$ ./hello
Hello world!

一步编译

# 直接生成可执行文件
$ gcc hello.c -o hello

# 使用make工具
$ make hello
cc hello.c -o hello

1.5 gcc编译器使用

基本编译选项

# 基本编译
gcc hello.c -o hello

# 开启所有警告(强烈推荐!)
gcc -Wall hello.c -o hello

# 指定C语言标准
gcc -std=c99 hello.c -o hello
gcc -std=c11 hello.c -o hello

-Wall选项的重要性

-Wall选项会显示所有警告信息,帮助发现潜在错误。

示例:隐式函数声明

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

int main()
{
    FILE *fp;
    fp = fopen("tmp", "r");  // 文件不存在
    if (fp == NULL)
    {
        // 使用strerror但未包含string.h头文件
        fprintf(stderr, "fopen():%s\n", strerror(errno));
        exit(1);
    }
    puts("ok!");
    exit(0);
}

不使用-Wall编译:

$ gcc a.c
# 编译通过,但运行报段错误
$ ./a.out
段错误

使用-Wall编译:

$ gcc a.c -Wall
a.c: 在函数'main'中:
a.c:11:3: 警告:隐式声明函数'strerror' [-Wimplicit-function-declaration]
    fprintf(stderr, "fopen():%s\n", strerror(errno));
    ^
a.c:11:3: 警告:格式 '%s' expects argument of type 'char *', but argument 3
has type 'int' [-Wformat=]

解决方法: 包含正确的头文件

#include <string.h>  // strerror函数需要此头文件

char *strerror(int errnum);

1.6 注释

C语言支持三种注释方式:

// 1. 行注释(C99标准)
int a = 10;  // 这是行注释

// 2. 块注释
/*
 * 这是块注释
 * 可以跨多行
 */
int b = 20;

// 3. 预编译注释(用于调试)
#if 0
void func()
{
    // 这段代码不会被编译
}
#endif

预编译注释的优势

  • 可以嵌套注释
  • 可以快速禁用大段代码
  • 常用于调试

1.7 vim编辑器技巧

在vim中编写C代码的实用技巧:

  • Ctrl+P: 自动补全
  • Shift+K: 查看函数的man手册
# 在vim中,光标移到printf上,按Shift+K
# 等同于在终端执行:
$ man 3 printf

1.8 实践练习

练习1:编译并运行Hello World

  1. 创建hello.c文件
  2. 使用gcc -Wall编译
  3. 查看返回值

练习2:理解编译过程

使用分步编译,查看每个中间文件的内容:

gcc -E hello.c > hello.i
gcc -S hello.i
gcc -c hello.s
gcc hello.o -o hello

练习3:修复警告

编写代码故意不包含某些头文件,使用gcc -Wall找出问题并修复。

1.9 常见错误

错误1:未包含头文件

// 错误:使用printf但未包含stdio.h
int main()
{
    printf("Hello\n");  // 隐式函数声明
    return 0;
}

错误2:忘记return或exit

int main()
{
    printf("Hello\n");
    // 忘记return或exit,返回值不确定
}

错误3:语句后缺少分号

int main()
{
    printf("Hello\n")  // 缺少分号
    return 0;
}

1.10 小结

本章学习了:

C程序的基本结构 main函数的多种形式 程序的编译过程(预处理→编译→汇编→链接) gcc编译器的使用,特别是-Wall选项 程序的退出方式(return vs exit) C语言的注释方式

重点提示:

  1. 养成使用gcc -Wall的习惯
  2. 总是包含必要的头文件
  3. 理解编译的四个阶段
  4. main函数要有明确的返回值

下一章: 第02章 数据类型与变量