Linux下C语言编程实例如何快速上手?

99ANYc3cd6
预计阅读时长 26 分钟
位置: 首页 C语言 正文

下面我将通过一系列从简单到复杂的实例,带你一步步入门 Linux C 语言编程。

linux下c语言编程实例
(图片来源网络,侵删)

环境准备

在开始之前,请确保你的 Linux 系统已经安装了必要的编译工具。

  1. 打开终端
  2. 更新软件包列表 (推荐):
    sudo apt update  # 对于 Debian/Ubuntu 系统
  3. 安装 GCC (GNU Compiler Collection) 和 GDB (GNU Debugger):
    sudo apt install build-essential gdb

    build-essential 是一个元数据包,它会自动安装 gcc, g++, make 等核心编译工具。


Hello, World!

这是所有编程语言的第一个程序,让我们看看它在 Linux 下是如何工作的。

代码 (hello.c)

#include <stdio.h> // 标准输入输出库,包含了 printf 函数的声明
int main() {
    // printf 函数用于在标准输出(通常是终端)上打印字符串
    // \n 是一个换行符
    printf("Hello, Linux World!\n");
    // main 函数返回 0 表示程序成功执行完毕
    return 0;
}

代码解析

  • #include <stdio.h>: 这是一个预处理器指令,它告诉编译器在编译之前,将 stdio.h 文件的内容包含进来。stdio.h 定义了标准输入/输出函数,如 printf, scanf 等。
  • int main(): 这是程序的入口点,操作系统会首先调用这个函数。
  • printf(...): 一个来自 stdio.h 的函数,用于格式化并输出文本。
  • return 0;: main 函数的返回值。0 在 Unix/Linux 系统中通常代表程序成功执行,任何非零值都表示程序遇到了错误。

编译与运行

  1. 保存代码:将上面的代码保存为 hello.c

    linux下c语言编程实例
    (图片来源网络,侵删)
  2. 编译:在终端中,使用 gcc 编译器进行编译。

    gcc hello.c -o hello
    • gcc: 调用 GCC 编译器。
    • hello.c: 源文件。
    • -o hello: 指定输出的可执行文件名为 hello,如果不写 -o,默认会生成一个名为 a.out 的文件。
  3. 运行:编译成功后,你会得到一个名为 hello 的可执行文件,运行它:

    ./hello
    • 表示在当前目录下寻找并执行该程序,因为 Linux 的 PATH 环境变量通常不包含当前目录,所以必须这样写。

输出:

Hello, Linux World!

文件操作

Linux 中“一切皆文件”,文件操作是 C 语言编程的核心,下面是一个读取文件内容的例子。

linux下c语言编程实例
(图片来源网络,侵删)

代码 (read_file.c)

#include <stdio.h>
#include <stdlib.h> // 用于 exit 函数
int main() {
    FILE *fp;       // 文件指针
    char ch;        // 用于存储读取的字符
    // 以只读模式 ("r") 打开文件 "test.txt"
    fp = fopen("test.txt", "r");
    // 检查文件是否成功打开
    if (fp == NULL) {
        perror("Error opening file"); // perror 会打印 "Error opening file: " 并附上系统错误信息
        return EXIT_FAILURE;          // EXIT_FAILURE 是 <stdlib.h> 中定义的非零错误码
    }
    // 循环读取文件,直到到达文件末尾 (EOF - End of File)
    printf("Content of test.txt:\n");
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch); // 将读取到的字符输出到标准输出
    }
    printf("\n");
    // 关闭文件,这是一个好习惯
    fclose(fp);
    return EXIT_SUCCESS; // EXIT_SUCCESS 是 <stdlib.h> 中定义的 0
}

代码解析

  • FILE *fp: C 语言使用 FILE 类型的指针来操作文件流。
  • fopen("test.txt", "r"): 打开文件。
    • 第一个参数是文件名。
    • 第二个参数是打开模式:
      • "r": 只读。
      • "w": 只写,如果文件不存在则创建,如果存在则清空。
      • "a": 追加,如果文件不存在则创建,如果存在则在末尾写入。
      • "r+": 读写。
  • if (fp == NULL): fopen 可能会失败(例如文件不存在),此时它会返回 NULL,必须检查。
  • perror(): 一个非常有用的函数,它打印你提供的自定义错误信息,并附上系统描述的错误原因(如 "No such file or directory")。
  • fgetc(fp): 从文件指针 fp 指向的文件中读取一个字符。
  • EOF: 一个宏,代表文件结束。
  • fclose(fp): 关闭文件,释放系统资源。

编译与运行

  1. 创建一个测试文件
    echo "This is a test file for C programming on Linux." > test.txt
  2. 编译 C 程序
    gcc read_file.c -o read_file
  3. 运行
    ./read_file

输出:

Content of test.txt:
This is a test file for C programming on Linux.

命令行参数处理

很多 Linux 工具都通过命令行参数来配置行为(如 ls -l),C 语言可以通过 main 函数的参数来获取它们。

代码 (args.c)

