要求:
- 认真听讲,不能玩手机;
- 记笔记(记自己不会的);
- 早睡早起:不要熬夜;
- 练习(上课敲得代码:至少三遍);
- 遇到问题:自己先思考;
注意:!!!关闭虚拟机的时候:不能直接点击右上角的×去关闭!!!点击
:可以选择暂停虚拟机或者关闭虚拟机
Day1:
- 编程环境的介绍
- Linux常用命令
- Vim编辑器
- Gcc编译器
1、编程环境的介绍
虚拟机、ubuntu(linuxos)
虚拟机:虚拟出来的一台pc机
为什么要是用linuxos?
嵌入式:以计算机技术为基础,软硬件可裁剪(软件控制硬件)(智能小车)
裁剪:修改
为什么要修改:根据用户的需求;
软件的裁剪:linuxos
目录结构
Windows目录结构:倒置的森林
Linuxos:目录结构:倒置的树
Linuxos下:一切皆文件
/:根目录:根目录是linuxos的顶层目录:一切文件都从他开始,都在他之下
什么是家目录:用户所在的路径;
home是不是家目录?
小写的home不是家目录;home之下才是我们的家目录
家目录又称为:工作目录:主目录:HOME:~;
在家目录之上:普通用户没有操作权限!
解决方法:
1、在命令前+sudo(给你一次管理员的权限)
2、先切换为超级用户:sudo su(永久操作); 退出超级用户:exit
普通用户:$ 超级用户:#
3、linux的常用命令
命令格式:命令 [选项] [参数]
注意:
- 【】表示可以省略:选项:功能 参数:操作的对象
- 以上三者用空格隔开
在哪里去输入命令:终端
终端:人机交互的界面
打开一个终端:
- 点击终端图标
- Ctrl+shfit+n:打开一个和当前终端相同路径的终端
- Ctrl+alt+t:打开一个路径为家目录的终端
清屏:
- ctrl+l
- Clear
放大:ctrl+shift+‘+’
缩小:ctrl+‘-’
上下箭头:查看历史命令
自动补全键:TAB键
结束正在运行的代码:Ctrl+c
命令提示符:
用户名@主机名:当前的路径 用户权限
$:普通用户 #:超级用户
pwd:查看当前所在的绝对路径
ls: 查看当前路径下的内容
ls -a:查看当前路径下的所有内容(包含隐藏文件)
隐藏文件:以.开头的文件
. 当前路径
.. :上一级路径
ls -l:打印文件的详细属性
ls -la:打印当前路径下所有文件的详细属性
ls 路径:打印指定路径下的内容
ls:发现三种颜色:
白色:普通文件
蓝色:文件夹/目录
绿色:可执行文件
cd 路径:切换路径
绝对路径:以根目录开始的路径
相对路径:相对于当前所在的路径
cd :切换到家目录
cd - :回到上一次操作的路径
touch 文件名:创建文件,一次可以创建多个
rm 文件名:删除文件,一次可以删除多个(注意路径)!!!
mkdir 文件夹名:创建文件夹,一次可以创建多个
rmdir 文件夹名:删除空文件夹,一次可以删除多个
rm -r : 删除非空文件夹(删除前确认一下)
rm -ri: 删除文件夹,并一一提示
rm -rf: 删除文件夹,不提示
cp 源(文件/ -r 文件夹) 目的文件夹
mv
- 移动 mv 源文件/源文件夹 目的文件夹
- 重命名 mv 原来的名字 现在的名字(如果后面的不存在:那就是重命名的作用)
4、Vim编辑器
Vim 文件名;
如果文件存在,打开文件并进行编辑
如果文件不存在,创建文件并打开进行编辑
三种模式:
命令行模式:
命令行模式-----插入模式:i
命令行模式-----底行模式:shift+:
插入模式:
插入模式------命令行模式:esc
插入模式------底行模式:esc、shift+:
底行模式:
底行模式-----命令行模式:esc
底行模式-----插入模式:esc、i
底行模式:
w:保存
q:退出
wq:保存并退出
q!: 强制退出
wq!: 保存并强制退出
set nu: 显示行号
set nonu: 不显示行号
命令行模式:
yy:复制1行
nyy:复制n行
p:粘贴
dd: 剪切1行(剪切完毕如果不粘贴,那作用就为删除)
ndd:剪切n行
u:撤销
Ctrl+r:反撤销
Gcc编译器
Int()
{
Return 0;
}
void main()
{
不需要有返回值
}
main() //如果没有写返回值的数据类型,默认是整型int
{
Return 0;
}
编译:
- gcc 文件名生成一个名为a.out的可执行文件
执行:./a.out - gcc 文件名 -o 可执行文件名
-o:给可执行文件起一个名字
执行:./可执行文件名
注意:
解决方法:已经打开过1.c了,找到打开的1.c:删除
退出界面:q
赠送:
Printf的用法:
Printf(“格式控制串”,输出表);
格式控制串:原样输出的内容+格式化符(%d、%c、%f)
输出表:输出的内容(输出的内容要和格式化符一一对应!)
Day2:
- 计算机的基本结构
- 什么是程序
- 程序设计步骤
- 计算机的数据表示(进制转换)
- 基本数据类型(关键字(32个))
- 常量
1、计算机的基本结构
输入输出设备(键盘,显示器)
CPU处理器(控制器,运算器,寄存器)
存储器
程序
存储器:
内存:工作存储器,容量较小,读写速度快,掉电数据会丢失
外存:长期保存数据,容量较大,读写速度较慢,掉电数据不会丢失
寄存器:CPU内部存储器,容量最小,读写速度最快
2、什么是程序
程序:计算机能够识别的一组有序的指令
指令:计算机能够识别的操作
Hello.c 和a.out那个是程序?------a.out
3、程序设计步骤
Vim(编辑)--------->gcc(编译)------------>./可执行文件名(执行)
4、计算机的数据表示(进制转换)
分为:数值数据、非数值数据
4.1非数值数据(不能够直接进行算数运算的数据)
字符、图片、声音
‘a’ ‘b’
ASCII码表:规定了每一个字符以哪八位二进制数表示(1字节 == 8bir)
‘a’ == 97
‘A’ == 65
小写字符比大写字符大32--------(小写转大写:减32)
4.2 数值数据(可以直接进行算术运算的数据)
十进制、二进制、八进制、十六进制
十进制:逢十进1: 0~9构成
二进制:逢二进1: 0~1构成
八进制:逢八进1: 0~7构成
十六进制:逢十六进1: 0~9,a~f构成
为了区分不同的进制:我们给八进制前加0,十六进制前加0x(0X)
76(十进制) 076(八进制) 0x76(0X76)(十六进制)
(如果A-F是大写,X就要用写)
4.3进制转换:
其他进制转十进制:对应的数乘以对应的指数次幂之和
二进制转十进制:
八进制转十进制:
十六进制转十进制:0xaf4------- == 4*16^0+15*16^1+10*16^2 = 2804
十进制转其他进制:除以其他进制倒取余数
十进制转二进制: 除2倒取余 43-----------101011
十进制转八进制: 除8倒取余 43-----------053
十进制转十六进制:除16倒取余 43-----------0x2b
二进制与八进制之间的转换:
可以用3位二进制数表示一位八进制数
0~7-----------000~111
- -------------------000
- -------------------001
- -------------------010
- -------------------011
- -------------------100
- -------------------101
- -------------------110
- -------------------111
076---------------------------111 110
010 100 101-------------------0245
二进制和十六进制之间的转换:
可以用4位二进制数表示一个十六进制数
0~9,a~f(0~15)
0~15-------0000~1111
- ----------------0000
- ----------------0001
- ----------------0010
- ----------------0011
- ----------------0100
- ----------------0101
- ----------------0110
- ----------------0111
- ----------------1000
- ----------------1001
- ----------------1010
- ----------------1011
- ----------------1100
- ----------------1101
- ----------------1110
- ----------------1111
0xfca5----------------------1111 1100 1010 0101
0 1010 0101---------------0xa5
案例:
实现其他进制转为十进制:
1 1001 1110 ------------ 先转十六进制:0x19e---转十进制--14*16^0+9*16^1+1*16^2=414
06543---------------------转十进制:3*8^0+4*8^1+5*8^2+6*8^3= 3427
0xfadc---------------------转十进制:12*16^0+13*16^1+10*16^2+15*16^3= 64220
十进制转成二进制:先转8进制-------------01733------1 111 011 011
八进制和十六进制转换成二进制:
0xa865 0763
1010 1000 0110 0101 111 110 011
二进制转换成八进制和十六进制
110011101110
110 011 101 110----------06356
1100 1110 1110----------0xcee
5、基本数据类型
关键字:系统预先定义好的,有特殊含义的,并且都是小写,不能重复定义(32个)
数据类型:char、short、int、long、float、double、struct、enum、union、void
控制语句:if、else、switch、case、default、for 、do、while、break、continue、goto
存储类型:auto、static、extern、register
const:只读
return:返回函数
signed:有符号数
unsigned:无符号数
sizeof:计算所占内存空间的大小:单位(字节) sizeof(数据类型)//sizeof(变量名)
typedef:给已有的数据类型起别名;
volatile:防止编译器优化
标识符:程序员自己定义的,一般用来定义变量名,函数名,类型名
- 由数字、字母、下划线构成
- 第一个不能为数字
- 不能和关键字重名
(建议见名知意!!!)
基本数据类型:
32os:
字符型: char --- 1字节
整型: short-----2字节 int------4字节 long---4字节
浮点型:float-----4字节 double---8字节
64os:
字符型: char ---(1字节)
整型: short---(2字节) int ---(4字节) long---(8字节)
浮点型:float---(4字节) double---(8字节)
注意:每一种数据类型所占大小不一样的,作用是为了让你合理的分配内存空间
有符号数和无符号数:
Signed:有符号数
有符号数:有正数有负数
最高位用来表示符号位,0正1负
在计算机中:数据是以二进制的补码的形式存储的
正数:正数的原码,反码,补码都是一样的
- --------- 0000 1010(计算机中)
负数:
原码:最高位为符号位,其他位为数据位(直接转为二进制)
反码:原码的符号位不变,其他位取反(0变1,1变0)
补码:反码+1
-10---------- 1000 1010(原码)
-10---------- 1111 0101(反码)
-10---------- 1111 0110(补码)(计算机中)
知道一个数的补码:如何求原码?
1111 0110----------?
方法1:减1取反
减1-----1111 0110---------- 1111 0101
取反:---------------------------- 1000 1010------(-10)
方法2:补码的补码就是原码
1111 0110
取反:1000 1001
加1: 1000 1010----------(-10)
Unsigned:无符号数:只有正数
5.1字符型家族
值域范围
Char-----------1字节 == 8 bit
Unsigned char :0000 0000-----------1111 1111------(0~255)
Signed char :1000 0000------------0111 1111-----(-128~127)
补码:1 000 0000
1 111 1111
原码:1 1000 0000 (-128)
考点!!!(如果超范围:转圈数)
1、
Unsigned char c = 260; ------------ //1 0000 0100
printf(“%d\n”,c);---------------------//4
2、
Signed; --------------------------// 1000 0010(补码)
printf(“%d\n”,a);
补码:1000 0010
反码:
原码: 1 111 1110-------------(-126)
5.2 整型家族
值域:
Int整型:== 4字节== 32bit
Unsigned int:(0 ~ 2^32-1)
0000 0000 0000 0000 0000 0000 0000 0000--1111 1111 1111 1111 1111 1111 1111 1111
Signed int:(-2^31 ~ 2^31-1 )
1000 0000 0000 0000 0000 0000 0000 0000--0111 1111 1111 1111 1111 1111 1111 1111
Short:== 2字节== 16bit
Unsigned short:(0 ~ 2^16-1)
0000 0000 0000 0000--------------1111 1111 1111 1111
Signed short:(-2^15~ 2^15-1)(-32768~32767)
1000 0000 0000 0000---------------0111 1111 1111 1111
5.3 浮点型家族
浮点型的存储方式与正兴德存储方式不同
浮点型的存储方式决定了他不能够准确的表示一个数,只能近似的表示一个数
单精度浮点数:
float(4字节)---------保证6~7位有效数据(%f)(默认输出小数点后6位)
双精度浮点数:
double(8字节)-------保证15~16位有效数据(%lf)(默认输出小数点后6位)
%.nf-----------保留小数点后n位进行输出
常见错误:
转义字符:
6、常量
程序运行期间,不能也不会被改变的量
6.1 字符常量
‘a’ ‘A’
6.2 整型常量
二进制:1010
八进制:066
十六进制:0xaf5
十进制:99,-2
注意:默认情况下,整形常量为有符号数;
无符号的int类型:98U
Long类型:76L
无符号的长整型:78UL
6.3浮点型常量
小数:3.14 0.00001 10000(浮点型常量包含整形常量)
指数:1e+5 == 100000 1e-5 == 0.00001
%g:选择小数或者指数中比较合适(比较短)的一种情况进行输出
6.4 字符串常量
“hello”占几个字节
‘h’‘e’‘l’‘l’‘o’‘\0’
(字符串用双引号括起来,字符用单引号括起来)
注意:字符串由‘\0’结尾
6.5 标识常量(宏)
宏只是一个单纯的替换!
#define 宏名 表达式
注意:1、宏名一般用大写,为了和普通的变量区分开来吗,当然小写也可以
、宏后没有分号
案例:计算圆的周长和面积
宏函数:
既有宏的特点,又有函数的特点
#define 函数名(形参列表) 函数体
案例1:实现两个数的求和
案例2:
案例3:
案例4:
注意:宏只是一个单纯的替换,他不会考虑运算符优先级的问题,因此,需要给每个形参,以及整个表达式都加上括号!
Day3:
- 变量
2、数据类型转换(隐式类型转换、强制类型转换)
3、运算符
1、变量
定义:意味着要在内存中开辟空间
2、定义变量
如何定义一个变量????
存储类型 数据类型 变量名;
//存储类型:决定了在哪块区域去开辟空间
//数据类型:决定了开辟的内存空间的大小
//变量名:开辟的内存空间的名字
存储类型:auto、static、extern、register
3、局部变量和全局变量
3.1 局部变量
定义在函数(任何)体内的变量
3.2 全局变量
定义在函数(任何)体外的变量
4、存储类型
auto、static、extern、register
Auto:修饰的变量存储在栈区,只能修饰局部变量
Static:修饰的变量存储在静态区,即可以修饰全局变量,也可以修饰局部变量,用static修饰的变量叫做静态变量
extern:修饰的变量存储在静态区,只能修饰全局变量
register:修饰的变量存储在寄存器中,只能修饰局部变量
5、初始化
初始化:定义变量的时候就给他一个初始值!
- Int a = 10; //初始化
- Int a; a = 10;//赋值
注意:
- 全局变量如果没有初始化,他的值为0!
- 局部变量如果没有初始化,他的值为随机值!
(为了避免随机值,我们一般给局部变量初始化为0!)
auto:修饰局部变量,存储在栈区
register:修饰局部变量的,修饰的变量存储在寄存器中,但是他的内存空间很小,因此,当寄存器已满时,就算用register修饰了,还是存储在栈区
extern:修饰全局变量,存储在静态区
程序可以由多个.c构成,但是有且只能有一个main函数
作用:告诉编译器,该变量已经在其他文件中定义过了
Static: 即可以修饰局部变量,也可以修饰全局变量,存储在静态区
- 如果static修饰局部变量:作用:延长局部变量的生命周期;如果局部变量没有初始化,那么局部变量的值为0;如果初始化了,只能初始化1次;
- 如果static修饰全局变量:
作用:限制作用域,只能在本文件内使用
6、生命周期和作用域
6.1 生命周期
从开辟空间到空间释放
6.2 作用域
使用的范围
局部变量:
生命周期:从定义开始,到模块(距离他最近的大括号)结束;
作用域:大括号内(距离他最近的大括号)
用static修饰的局部变量:
生命周期:从定义开始,到程序结束
作用域:大括号内(距离他最近的大括号)
全局变量:
生命周期:从定义开始,到程序结束
作用域:整个程序
用static修饰的全局变量:
生命周期:从定义开始,到程序结束
作用域:本文件内(本个.c内)
7、数据类型转换
7.1强制类型转换(我们自己去转的)
7.2 隐式类型转换(编译器去转的)
横向箭头:不管有没有进行混合运算,都会进行转化!
注意:char、short使用的时候按照:int去用
注意:float在使用的时候按照:double去用
纵向箭头:只有在进行混合运算的时候,才会进行转换!
案例:
8、运算符
单算移关与,异或逻条赋
单目运算符,算术运算符,左移右移,关系运算符、按位与、异或、按位或、逻辑运算符、条件运算符、赋值
8.1算术运算符
+、-、*、/、++、--、%
注意:%不能用于浮点数
++在前:先自加,在赋值
++在后:先赋值,在自加
注意:如果++a和a++单独成立一条语句,那么都相当于给a+1
8.2关系运算符
> < >= <= == !=
注意: 0 < a < 5 //error
注意:等号的书写! ==(判断是否相等)
在判断是否相等的时候:将常量写在等号的左边!!!!
8.3 逻辑运算符
&&、 || 、 !
&&:
表达式1 && 表达式2
截断法则:有一个为假,结果就为假,前一个为假,后面就不在进行运算了
||:
表达式1 || 表达式2
截断法则:有一个为真,结果就为真,前一个为真,后面就不在进行运算了
8.4 sizeof运算符
Sizeof(数据类型) sizeof(变量名)
数据类型如何判断:去掉变量名,剩下的就是数据类型!
8.5 三目运算符
表达式1 ? 表达式2 :表达式3
先去判断表达式1是否成立,如果成立,就将表达式2的值作为整个表达式的值,如果表达式1不成立,则将表达式3的值作为整个表达式的值
8.6 逗号运算符
表达式1,表达式2,表达式3,表达式4,.........,表达式n
从左往右依次去计算每个表达式的值,最后,将表达式n的值作为整个表达式的值
注意:逗号运算符的优先级是最低的,因此在使用的时候加上括号!!
例题:
Int i = 2,j = 3, k = 4, a = 4, b = 5, c = 3;
则执行表达式(a = i < j) && (b = j > k) (i,j,k))后,c的值为多少?
为假:&&的截断法则:有一个为假,结果就为假,前一个为假,后面就不在进行运算了
8.7 位运算符
& 、 | 、 ~ 、 ^、 << 、 >>
8.7.1 与运算(&)
都为1,才为1(有一个0,就为0)
1001 0101
& 0100 1111
0000 0101
案例:将1101 0011的0~2位清零
1101 0011
& (1111 1000)------------&(~7)---------~(111)------(111-----111000)
1101 0000
一般用&:给某些位置零
8.7.2 或运算(|)
|:都为0,才为0(有一个1,就为1)
1101 0100
| 0010 1111
1111 1111
案例:将1101 0010的0~2位置为101
- 清零: &(~7)---------- -------------------1101 0 000
- 置位: |(000---- 101)----|(5)-----1101 0 101
8.7.3 取反(~)
0变1, 1变0
~(1001 0110) == 0110 1001
8.7.4 异或(^)
相同为0,不同为1
1101 0010
^ 0111 0110
1010 0100
8.7.5 左移(<<)
无符号数:高位丢弃,低位补0
0000 0001 << 2
0000 0100 -------- 4
有符号数:
正数:符号位不变,高位丢弃,低位补0
0000 0001 <<2
0 000 0100----- +4
负数:符号位不变,高位丢弃,低位补0
-4 << 2
原码:1 000 0100
反码:1 111 1011
补码:1 111 1100
左移:1 111 0000
原码:1 000 1111+1------------1001 0000----- -16
8.7.6右移(>>)
无符号数:低位丢弃,高位补0
0000 0100
0000 0001 ------- 1
有符号数:
正数:符号位不变,低位丢弃,高位补0
: 0000 0100
0000 0001---------- 1
负数:符号位不变,低位丢弃,高位补1
-1:
原码:1000 0001
反码:1111 1110
补码:1111 1111
补码:1111 1111
反码:1000 0000
原码:1000 0001------------(-1)
总结:
左移:
无符号数:高位丢弃,低位补0
有符号数:符号位不变,高位丢弃,低位补0
右移:
无符号数:低位丢弃,高位补0
有符号数:符号位不变,低位丢弃,高位补符号位
作业:
- 定义x和y为double类型的变量,则表达式x = 1, y = x+3/2; y的值为多少?x = 1,
y = x+3/2;
3和2都为整型:----结果转为整型----结果== 1
Y = double+ int --------结果转向double
所以y = 1.0 + 1 = 2.0 - 不使用第三方变量,实现两个数的交换;
Int a = 10;
Int b = 20;
A = a+b;
B = a-b;
A = a-b;
Day4:
- 输入输出
- 三大结构(顺序结构、选择结构、循环结构)
输入输出
函数:具有独立功能的模块
标准输入输出函数:scanf、printf(对变量的类型没有限制)
输入:从键盘拷贝数据到内存中
输出:将内存中的数据拷贝到终端
1.1输出
printf(“格式控制串”,输出表);
格式控制串:原样输出的内容 + 格式化符
输出表:输出的内容
注意:输出的内容要和格式化符一一对应!!!
整型:
%d:十进制的整数
%o:八进制
%x %X:十六进制
#:自动在八进制和十六进制前加上前缀
%u:以无符号的整型
%hd:short类型
%ld:long类型
字符型:
%c:字符型
浮点型:
%f:float类型
%lf:double类型
%g:选择小数和指数中比较合适的一种情况进行输出
%e:指数形式
%m.nf:
.nf:保留小数点后n为进行输出
m:指定我们输出的域宽,默认(m>0)右对齐,m的值大于数据的实际长度时,左边补空格,m的值小于数据的实际长度时,原样输出!(反之:m<0----左对齐:右边补空格)
1.2 输入
scanf(“格式控制串”,地址表);
格式控制串:原样输入的内容+格式化符
地址表:&+变量名(你要给哪片空间去输入)
注意:
- scanf的格式控制串中,不要去加多余的修饰语,如果要加,原样输入
- 如果输入“%d%d”时要给多个变量进行赋值,在格式控制串之间没有多余的修饰语时,以空格,回车,tab作为第一个变量输入结束的标志
- 全部输入结束后,必须以回车作为结束符
- 如果是“%c%c”时,在输入时,不能有空格回车tab键,因为空格回车tab也是字符;
解决办法:
- 在“%c%c”之间加上空格,或者逗号隔开
- 加%*c, *表示抑制符
1.3字符的输入输出函数
字符的输入函数:
Int();
//返回值:输入的字符的ascii码值
字符的输出函数:
putchar(int);
//参数:要输出的字符的ascii码值
2、三大结构
顺序结构、选择结构、循环结构
2.1 顺序结构
语句按照一定的先后顺序去执行
2.2 选择结构
2.2.1 单分支选择结构
if(表达式)
{
语句;
}
先判断表达式是否成立,如果成立,执行语句
2.2.2 双分支选择结构
if(表达式)
{
语句1;
}
else
{
语句2;
}
先判断表达式是否成立,如果成立,就执行语句1,否则,执行语句2;
案例:输入年份,输出该年是平年还是闰年
2.2.3 多分支if选择结构
If(表达式1)
{
语句1;
}
else if(表达式2)
{
语句2;
}
Else if(表达式3)
{
语句3;
}
。。。
Else if(表达式n-1)
{
语句n-1;
}
Else
{
语句n;
}
从上往下,依次去判断每个表达式是否成立,如果成立,就执行对应的语句
案例:输入一个成立,判断成绩的等级
85-100:AAAAAAA
70-85: BBBBBBBB
60-70: CCCCCCCC
60以下:DDDDDDD
2.2.4 switch语句
Switch(表达式)
{
Case 标号1:
语句1;
Case 标号2:
语句2;
Case 标号3:
语句4;
。。。。
Case 标号n-1:
语句n-1;
Default:
语句n;
}
注意:
- 表达式不能为float类型;
- 标号必须为常量;
- 当表达式等于标号的时候:执行冒号后面的语句!(如果都不相等,默认执行default后面的语句!)直到switch,case语句结束,或者遇到break语句结束!
结束条件:(停止输出冒号后面的语句的条件)
- 遇到break,跳出switch语句
- Switch,case语句结束
作业:
1、整理思维导图
2、输入年份和月份,输出该年该月有多少天
- 自定义宏,用三目运算符求两个数中比较小的一个数
2.3 循环结构
重复的去做一件事
三要素:循环的起始条件、循环的终止条件、循环变量的变化
2.3.1 for循环
for(表达式1 ;表达式2 ;表达式3)
{
循环体;
}
表达式1:循环的起始条件
表达式2:循环的终止条件
表达式3:循环变量的变化
先执行表达式1;然后判断表达式2是否为真,如果为真,则执行循环体,然后执行表达式3,以此反复,直至表达式2为假,跳出循环!
案例:用for循环实现1-100之和
思考:表达式1,表达式2,表达式3是否可以省略?
省略表达式1:在for循环之外:要给循环变量一个初始值
省略表达式2:死循环
省略表达式3:循环体内实现循环变量的变化
注意:表达式1,表达式2,表达式3都可以省略,但是分号不能省略
for循环的嵌套:
案例:
打印:
2.3.2 while语句
While(表达式)
{
循环体;
}
判断表达式是否成立,如果成立,则执行循环体,否则,跳出循环
案例:用while语句实现1-100之和
2.3.3 do...while语句
do
{
循环体
}while(表达式);
先执行循环体;判断表达式是否成立,如果成立,则执行循环体,否则,跳出循环;
案例:用do...while语句不实现1-100之和
总结:区别
while语句:先判断,在执行,语句至少执行0次;
do...while语句:先执行,在判断,语句至少执行1次;
2.3.4 break和continue的区别:
(跳出离他最近的一个循环!)
break:
- 跳出switch、case语句2、跳出循环
continue:跳出本次循环,进入下一次循环
2.3.5 死循环
While(1)
{
循环体;
}
for( ; 1 ; )
{
循环体
}
2.3.6 goto语句
无条件跳转语句
一般格式为:
goto 标号;
标号:
Day5:
数组:
1、概念
一组数据类型相同的元素组成的集合(一堆数据类型相同的数据组合在一起!)
特点:1、数据类型相同 、地址连续(打印地址:%p)
2、定义
存储类型 数据类型 变量名;
Int a;
存储类型:auto、static、register、extern
Auto:局部:栈区
Static:全局和局部:静态区
作用:全局:限制作用域,只能在本文件内使用
局部:延长局部变量的生命周期,如果没有初始化,则局部变量的值== 0,初始化:只能初始化一次
Extern:全局:静态区
作用:告诉编译器,该变量已经在其他文件中定义过了
Register:局部
存储类型数据类型数组名[元素的个数];
;
//相当于定义了一个数组:数组名为:a:数组中有5个元素,这五个元素都是int类型的
数据类型:数组中元素的数据类型
数组的数据类型:int [5]
数据类型:去掉变量名,剩下的就是数据类型!
开辟的内存空间的大小= sizeof(数据类型)*元素的个数
//数组:int[5]和int[6]是两种不同的数据类型
数组名:数组名代表的是数组首元素的地址!(表示整个数组)
首元素的地址:&arr[0]
数组名:arr
注意:定义数组时:元素的个数必须为一个确定的值!
3、初始化
3.1 部分初始化
int arr[5] = {1,2,3};
//a[0] = 1, a[1] = 2, a[2] = 3; a[3]和a[4] = ?
在进行部分初始化时,未初始化的部分其值为0;因此,利用部分初始化的特点:给数组进行清零!
数组清零: int arr[100] = {0};
3.2 全部初始化
Int a[5] = {1,2,3,4,5};
Int a[ ] = {1,2,3};//在进行全部初始化时,数组元素的个数是可以省略的,有后面赋值的具体的元素个数来决定!
总结:
1、数组定义在函数体内时,如果没有初始化,(相当于局部变量),数组中的值为随机值
- 数组定义在函数体外,如果没有初始化,(相当于全局变量),数组中的值为0
- 数组定义在函数体内,用static修饰(相当于用static修饰的局部变量)数组中的值为0
访问
数组名[下标]
注意:下标从0开始
案例:实现对数组的输入和输出
判断对错:
- int a[5];
错:如果当做元素:不能将集合赋给一个元素;并且没有a[5]
2、int a[5];
a= {1,2,3,4,5}; //错:数组名:a:数组收元素的地址!
3、int a[ ] = {0}; //对:相当于全部初始化;可以但没必要;int a = 0;
4、int a[ ]; //错,数组!只有在进行全部初始化时,元素的个数才可以省略
作业:
- 打印99乘法表
2、作业:打印等腰三角形
5行
先打印空格,在打印*,打印换行
- ---------- 4个空格 1个*
- --------- 3个空格 3个*
- --------- 2个空格 5个*
N--------- 5-n个空格 2*n-1个*
3、求一组数中的最大值
Day 6:
- 冒泡排序:思想!
- 字符数组
- 字符串的输入和输出
1、冒泡排序
思想:从左往右,两两依次比较,如果前一个数比后一个数大,就交换位置,反之,不变!
66、33、52、24、19----------- 19、24、33、52、66
2、字符数组
整型数组:保存一组int类型的数据
存储类型 数据类型数组名[元素的个数];
数据类型:数组中元素的数据类型
Int arr[5];
字符数组:保存一组char类型的数据
存储类型 数据类型 数组名[元素的个数];
数据类型:数组中元素的数据类型
定义: char str[10];//定义了一个字符数组str,该数组中可以存放10个char类型的字符
数组所占的内存空间== sizeof(char)*10 = 10
数组的数据类型:char [10];//去掉数组名
Int: 10, 20, 30
Float:3.14 4.165
Char:‘a’ ‘b’
字符串:用什么保存?“hello” = ‘h’‘e’‘l’‘l’‘o’‘\0’
用字符数组来保存!
给字符数组清零:
Char str[10] = {0}
Char str[10] = {‘\0’};
字符数组的本质就是字符串;
给字符数组进行赋值:
1、Char str[10] = { ‘h’,’e’,’l’,’l’,’o’ };
Str[5]----->str[9] ==’\0’;
“hello” = ‘h’,’e’,’l’,’l’,’o’,‘\0’
2、Char str[10] = “hello”;
//数组名就是数组首元素的地址
//&str[0] == str
3、字符串的输入输出函数
3.1字符串的输出函数
%s:字符串
Printf(“ %s ”, str);
puts(数组名);
功能:将数组中的内容打印到终端,并且自动换行
注意:打印到‘\0结束
3.2 字符串的输入函数
Scanf(“%s”,str);
gets(数组名);
功能:将输入的字符串保存在数组中,并且在末尾自动添加‘\0’
注意:gets不会进行越界检查,如果超出范围,就会操作未申请到的内存空间,段错误
出现段错误的原因:非法操作你没有申请的空间。
4、总结:
4.1 scanf和gets的区别
gets是以回车作为结束符,而scanf以空格,回车,tab作为结束符
缓冲区:
gets:当完成字符串的输入之后,会自动清空缓冲区的内容
scanf:当完成字符串的输入之后,会在缓冲区遗留空格、回车、tab
注意:
gets:首先检查缓冲区里面是否有内容,如果有,直接拿来用,否则等待输入
scanf:标准输入函数:每一次只能等待键入
4.2 printf和puts的区别
Puts后会自动添加换行,而printf不会!
作业:
1、思维导图
2、求一组数中的最大值和次大值
3、不使用字符串的拷贝函数:实现字符串的拷贝(画图)
Day7:
- 字符串处理函数
- 二维整型数组
- 二维字符数组
- 函数
- 指针
字符串的处理函数
strlen、strcpy、strcat、strcmp
第一步:添加头文件:#include <string.h>
第二步:函数名(参数);
求字符串的长度
strlen(数组名);
功能:求字符串的实际长度
返回值:求得的字符串的实际长度,不包含‘\0’
Strlen和sizeof的区别
- strlen是函数,sizeof是运算符
- Strlen求到的是字符串的实际长度,不包含‘\0’,sizeof求到的是整个空间的大小案例:不使用strlen:求字符串的实际长度
1.2字符串的拷贝函数
Strcpy(数组1,数组2/字符串);
功能:将数组2中的内容拷贝到数组1中,包含‘\0’,相当于完全拷贝
注意:数组1的容量大于数组2
Strncpy(数组1,数组2/字符串,n);
功能:将数组2的前n个字符拷贝到数组1中
1.3字符串连接函数
Strcat(数组1,数组2/字符串);
功能:将数组2或者字符串的内容连接到数组1中,数组1中的‘\0’会被覆盖
注意:数组1的容量要大一些
Strncat(数组1,数组2/字符串,n);
功能:将数组2或者字符串的前n个字符连接在数组1后面
案例:不使用strcat:实现字符串的连接!
1.4 字符串的比较函数
Strcmp(数组1/字符串1,数组2/字符串2);
功能:比较字符串1和字符串2的大小
返回值:
大于0:字符串1 > 字符串2
等于0:字符串1 == 字符串2
小于0:字符串1 < 字符串2
比较规则:
从左往右一次对字符串中的字符的ascii码值进行比较,直到遇到不同的ascii值或者遇到‘\0’结束比较
2、二维数组
1、概念(数组数组)
整形数组: 一堆int类型组成的集合
字符数组: 一堆char类型组成的集合
浮点型数组:一堆float类型组成的集合
数组数组: 一堆数组类型组成的集合
二维数组:元素为一维数组的一维数组
一组数组类型的元素组成的集合(一堆一维数组组成的数组)
元素:一维数组(元素:一维数组的里面存放的元素的个数以及数据类型必须相同)
- 数据类型相同、地址连续
定义
定义一个:一维整型数组:
存储类型 数据类型 数组名[元素的个数];
Int a[3];
//一维数组中有3个int类型的元素
数组的数据类型:int [3];
定义一个:二维数组:
存储类型数据类型数组名[元素的个数][一维数组中元素的个数];
存储类型 数据类型 数组名[行数][列数];
//将2个一维数组(int [3])组合在一起
Int arr[2][3];
//数据类型:一维数组中元素的数据类型
行数:二维数组元素的个数:一维数组的个数
列数:一维数组中元素的个数
二维数组中真正的元素的个数 == 行数*列数
初始化
3.1部分初始化
Int a[2][3] = {1,2};
Int a[2][3] = {{1,2},{1}};
a[0][0] = 1; a[0][1] = 2;//其他值为0
3.2全部初始化
Int a[2][3] = {1,2,3,4,5,6};
Int a[2][3] = {{1,2,3},{4,5,6}};
思考:二维数组在进行初始化时,行数和列数是否可以省略?
行数可以省略,列数不行
nt a[ ][3] = {1,2,3,4,5,6,7};//表示有3个一维数组,每个一维数组中有三个元素
Int a[2][ ] = {1,2,3,4,5,6}; //error
4、访问
案例:打印杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
3、二维字符数组
一维字符数组:
存储类型 数据类型 数组名[元素的个数];
Char str[10] = “hello”;
//定义了一个一维字符数组str,该数组由10个char类型的元素组成
一维字符数组的本质-----字符串!
一维字符数组的数据类型:char [10];
Scanf(“%s”,str);
Printf(“%s”,str);
二维字符数组:
存储类型 数据类型 数组名[行数][列数];
Char str[5][10];
行数:一维字符数组的个数==========字符串的个数
列数:每个一维数组中元素的个数====每个字符串长度
//定义了一个二维字符数组str
该二维字符数组中有5个字符串,每个字符串的长度为10字节
4、函数
1、概念
具有独立功能的模块
2、为什么要使用函数
1、使代码模块化
2、提高代码的复用率
3、函数的分类
3.1 库函数
printf 、scanf 、strlen、strcat......
3.1.1引入头文件
#include <stdio.h>、 #include<string.h>
3.2.1 调用函数
Strlen(数组名);
函数名(实际参数);
返回值:字符串的实际长度;考虑:返回值的数据类型,以及返回值是否需要
(如果需要使用函数的返回值:定义一个与其返回值相同的数据类型去接收!)
3.2自定义函数
3.2.1函数定义
存储类型数据类型函数名(形式参数列表)
{
函数体;//具体功能的实现
返回值;
}
存储类型:static、extern
数据类型:函数返回值的数据类型(函数返回值:不写默认为:int)
函数名:见名知意(满足标识符的命名规则)
形式参数列表:实现功能所需要的参数,需要调用者传入
函数体:具体功能的实现
返回值:若没有返回值,返回值可以省略(类型:void),如果有返回值:有且只能有一个!
3.2.2调用函数
函数名(实参列表);
注意:
- 需要将实参的值传递给形参,实参的个数和数据类型必须和形参一致
- 实参,可以是常量、变量、表达式,但必须是一个确定的值;
- 实参和形参是两块独立的空间(因此可以重名)
- 传参实际上是将实参的值拷贝给形参
- 形参是局部变量,在函数调用时开辟空间,调用结束立即释放
3.2.2.1 调用时
3.2.2.2 调用结束
3.2.2.3 函数声明
如果函数没有在main函数之前,就需要在main函数之前添加声明;
声明方法:将函数头直接拷贝到main函数之前,然后加上分号;
未加声明之前:
加上声明之后:
声明的作用:帮助编译器做语法检查(例如:参数的个数以及数据类型)
作业:
先输入两个数:实现加减乘除
- 封装函数实现两个数的交换
Day8:
- 指针
- 二级指针
指针
1.1什么是指针?
Char是一种数据类型,它是一种保存字符的数据类型(‘a’,‘b’)
Int 是一种数据类型,它是一种保存整形数的数据类型(10,20)
float是一种数据类型,他是一种保存浮点数的数据类型(3.14 2.37)
指针是一种数据类型,它是一种保存地址的数据类型(%p打印出来的地址编号)
1.2什么是地址?
内存分配的最小单元是字节,每一个字节都有一个编号,这个编号就叫做地址!
地址的本质:内存单元的编号!
指针:
指针:指针就是地址
指针的本质:内存单元的编号
1.3 指针常量
Char定义的变量-----------保存字符常量
Int定义的变量----------保存整形常量
float定义的变量-------保存浮点型常量
指针定义的变量-------保存指针常量(地址:专门用来保存内存单元的编号)
1.4 指针变量
如何定义一个指针变量?
存储类型数据类型* 变量名;
;
//*用来表示p是一个指针变量
//定义了一个指针变量p,这个p用来保存类型变量的地址
//指针保存谁的地址========等价于===========指针指向谁
数据类型:指针指向的数据类型
指针p的数据类型:int *;
指针指向的数据类型:去掉一个*,在去掉变量名,剩下的就是指针指向的数据类型!
注意:*和&互为逆运算;
p保存了a的地址,作用是什么?
- 间接访问a的值
- 间接改变a的值
1.5 指针的赋值
指针的赋值:相当于改变指针的指向;
注意:对指针变量进行赋值时,要注意类型匹配!
思考?
- 什么是指针?
- 地址是什么?
- 什么是指针变量?
- 指针变量如何定义?
- 如何给指针变量赋值?
- 指针变量赋值之后可以干什么?
注意:
在32os中:所有的指针都占4字节
在64os中,所有的指针都占8字节
1.6、空指针
没有指向的指针:NULL(值为0的指针,就认为该指针没有指向)
注意:0号地址禁止操作
要操作就改变指针的指向:
1.7、野指针
不知道指向哪里的指针
局部变量:没有初始化:随机值
局部指针:没有初始化:野指针
如何避免野指针?
在定义指针时:初始化为NULL;
1.7、值传递
案例:封装函数实现两个数的交换
1.7、地址传递
2、二级指针
2.1概念
指针的指针(地址)
二级指针的内存空间中保存的是一级指针的地址
2.2定义
定义一个整形变量;
存储类型 数据类型变量名;
;
//编译器开辟4个字节的内存空间:这片空间的名字叫a,这片空间中保存的是整形数
a的数据类型:int
定义一个一级整形指针
存储类型数据类型指针变量名;
Int ;
//编译器开辟4字节的内存空间:这片空间的名字叫p,这片空间中保存的是整形数的地址
p的数据类型:int *
定义一个二级整形指针
存储类型 数据类型 * 指针变量名;
Int* ;
pp的数据类型:int**;
Int *:pp指向的数据类型========等价于====pp保存什么数据类型变量的地址
指针指向谁=========等价于============指针保存谁的地址
2.3总结
- 指针的数据类型:去掉变量名,剩下的就是数据类型Int *p;//int *
Int **p;//int **
Int ***p;//int *** - 指针指向的数据类型:去掉变量名和一个*,剩下的就是指针指向的数据类型Int *p;//指向的数据类型:int
Int **p;//指向的数据类型:int *
Int ***p;//指向的数据类型:int ** - 指针能够访问到的内存空间的大小:由他指向的数据类型决定
(1)Int a =10;
Int *p =&a;//*p能够访问到的内存空间的大小为4字节
- char b = ‘a’;Char *p = &b;//*p能够访问到的内存空间的大小为1字节
- int *p = NULL;
Int **pp = &p;//*pp能够访问到的内存空间的大小为4字节
//pp指向的数据类型int * : 所以他能够访问到的内存空间的大小为4字节
4、
Int ** n = NULL; //n的数据类型:int **
Int ** * m = &n; //m指向的数据类型int**
Day9:
指针的算数运算
指针+1-------加多大?
总结:
p+n:p+n相当于向地址增大的方向移动了n个数据
实际的变化:p + sizeof(指针指向的数据类型)* n
(p的指向没有发生改变)
- n: p-n相当于向地址减小的方向移动了n个数据
实际的变化:p - sizeof(指针指向的数据类型) * n
(p的指向没有发生改变)
p++:p向地址增大的方向移动的一个数据(p的指向发生了改变)
p--: p向地址减小的方向移动了一个数据(p的指向发生了改变)
p-q:(p和q的数据类型一致):这两个指针之间相隔的数据的个数
注意:
- 指针的算术运算只有在操作连续的内存空间时,才有意义!
- p是一个指针变量,以上的操作方法对指针常量也适用,但是++、--除外
2、为什么数组名[下标]可以访问数组中的元素?
数组名的含义:
1、数组名就是数组首元素的地址,指针常量,不能++、--,数据类型
2、数组名表示整个数组时:sizeof(数据类型 [元素的个数]); 数据类型[元素的个数]
3、指针和一维数组的关系
3.1指针常量和一维数组的关系
3.2指针变量和一维数组的关系
改变指针的指向操作:数组输入输出:
通过指针访问一维数组中的元素:5种方法:
总结:数组名和指针变量的区别:数组名为指针常量,不能自加自减!
案例:
- printf中有表达式的时候:右结合
2、64os:
4、冒泡排序的实现:
4.1指针的指向不发生改变
4.2指针的指向发生改变
作业:实现数组的输入输出排序,以及输出最大值(用指针移动的方式实现:改变指针的指向)
作业:
- 封装函数实现求字符串的长度
- 封装函数实现字符串的拷贝
- 封装函数实现字符串的连接
要求:(必须使用指针指向发生改变的方式!)
Day10:
1、指针和二维数组的关系
总结:
- a、&a[0]、a[0]、&a[0][0]的值相等,但是意义不同a:int(*)[4]类型:指向一维数组: a[0]: int * :指向int类型
- 为什么说a不是int**类型:如果a是int **类型,那么a+1移动4(8)个字节,可是此时a+1,移动了16字节,也就是整个数组,因此此时a不是int **类型
- a指向a[0],a[0]又是一个数组,因此我们说a是一个指向数组的指针!
数组指针与指针数组
2.1 数组指针
2.1.1概念:
指向数组的指针(保存数组的地址的指针)
2.1.2 定义:
存储类型数据类型(* 变量名)元素的个数];
Int (*p)[3];
//定义了一个数组指针p,该指针指向一个拥有3个int类型元素的一维数组
(该指针可以保存一个拥有3个int类型元素的一维数组的地址)
p的数据类型:int(*)[3];
p指向的数据类型: int [3]
p先和谁结合:本质就是谁
p先和*结合:定义的本质就是指针
p先和[]结合:定义的本质就是数组
注意:[ ]的优先级高于*
Int a = 10;//定义了一个整型变量
Int*p定义了一个指向整型的指针
//p指向a
P = &a;
Int a[3] = {0};//定义了一个一维数组//该数组中有3个int类型的元素
Int (*p)[3] = NULL;//定义了一个指向拥有3个int类型元素的一维数组
//p指向数组a
P = &a;
2.1.3 数组指针和一维数组的关系
注意:数组指针几乎不操作一维数组,更多的是操作二维数组,因为指针在访问连续的内存空间时才有意义。如果是一维数组,p+1越界了!
2.1.4 数组指针和二维数组的关系
2.2 指针数组
2.2.1 概念
元素为指针的数组
2.2.2 定义
存储类型数据类型变量名[元素的个数];
Int * arr[3];
//定义了一个指针数组arr,该数组中有3个int *类型的元素;
2.2.3指针数组和二维数组的关系
const的作用
Const修饰:只读
Const修饰变量:
不能直接修改a的值;
可以间接修改:
因此:被const修饰之后:变量之前在哪里存放,现在还在那里存放,只能不能直接修改!
案例?Char * str = “hello”;
*str = ‘a’;//error:常量区的内容:不管是直接改变还是间接改变都不可以!!!
Const修饰指针:
左数右指(const关于*的位置)
修饰指针
//1. const int *p = NULL;
//2. int const *p = NULL;
//3. int * const p = NULL;
//4. const int * const p = NULL;
//5. int const * const p = NULL;
左数右指
当const在*的左边时,值不能更改,*p不能改
当const在*的右边时,指向不能改,p不能改
main函数传参
Main函数有两个参数:
第一个参数:字符串的个数
第二个参数:保存每个字符串的地址char * argv[ ]