Linux下C语言教程-李慧芹老师-第一章

配套代码笔记Github地址

目录

第一章 绪论

课程地址,史上最强最细腻的linux嵌入式C语言学习教程【李慧芹老师】_哔哩哔哩_bilibili

第一节

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位的redhat6vimgcc4.4.6(make)
  • 本人:WSL-debianvscode(remote ssh)gcc12.2.0(make)ohmyzsh(theme:eastwood)

我的gcc版本比较新,所以很多提示比较完善,老师这个课程是很早的课,那个时候的gcc提示没有现在厉害,所以还是要结合老师的视频的思路,在当时提示不完善的时候是如何手撕代码分析出来的。

第二节

神一般的Hello world!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//hello.c
#include <stdio.h>
#include <stdlib.h>

#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得看编译器环境,目前在linuxgcc下,int main(void);常用,需要传参用int main(int argc, char **argv);

源文件到可执行文件

gcc

C源文件=>预处理=>编译=>汇编=>链接=>可执行文件

所有#后面的代码都在预处理解决

1
2
3
4
5
6
7
8
9
10
11
12
# 单步执行
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

1
2
3
4
5
$ make hello
cc hello.c -o hello
# cc就是make选择的编译器,这里是gcc
$ ls
hello hello.c

vim

老师对于常用的.vimrc做了一些介绍,笔者建议vscoderemote-ssh插件,可以在win的vscode编辑器享受linux的环境。

第三节

基本概念

Hello world为例对写程序的思路提出如下要求

1. 头文件正确包含的重要性
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

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的警告!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 通过 -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 ‘<stdlib.h>’ or provide a declaration of ‘malloc’
1 | #include <stdio.h>
+++ |+#include <stdlib.h>
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 ‘<stdlib.h>’ 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语言程序往往如果能把警告都消除,错误也能解决。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main()
{
FILE *fp;

fp = fopen("tmp", "r");
if (fp == NULL)
{
fprintf(stderr, "fopen():%s\n", strerror(errno));
exit(1);
}
puts("ok!");
exit(0);
}

这个程序运行报段错误,这个时候,查看一下警告就是问题所在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ ./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库。加入这个库重新运行。

1
2
3
4
[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的程序:

1
2
3
4
[main][~/LinuxC/Chapter1/Section3]$ ./hello
Hello world!
[main][~/LinuxC/Chapter1/Section3]$ echo $?
0

如果不带return 0

老师演示的返回值是13,是printf的返回的Hello world!\n的长度。

在我本地无法复现,新版本可能改了。

5. 多用空格空行
6. 添加注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//单行注释

/*
* 多行注释
* 多行注释
* 多行注释
*/

//大段的注释
#if 0
func(){

}
#endif

算法

解决问题的方法。(流程图,NS图,FSM有限状态机)

程序

用某种语言实现算法

进程

防止写越界,防止内存泄漏,谁打开谁关闭,谁申请谁释放


Linux下C语言教程-李慧芹老师-第一章
http://sinlatansen.github.io/2024/03/10/Linux下C语言教程-李慧芹老师-第一章/
作者
fugu
发布于
2024年3月10日
许可协议