#include <stdio.h>
int main(int argc, char *argv[]) {
    // argc: argument count (参数个数)
    // argv: argument vector (参数向量),一个字符串数组
    printf("Program name: %s\n", argv[0]); // argv[0] 总是程序的名称
    printf("Total arguments: %d\n", argc);
    printf("Arguments passed:\n");
    // 从 1 开始遍历,因为 argv[0] 是程序名
    for (int i = 1; i < argc; i++) {
        printf("  argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}

代码解析

  • int argc: argc 是一个整数,代表传递给程序的参数总数,包括程序名本身。
  • char *argv[]: argv 是一个字符指针数组,每个元素都是一个指向参数字符串的指针。
    • argv[0] 指向程序的可执行文件名。
    • argv[1] 指向第一个实际参数。
    • argv[argc-1] 指向最后一个参数。
    • argv[argc] 是一个 NULL 指针,标志着数组的结束。

编译与运行

  1. 编译
    gcc args.c -o args
  2. 运行:尝试传入不同的参数。
    ./args
    ./args hello world
    ./args -l -a --verbose

输出示例 (./args hello world):

Program name: ./args
Total arguments: 3
Arguments passed:
  argv[1] = hello
  argv[2] = world

使用系统调用

这是 Linux C 编程最强大也最核心的部分,系统调用是用户程序请求内核服务的接口,我们通常不直接调用系统调用,而是使用 C 标准库(如 glibc)提供的封装函数,因为它们更安全、更方便。

下面这个例子使用 fork()exec() 系列函数来创建一个子进程,并让子进程执行一个外部命令(ls -l),而父进程则等待子进程结束。

代码 (process_example.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>   // fork, exec, pid_t 等函数的头文件
#include <sys/wait.h> // waitpid 函数的头文件
#include <string.h>
int main() {
    pid_t pid; // 进程ID类型
    int status;
    printf("Parent process (PID: %d) is running...\n", getpid());
    // fork() 创建一个子进程
    // 如果成功,在父进程中返回子进程的PID,在子进程中返回 0
    // 如果失败,在父进程中返回 -1
    pid = fork();
    if (pid < 0) {
        // fork 失败
        perror("fork failed");
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        // --- 子进程代码块 ---
        printf("Child process (PID: %d) created. Executing 'ls -l'...\n", getpid());
        // execlp 会用 "ls -l" 命令替换当前子进程的映像
        // 执行成功后,execlp 不会返回
        // 如果失败,才会返回 -1
        execlp("ls", "ls", "-l", NULL);
        // 如果执行到这里,说明 execlp 失败了
        perror("execlp failed");
        exit(EXIT_FAILURE);
    } else {
        // --- 父进程代码块 ---
        printf("Parent process (PID: %d) is waiting for child (PID: %d) to finish...\n", getpid(), pid);
        // 父进程等待子进程结束
        // waitpid 会阻塞,直到指定的子进程状态改变
        // -1 表示等待任意子进程
        waitpid(pid, &status, 0);
        // 检查子进程的退出状态
        if (WIFEXITED(status)) {
            printf("Child process (PID: %d) exited with status: %d\n", pid, WEXITSTATUS(status));
        }
        printf("Parent process (PID: %d) finished.\n", getpid());
    }
    return 0;
}

代码解析

  • #include <unistd.h>: 包含了 POSIX 标准接口,如 fork, exec, pipe 等。
  • #include <sys/wait.h>: 包含了 waitpid 等与进程等待相关的函数。
  • pid_t pid: pid_t 是一个用于进程 ID 的数据类型。
  • fork(): 这是 Linux/Unix 中创建新进程的唯一方法,它会复制当前进程,创建一个几乎完全相同的子进程。
  • if (pid == 0): 这个 if-else 结构是 fork 的标准用法。pid == 0 的分支在子进程中运行。
  • execlp(...): exec 系列函数用于执行一个新程序,它会替换当前进程的映像,也就是说,子进程在调用 execlp 后,就不再是原来的 C 程序了,而是变成了 ls 命令。
    • p 后缀表示会在 PATH 环境变量中搜索程序。
    • 参数列表:execlp("要执行的程序", "argv[0]", "argv[1]", ..., NULL),最后一个参数必须是 NULL
  • waitpid(pid, &status, 0): 父进程调用它来挂起自己的执行,直到子进程终止。
  • WIFEXITED(status)WEXITSTATUS(status): 宏,用于从 waitpid 获取的 status 中解析子进程的退出状态。

编译与运行

  1. 编译
    gcc process_example.c -o process_example
  2. 运行
    ./process_example

输出: 你会看到 ls -l 命令的输出结果,穿插在父进程和子进程的打印信息中,具体输出会根据你当前目录的文件而变化。

Parent process (PID: 1234) is running...
Child process (PID: 1235) created. Executing 'ls -l'...
total 16
drwxr-xr-x 2 user user 4096 Oct 26 10:30 .
drwxr-xr-x 3 user user 4096 Oct 26 10:29 ..
-rwxr-xr-x 1 user user 8608 Oct 26 10:30 process_example
-rw-r--r-- 1 user user  123 Oct 26 10:30 process_example.c
Parent process (PID: 1234) is waiting for child (PID: 1235) to finish...
Child process (PID: 1235) exited with status: 0
Parent process (PID: 1234) finished.

总结与进阶

  • 使用 GDB 调试: 当程序出错时,使用 GDB 是必不可少的。
    gdb ./your_program

    在 GDB 中,你可以设置断点 (break main)、单步执行 (next, step)、查看变量 (print var_name) 等。

  • Makefile: 当项目变大,有多个源文件时,手动编译会变得很麻烦。Makefilemake 工具可以自动化编译过程。
  • 多线程: 使用 <pthread.h> 库可以编写多线程程序,充分利用多核 CPU。
  • 网络编程: 使用 <sys/socket.h> 等头文件可以进行 Socket 编程,开发客户端/服务器应用。

这些实例涵盖了 Linux C 编程的基础,从这些起点出发,你可以探索更广阔的领域,如系统编程、驱动开发、内核模块等,Linux 为 C 语言程序员提供了一个强大而灵活的平台。

-- 展开阅读全文 --
头像
delay函数在C语言中如何正确使用?
« 上一篇 今天
dede管理员密码如何重置?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]