一、windows与linux差异?
1、从目录架构角度分析。
windows架构是一个容器,文件夹与文件夹之间存在大小包含关系。
linux架构是一颗树,目录与目录之间存在索引关系。
2、从操作方式分析。
windows系统以图形界面进行交互。 -> 只需要使用鼠标进行点击
linux系统以命令行方式进行交互。 -> 每一个动作,都是一个命令。
所以说,要操作Linux系统,首先要知道一些linux命令。
二、在linux下使用命令来操作这个系统,那么这些命令是写在哪里的?
命令写在命令行上,而命令行是在一个终端上,所以说首先我们需要打开一个终端。
1、如何打开一个终端。
组合键:"ctrl + alt + T"
放大字体:" ctrl + shift + "+" "
缩小字体:" ctrl + "-" "
2、在终端上就会显示一个命令行。
这个命令行其实由一个程序产生的,在我们打开终端后,终端上方默认执行一个bash程序,这个bash程序就会产生一个命令行。
gec@ubuntu:~$ agsdhvasdsadf -> 命令是写命令行后面(输入完按回车)
agsdhvasdsadf: command not found -> 结果:命令行没法识别该命令,所以提示命令每找到。
3、这个命令行由什么东西组成?
gec@ubuntu:~$
gec -> 用户名
@ -> 分隔符,用于分隔用户名与主机名
ubuntu -> 主机名
: -> 分隔符,用于分隔主机名与路径名
~ -> 当前所在的路径
$ -> 身份 $ -> 普通用户 # -> 超级用户
三、学习一些linux简单命令。
1、 根目录与家目录分别在哪里?
家目录 -> ~ -> /home/gec
根目录 -> /
2、 学习几个比较简单命令。
1)pwd(print working diretcory) -> 打印当前工作路径
gec@ubuntu:~$ pwd
/home/gec
gec@ubuntu:/$ pwd
/
2)cd(change diretcory) -> 改变工作路径
方法一: cd + 绝对路径
什么是绝对路径?
以"/"根目录开始,一层一层目录地往下写。
/home/gec -> 根目录下的home目录下的gec目录
/lib -> 根目录下的lib目录
/mnt -> 根目录下的mnt目录
例子: 当前我在家目录,我想去根目录下的lib目录,怎么去?
目标: /lib
命令: cd /lib
方法二:cd + 相对路径
什么是相对路径?
就是相对于当前的目录而言,这个目标位置在哪里?
例子:当前我在家目录,我想去根目录下的lib目录,怎么去?
这个lib目录相对于当前目录而言,在哪里?
在当前目录的上一级目录的上一级目录的lib目录
./ ../ ../ lib
. -> 当前目录
.. -> 上一级目录(父目录)
命令: cd ./../../lib
练习1: 假设当前在home目录,想切换到家目录下的Downloads目录,请问用以上两种办法如何切换?
Downloads目录绝对路径: /home/gec/Downloads
cd /home/gec/Downloads
Downloads目录相对路径: ./gec/Downloads 等价于 gec/Downloads
cd ./gec/Downloads
3)ls(list) -> 列出某一个目录的文件名
gec@ubuntu:~$ ls -> 单独的一个ls就会默认列出当前目录下的文件名。(不包括隐藏文件)
等价于
gec@ubuntu:~$ ls .
gec@ubuntu:~$ ls .. -> 列出当前目录下的上一级目录的内容
gec@ubuntu:~$ ls / -> 列出根目录下的内容
gec@ubuntu:~$ ls -a -> 列出当前目录下所有文件(包括隐藏文件)
四、嵌入式学习大纲。
分开6个技术模块去学习,基于C/C++开发。
前4个阶段 -> 软件开发
C -> C语言、linux、GEC6818平台、IO操作、数据结构。
-> 通信方式,进程/线程、网络。
C++ -> C++语法,QT使用。
-> 在QT平台上去实现音视频编程,数据库,串口通信
后2个阶段 -> 硬件开发
C -> STM32 -> 裸机开发
-> GEC6818 -> 驱动开发
五、C语言学习大纲。
1、main函数使用事项、变量的定义、赋值、数据类型、数据类型在内存中意义,运算符号。
2、ASCII码、表达式,语句,逗号表达式,三目运算,控制流。
3、函数意义,调用,声明,定义,函数形参与实参的关系,返回值、函数书写规则,函数名定义,函数调用返回的位置。
4、特殊函数用法:递归函数,回调函数,内联函数、变参函数。
5、数组定义、数组赋值、数组下标、整型数组、字符数组、指针数组、二维数组。
6、指针定义、指针赋值、指针解引用、空指针,野指针,通用类型指针,整型指针,字符指针,二级指针,数组指针,函数指针,const指针。
7、结构体定义、结构体变量、结构体指针、结构体变量与指针如何访问成员,如何计算结构体在内存中占用的字节数,结构体数组。
8、联合体使用、枚举类型,宏定义,头文件书写,条件编译,拆分多个.c文件,编译过程。
9、堆空间的申请与释放,字符串函数使用。
六、C语言程序框架。
1、C语言程序入口:main函数(主函数) -> main() -> 程序一定是从main函数开始执行。
特点:
1)程序必须以main作为主函数的命名。
2)在程序中,main函数可以在任意的位置,都是被第一个执行的,并不是说第一个函数就会被第一个执行。
3)main函数有且仅有一个
2、main函数的框架:
main() -> main函数的函数头
{ -> main函数的函数体
/* 需要实现的内容写在这里就可以 */
}
3、在linux下,任何一个函数就像一个任务,任务都会有返回值。 -> 函数的执行结果。
返回值类型? -> 执行结果的类型
int -> 0/1/10/20
char -> 'x','a','z'
float -> 3.14..
1)写法?
写在main函数的函数头的前面即可。
返回值类型 main()
一般而言,main函数返回值都是int类型,正常退出就返回0,异常退出就返回-1
int main() -> 无论将来这个main函数执行成功,还是失败,都会返回一个int类型的数据。
{
}
2)怎么返回? -> return语句。
int main()
{
....;
....;
return 0; //程序正常退出
....; // 一定不会执行
}
注意:
return后面的值的类型必须与返回值类型一样。 (0->int)
在程序中,只要执行了return语句,那么就代表程序已经结束。
4、在linux下运行程序时,往往通过命令行给main函数传递参数。
1)main函数头如何写?
int main()
int main(void) -> 默认即使传递了参数来main函数,main函数也不接收。
正确写法:需要两个参数来接受这些参数。
int argc -> argument count -> 参数的数目 -> 也就是说这个argc参数可以统计一共接受了多少个参数。
-> 你传递了2个参数,那么这个argc就等于2。
char *argv[] -> argument value -> 参数的值 -> 也就是说这个argv参数可以储存这些参数的值。
-> 你传递了aaa的参数过来,那么argv就可以保存着aaa这个参数的值。
int main(int argc,char *argv[])
2)命令行是如何传递参数的?
例如: 执行当前目录下main_test这个程序,命令行如何传递参数?
./main_test aaa bbb ccc -> 所有的参数都要使用空格来分开
3)那么这些参数跟argc与argv关系?
例子:
./xxx aaa -> 其实就等价于给argc与argv赋值 argc=2 argv[0]="./xxx" argv[1]="aaa"
./xxx aaa bbb -> 其实就等价于给argc与argv赋值 argc=3 argv[0]="./xxx" argv[1]="aaa" argv[2]="bbb"
./xxx aaabbb -> 其实就等价于给argc与argv赋值 argc=2 argv[0]="./xxx" argv[1]="aaabbb"
5、头文件
1)程序中一定要写头文件吗?
不一定要。当我们在程序中,调用一个函数之前,必须先声明该函数,有些函数声明语句写在头文件中,当我们调用一些函数时不需要声明该函数,只需要包含这个函数对应的头文件就可以。换句话说,如果程序中没有调用任何的函数,也就是不需要声明任何的函数,头文件就不需要包含了。
2)头文件作用。
对函数的声明函数,所以在调用函数之前一定要包含头文件。
3)函数对应的头文件在哪个,不需要背,只需要通过手册(新华字典)去查询即可。
如果说遇到函数的头文件不知道哪一个,怎么查? -> printf()
命令公式: man 函数对应的手册数 函数名
gec@ubuntu:~$ man 3 printf -> man: 使用man手册
3: 代表查看库函数 (printf属于标准C库中的函数)
printf: 代表你需要插看的内容
(按'q'退出查看man手册)
SYNOPSIS -> 使用格式
#include <stdio.h> -> 也就是说你的程序中使用了printf(),那么就一定要包含#include <stdio.h>
6、注释。 (注释不一定要写的,注释:精简,易懂)
//.....; -> 单行注释
/* -> 多行注释
....;
....;
*/
7、缩进与空行
1)每一个复合语句都需要进行缩进。
int main()
{ -> 属于第一个复合语句
for()
{ -> 属于第二个复合语句
for()
{ -> 属于第三个复合语句
}
}
}
2)什么时候需要空行?
头文件与main函数之间。
模块与模块之间。
return语句之前。
---------------------------------------
#include <stdio.h>
int main(int argc,char *argv[])
{
/* 以下的两个函数实现A模块 */
funA1(); //实现功能A函数接口1
funA2(); //实现功能A函数接口2
/* 以下的函数实现B功能 */
funB1(); //实现功能B函数接口1
return 0;
}
----------------------------------------
8、编译程序。
1)为什么要进行编译?
xxxx.c 编译器 xxxx
C语言程序 ------> 可执行程序 (二进制代码)
人类懂 人类不懂
机器不懂 机器懂
2)编译过程做了什么事情?
其实就是检查这个C语言程序中语法是否正确。
编译完后,你可能会得到三种结果:
编译通过:不会出现任何的提示,代表编译通过,正常生成一个可执行程序。
编译警告:会出现提示,提示前面有一个明显warning,但是还是能够正常生成一个可执行程序。 ->例如: 没包头文件
没有包含头文件警告:
warning: implicit declaration of function ‘printf’
编译出错:会出现提示,提示前面有一个明显error,不能够正常生成一个可执行程序。 ->例如:缺少了一个;
error: expected ‘;’ before ‘return’
3)编译器是什么?
gcc
4)如何编译程序?
第一步: 在linux下切换到.c文件的所在地
cd /mnt/hgfs/GZ2057/01 C语言/02/code
第二步: 使用命令编译。
gec@ubuntu:/mnt/hgfs/GZ2057/01 C语言/02/code$ gcc project.c -o project
第三步: 看看程序生成了没有?
gec@ubuntu:/mnt/hgfs/GZ2057/01 C语言/02/code$ ls
project project.c
9、执行程序。
./xxxx
七、编写代码,验证以上的结论。
安装windows编程软件: npp.7.5.8.Installer.exe
1、设置windows与linux的共享目录。
1)在windows上确定好哪一个是共享目录。
E:\GZ2057
2)在Ubuntu中设置该目录为共享目录。
虚拟机 -> 设置 -> 选项 -> 共享文件夹 -> 总是启用 -> 添加 -> 下一步 -> 主机路径: E:\GZ2057 -> 下一步 -> 完成 -> 确定
3)使用cd命令切换到共享目录所在地
家目录所在地: /home/gec/
根目录: /
共享目录所在地:/mnt/hgfs/
gec@ubuntu:~$ cd /mnt/hgfs/
gec@ubuntu:/mnt/hgfs$ ls
GZ2057 -> 如果能看到GZ2057,说明共享成功
-> 如果输入ls,没有看到任何的东西,只需要重启虚拟机就可以。
2、创建一个工程,并编辑这个工程。
在E:\GZ2057\01 C语言\02\code\中创建一个工程,叫project.c。
右键选择这个文件,选择Edit with Notepad++
练习2: 设置好共享文件夹。
练习3: 写一个程序,实现无论输入多少个参数,都可以打印所有的参数。
#include <stdio.h>
int main(int argc,char *argv[]) // ./xxx aaa
{
int i;
for(i=0;i<argc;i++)
{
printf("argv[%d]:%s\n",i,argv[i]);
}
return 0;
}
八、数据类型。
1、什么是数据类型?
数据类型描述了一个变量究竟存放着什么数据。
数据类型分为基本数据类型与非基本数据类型。
基本数据类型:char short int long float double。
非基本数据类型:数组、指针、结构体
2、研究一下基本数据类型在内存中占用的空间问题?
例子:假设有一个整型变量,那么这个变量在内存中占用多少个字节?
看这个变量对应的数据类型是占用多少个字节。
等价于:
有以下的程序,请问在运行程序的过程中占用内存多少个字节?
int main(int argc,char *argv[])
{
int a;
return 0;
}
sizeof() -> 计算内存占用字节的大小。
sizeof(char) -> 计算一个char类型的数据在内存中占用多少个字节数。
#include <stdio.h>
int main(int argc,char *argv[])
{
printf("sizeof(char) = %ld\n",sizeof(char));//1
printf("sizeof(short) = %ld\n",sizeof(short));//2
printf("sizeof(int) = %ld\n",sizeof(int));//4
printf("sizeof(long) = %ld\n",sizeof(long));//8
printf("sizeof(float) = %ld\n",sizeof(float));//4
printf("sizeof(double) = %ld\n",sizeof(double));//8
return 0;
}
结论: 基本数据类型占用空间的大小由编译系统来决定的。
九、如何定义变量?
1、定义公式: 数据类型 变量名
数据类型: 从基本数据类型中选择,也可以从非基本数据类型中选择。
变量名:有一套规则。
1)只能由字母,数字,下划线组成。 int a+5
2)不能以数字开头。 int 5_a
3)不能与系统的关键字重名 int If (对) int if (错)
例子1: 定义一个整型变量,名字为x。
int x;
例子2: "int x"这句话是什么含义?
在内存空间中连续申请4个字节的空间,然后使用变量x间接访问这片内存空间。
int main(int argc,char *argv[])
{
int x; -> 申请了连续4个字节空间。
return 0; -> 程序结束就会释放空间。
}
2、内存分配原则? -> 连续空闲不确定。
1)在分配内存时,内存地址一定是连续。
2)在分配内存时,一定是空闲。(之前的变量申请过的空间就不会再被申请到)
3)分配内存时,位置是不确定。
十、变量的赋值,作用域,生命周期。
1、变量的赋值。
使用"="来对变量进行赋值,"="的作用把"="右边的值赋值给"="左边的值。
1)定义变量的同时初始化。
int x = 100; -> x不会出现随机值。
2)先定义,后初始化。
int x; -> x = 随机值
x = 100; -> x = 100
2、变量的生命周期与作用域。
生命周期:这个变量从什么时候开始出现在内存空间到什么时候从内存空间中释放这个过程。
作用域:在程序中,这个变量能够作用到的地方。
局部变量 Vs 全局变量
1)什么是局部变量?什么是全局变量?
在程序函数体内部定义的变量就是局部变量,在函数体外定义的变量就是全局变量。
int x; -> 全局变量
int main(int argc,char *argv[])
{
int a; -> 局部变量
}
2)两者在内存空间中申请的位置区别?
局部变量申请的空间位置,一定在栈区。
全局变量未初始化过就是在bss段,已初始化过就是在data段。
int c = 10; -> c在data段,10是常量区
int d; -> d在bss段
int main(int argc,char *argv[])
{
int a = 100; -> a在栈区 100在常量区
int b; -> b在栈区
return 0;
}
3)初始化值
局部变量: 随机值
全局变量: 0
4)生命周期
局部变量在函数中定义时开始,在定义的函数返回时,就会释放这个空间。
全局变量一开始就会申请,等到程序结束才会释放。
5)作用域
局部变量:只能在定义该变量的那个函数中使用。
全局变量:整个程序中所有的函数都可以使用。
思考题?
1、形式参数"int x"是属于局部变量还是全局变量?
属于局部变量,所以需要申请空间,还有就是在函数结束时会释放。
int fun(int x) //x = 10
{
x -> 就是局部变量
int y;
}
int main()
{
fun(10);
}
2、能不能在不同的函数中定义相同的变量名?
可以。
int fun()
{
int y;
}
int main()
{
int y;
}
3、全局变量可以跟局部变量同名吗?
可以重名。如果重名,打印出来的值就是局部变量。
4、全局变量作用域只能往下,不能网上。
练习4: 请求出以下程序的结果。 (考点: 局部变量的生命周期)
int my_fun(int c)
{
c = c/5;
return c;
}
int fun(int a,int b)
{
int c;
c = a + b;
my_fun(c);
return c;
}
int main(int argc,char *argv[])
{
int a = 10,b = 5;
int ret = fun(a,b);
printf("ret = %d\n",ret); //15
return 0;
}
十一、运算符号。
+ - * / % = & && | || == != ++ -- += -= *= /= %=
1)把浮点型赋值给整型变量,那么精度就会降低。(把小数点后面的数据弄丢了)
2)
int c = 5/2;
printf("c = %d\n",c);//2
float e;
e = 5/2;
printf("e = %f\n",e);//2.000000
float f;
f = 5.0/2;
printf("f = %f\n",f);//2.500000
float g;
g = 5/2.0;
printf("g = %f\n",g);//2.500000 (对)
//2.000000 (错)
float h;
h = 5.0/2.0;
printf("h = %f\n",h);//2.500000
int i;
i = 5.0/2.0;
printf("i = %d\n",i);//2
3)%两边不可以由小数点。
4)& -> 位与运算
5&6
5 -> 0101
6 -> & 0110
----------------------
0100 -> 4
&& -> 逻辑与运算 -> 非0即真
5&&6
5 -> 非0 -> 真
6 -> 非0 -> 真
| -> 位或运算
5|6
5 -> 0101
6 -> | 0110
==========================
0111 -> 7
||
5||6
5 -> 非0 -> 真
6 -> 非0 -> 真