# 目录 - [目录](#目录) - [第一章 绪论](#第一章-绪论) - [第一节](#第一节) - [C语言发展史](#c语言发展史) - [C语言特点](#c语言特点) - [C语言学习建议](#c语言学习建议) - [课程思路](#课程思路) - [课程平台](#课程平台) - [第二节](#第二节) - [神一般的`Hello world!`](#神一般的hello-world) - [源文件到可执行文件](#源文件到可执行文件) - [gcc](#gcc) - [make](#make) - [vim](#vim) - [第三节](#第三节) - [基本概念](#基本概念) - [以`Hello world`为例对写程序的思路提出如下要求](#以hello-world为例对写程序的思路提出如下要求) - [1. 头文件正确包含的重要性](#1-头文件正确包含的重要性) - [2. 以函数为单位来进行程序编写](#2-以函数为单位来进行程序编写) - [3. 声明部分+实现部分](#3-声明部分实现部分) - [4. `return 0/exit(0)`](#4-return-0exit0) - [5. 多用空格空行](#5-多用空格空行) - [6. 添加注释](#6-添加注释) - [算法](#算法) - [程序](#程序) - [进程](#进程) - [防止写越界,防止内存泄漏,谁打开谁关闭,谁申请谁释放](#防止写越界防止内存泄漏谁打开谁关闭谁申请谁释放) # 第一章 绪论 课程地址,[史上最强最细腻的linux嵌入式C语言学习教程【李慧芹老师】_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV18p4y167Md/?spm_id_from=333.999.0.0&vd_source=4e03f52e94cfa281cde032856b1f93a7)。 ## 第一节 ### C语言发展史 | 时间 | 发展 | | ---- | -------------------- | | 1960 | 原型A语言->ALGOL语言 | | 1963 | CPL语言 | | 1967 | BCPL | | 1967 | B语言 | | 1973 | C语言 | ### C语言特点 1. 基础性语言 2. 语法间接、紧凑、方便、灵活 3. 运算符,数据结构丰富 4. 结构化,模块化编程 5. 移植性好,执行效率高 6. 允许直接对硬件操作 ### C语言学习建议 1. 概念的正确性 2. 动手能力 3. 阅读优秀的程序段 4. 大量练习,面试题 ### 课程思路 1. 基础概念 2. 数据类型,运算符和表达式 3. 输入输出专题 4. 流程控制 5. 数组 6. 指针 7. 函数 8. 构造类型 9. 动态内存管理 10. 调试工具(gdb,make) 11. 常用库函数 ### 课程平台 * 老师:64位的`redhat6`,`vim`,`gcc4.4.6(make)` * 本人:`WSL-debian`,`vscode(remote ssh)`,`gcc12.2.0(make)`,`ohmyzsh(theme:eastwood)` 我的`gcc`版本比较新,所以很多提示比较完善,老师这个课程是很早的课,那个时候的gcc提示没有现在厉害,所以还是要结合老师的视频的思路,在当时提示不完善的时候是如何手撕代码分析出来的。 ## 第二节 ### 神一般的`Hello world!` ```c //hello.c #include #include #if 0 void main(void); void main(int argc, char **argv);// char *argv[] int main(int argc, char **argv); int main(void); #endif int main(void) { printf("Hello world!\n"); exit(0); } ``` 用那种`main`得看编译器环境,目前在`linux`的`gcc`下,`int main(void);`常用,需要传参用`int main(int argc, char **argv);`。 ### 源文件到可执行文件 #### gcc C源文件=>预处理=>编译=>汇编=>链接=>可执行文件 > 所有`#`后面的代码都在预处理解决 ```bash # 单步执行 gcc -E hello.c > hello.i # 预处理生成hello.i gcc -S hello.i # 编译生成hello.s gcc -c hello.s # 汇编生成hello.o gcc hello.o -o hello # 链接生成hello ./hello # 运行 Hello world! # 一次到位 gcc hello.c # 得到a.out可执行文件 # 指定名字 gcc hello.c -o myhello # 得到myhello可执行文件 ``` #### make ```bash $ make hello cc hello.c -o hello # cc就是make选择的编译器,这里是gcc $ ls hello hello.c ``` ### vim 老师对于常用的`.vimrc`做了一些介绍,笔者建议`vscode`的`remote-ssh`插件,可以在win的vscode编辑器享受linux的环境。 ## 第三节 ### 基本概念 #### 以`Hello world`为例对写程序的思路提出如下要求 ##### 1. 头文件正确包含的重要性 ```c #include int main(void) { int *p = NULL; int i; p = malloc(sizeof(int)); if (p == NULL) return -1; printf("Hello world!\n"); return 0; } ``` 这里我的gcc版本比较新,所以和老师的不一致,总之老师的意思就是 > 不要忽略gcc的警告!!! ```bash # 通过 -Wall 参数让gcc显示全部警告 # 注意'W'要大写 $ gcc hello.c -Wall hello.c: In function ‘main’: hello.c:7:9: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration] 7 | p = malloc(sizeof(int)); | ^~~~~~ hello.c:2:1: note: include ‘’ or provide a declaration of ‘malloc’ 1 | #include +++ |+#include 2 | hello.c:7:9: warning: incompatible implicit declaration of built-in function ‘malloc’ [-Wbuiltin-declaration-mismatch] 7 | p = malloc(sizeof(int)); | ^~~~~~ hello.c:7:9: note: include ‘’ or provide a declaration of ‘malloc’ hello.c:6:9: warning: unused variable ‘i’ [-Wunused-variable] 6 | int i; | ^ ``` * 例如说这个变量`i`定义了但是没用上,就是你清楚来龙去脉可以忽略的警告。 * 而`malloc`那个警告就是在告诉你`malloc`所属的`stdlib.h`库未引入。 * C语言程序往往如果能把警告都消除,错误也能解决。例如: ```c #include #include #include int main() { FILE *fp; fp = fopen("tmp", "r"); if (fp == NULL) { fprintf(stderr, "fopen():%s\n", strerror(errno)); exit(1); } puts("ok!"); exit(0); } ``` 这个程序运行报段错误,这个时候,查看一下警告就是问题所在。 ```bash $ ./a [1] 1960 segmentation fault ./a $ gcc a.c -Wall a.c: In function ‘main’: a.c:12:41: warning: implicit declaration of function ‘strerror’; did you mean ‘perror’? [-Wimplicit-function-declaration] 12 | fprintf(stderr, "fopen():%s\n", strerror(errno)); | ^~~~~~~~ | perror a.c:12:35: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=] 12 | fprintf(stderr, "fopen():%s\n", strerror(errno)); | ~^ ~~~~~~~~~~~~~~~ | | | | | int | char * | %d ``` 用`%s`需要的类型是`char *`,但是`strerror(errno)`的类型是`int`,它是所以是`int`,是因为C语言对没有找到原型的函数返回值都是`int`,所以根源在于`strerror`函数没有原型,没有引入需要的`string.h`库。加入这个库重新运行。 ```bash [main][~/LinuxC/Chapter1/Section3]$ make a cc a.c -o a [main][~/LinuxC/Chapter1/Section3]$ ./a fopen():No such file or directory ``` ##### 2. 以函数为单位来进行程序编写 main`是特殊的定义,其实就是一个正在运行的线程。其实对于内核而言,是只有进程的概念,且与我们理解的进程、线程不一样。 ##### 3. 声明部分+实现部分 早期的编译器要求变量先定义后使用。 ##### 4. `return 0/exit(0)` 结束当前进程,是给父进程看的。 对于带有`return 0`的程序: ```bash [main][~/LinuxC/Chapter1/Section3]$ ./hello Hello world! [main][~/LinuxC/Chapter1/Section3]$ echo $? 0 ``` 如果不带`return 0`: 老师演示的返回值是13,是`printf`的返回的`Hello world!\n`的长度。 在我本地无法复现,新版本可能改了。 ##### 5. 多用空格空行 ##### 6. 添加注释 ```c //单行注释 /* * 多行注释 * 多行注释 * 多行注释 */ //大段的注释 #if 0 func(){ } #endif ``` #### 算法 解决问题的方法。(流程图,NS图,FSM有限状态机) #### 程序 用某种语言实现算法 #### 进程 #### 防止写越界,防止内存泄漏,谁打开谁关闭,谁申请谁释放