我的学习之旅:理解 C 语言
社区文章 发布于 2025 年 3 月 9 日
大家好!我刚开始学习 C 语言编程,我想通过分解这个程序来记录我的学习旅程。这些代码来自 alex the dev,我只是在代码中添加注释以理解发生了什么。目前我正在学习 C 语言的第五章,如果你想比较的话。格式化感谢 Copilot。
1. 引入必要的库
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
我学到了什么:
stdlib.h
:
提供动态内存分配函数(`malloc`、`realloc`、`free`)。stdio.h
:
包含输入/输出操作函数,如 `printf`、文件操作(`fopen`、`fread`、`fclose`)。string.h
:
提供字符串处理函数,如 `strcmp`(用于比较字符串)和 `memcpy`(用于复制内存)。
2. 定义一个结构体来保存参数
typedef struct arguments {
char **files;
unsigned int files_count;
} arguments;
- 结构体(`struct`)在 C 语言中用于将相关变量组合在一起。
- 结构体成员
char **files
:
这是一个双指针。- 一个 `char *` 表示一个字符串(字符数组)。
- 一个 `char **` 表示一个字符串数组,意味着它可以保存多个文件名。
unsigned int files_count
:
跟踪已提供的文件名数量。使用 `unsigned int` 确保该数字永远不会是负数。
3. 解析命令行参数
void parse_arguments(int argc, char **argv, arguments *args) {
args->files = malloc(argc * sizeof(char *));
int index = 0;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--help") == 0) {
printf("Usage: ./main [file1] or [--help]
");
exit(0);
} else {
args->files[index] = argv[i];
index++;
}
}
args->files_count = index;
}
我学到了什么:
- 函数参数
int argc
:命令行参数的数量。char **argv
:字符串数组,其中每个字符串都是一个命令行参数。arguments *args
:指向我们的 `arguments` 结构体的指针,以便函数可以修改它。
- 动态内存分配
args->files = malloc(argc * sizeof(char *));
这里我们为指针数组分配内存。使用 `->` 运算符是因为 `args` 是一个指向结构体的指针。它是 `(*args).files` 的简写。
- 循环遍历参数
- 我们从索引 `1` 开始(因为 `argv[0]` 是程序名称)。
- 如果参数是 `"--help"`,程序会打印帮助消息并退出。
- 其他参数被假定为文件名并存储在 `files` 数组中。
- 存储文件计数
- 循环结束后,存储的文件名数量保存到 `args->files_count` 中。
4. 将文件读入内存
#define MAX_LEN 128
int read_file(char *path, char **buffer) {
int tmp_capacity = MAX_LEN;
char *tmp = malloc(tmp_capacity * sizeof(char));
int tmp_size = 0;
if (tmp == NULL) {
perror("Memory allocation error");
exit(1);
}
FILE *f = fopen(path, "r");
if (f == NULL) {
perror("File opening error");
exit(1);
}
int size = 0;
do {
if (tmp_size + MAX_LEN > tmp_capacity) {
tmp_capacity *= 2;
tmp = realloc(tmp, tmp_capacity * sizeof(char));
if (tmp == NULL) {
perror("Memory allocation error");
exit(1);
}
}
size = fread(tmp + tmp_size, sizeof(char), MAX_LEN, f);
tmp_size += size;
} while (size > 0);
fclose(f);
tmp[tmp_size] = '\0';
*buffer = tmp;
return tmp_size;
}
我学到了什么:
- 定义常量
#define MAX_LEN 128
设置从文件中读取的块大小。
- 文件内容的内存分配
- 最初,分配一个大小为 `MAX_LEN` 的缓冲区 `tmp`。
- 如果读取文件时需要更多空间,则使用 `realloc` 将缓冲区大小加倍。
- 文件操作
- 使用 `fopen` 打开文件。如果打开失败,则打印错误。
- 使用 `fread` 分块读取文件,指针算术(`tmp + tmp_size`)确保新数据正确追加。
- 缓冲区终止
- 读取后,关闭文件并添加空终止符(`\0`)以标记字符串的结尾。
- 通过 `*buffer` 返回指向已分配缓冲区的指针。
5. 主函数:将所有内容整合
int main(int argc, char **argv) {
arguments args = {0};
parse_arguments(argc, argv, &args);
char *buffer = NULL;
int buffer_size = 0;
for (int i = 0; i < args.files_count; i++) {
char *content = NULL;
int size = read_file(args.files[i], &content);
buffer = realloc(buffer, buffer_size + size + 1);
memcpy(buffer + buffer_size, content, size);
buffer_size += size;
free(content);
}
printf("%s\n", buffer);
free(buffer);
free(args.files);
return 0;
}
🚀 最终思考
在记录这个程序的过程中,我真的学到了很多!
如果你也在学习 C 语言,希望这能有所帮助。如果你有任何问题(或者我解释错了 😅),请告诉我!
编程愉快!🎉