day6
数组
1概念
一组数据类型相同的元素组合在一起
1 数据类型相同 2 地址连续
2定义
存储类型 数据类型 变量名;
Int a;
存储类型 数据类型 数组名【元素的个数】;
Int arr[5];
Float brr【5】;
定义了一个数组,数组名为arr,数组中有五个int类型元素;
数组名:arr
数据类型:数组元素的数据类型
数组的数据类型是什么?
数据类型:去掉变量名,就是数据类型
数组的数据类型: int [5];
Int arr[5];//数据类型是 int [5];
Int brr[6];//数据类型是 int [6];
Int crr[5];
int [5]和int [6]表示的数据类型是不一样的;
元素的个数:必须为一个确定的值
数组名:
代表数组首元素的地址(可以表示整个数组)
%p:打印地址
3初始化
3.1部分初始化
Int arr[5] = {1,2,3};
部分初始化,未被初始化的部分,值为0
用此特性给数组清零
Int arr[5]={0};
3.2全部初始化
全部进行初始化
Int arr【】;//error
只有全部初始化的时候才可以这样去做!!!
Int arr[ ] = {1,2,3}; //可以,编译器自动计算数组元素的个数
如果不进行初始化:产生的结果
总结:
- 数组定义在函数体外,(相当于全局变量)不初始化,元素都为0
- 数组定义在函数体内,(相当于局部变量)不初始化,元素为随机值
数组定义在函数体内,(相当于用static修饰局部变量)用static修饰,不初始化,元素都为0
4访问
案例:判断以下四个是否正确
1、int a[5];(a[0]----a[4])
a[4] = {1,2,3,4,5} ; //error 没有a[5]
2、int a[5];
a = {1,2,3,4,5}; //error数组名表示数组首元素的地址
3、int a[ ] = {0}; //对,没有意义 int a = 0;
4、int a[ ]; //error 编译器不知道要分配多大的内存空间
5冒泡排序
(c语言阶段唯一一个算法)
Int arr[5] = { 14, 85,99,2,30};------------> 2,14,30,85,99
思想:从左向右两两依次比较,如果前一个数大于后一个数,就交换位置;反之,不变。
字符数组
定义:
字符数组的本质就是字符串;
存储类型 数据类型 数组名[元素的个数];
Char str[10];
定义了一个名为str的字符数组,所占内存空间:sizeof(数据类型)*元素的个数=1*10=10
数据类型:元素的数据类型
数组的数据类型:char [10];
初始化:char str[10]={‘s’,’h’,’a’,’n’,’g’};
Char sstr[6]={‘h’,’e’,’l’,’l’,’o’};//自己最多只能去初始化五个字符,因为要给’\0’留位置
Char atr[10]=”hello”;
用部分初始化的特性去给字符数组清零:char btr[10]={‘\0’};
1字符串的输出函数
%s:输出字符串
Puts(数组名);
功能:将数组的内容打印到终端,并自动添加换行
注意:遇到’\0’结束
2字符串的输入函数
gets(数组名)
功能:将键盘接受到的字符串存入数组,并会在末尾添‘\0’
注意:不会进行越界检查,输入的时候要注意不要越界
3scanf和gets的区别
- scanf是标准输入函数,他每次输入都会采用键入的方式,不会去检查缓冲区有无内容
- gets会先去检查缓冲区有没有东西,如果缓冲区有内容,他会率先去读取缓冲区的内容
注意:
scanf每次输入后,会在缓冲区遗留 空格回车tab键
gets每次输入完毕之后,他会自动清空缓冲区里面的内容
4printf和puts的区别
puts会自动换行,printf不会
day7
字符串处理函数
Strlen、 strcpy、 strcat、 strcmp、
man手册去查看字符串处理函数需要的头文件
头文件:#include <string.h>
1求字符串的长度
Strlen(数组名);
返回值:字符串的长度
功能:计算字符串的实际长度,不包括‘\0’
Sizeof和strlen的区别:
- sizeof是一个运算符,strlen是函数
- Sizeof求到的是所占内存空间的大小,strlen求到的字符串的实际长度(不包含’\0’)
示例:不使用字符串处理函数,求字符串的实际长度
2字符串拷贝函数
Strcpy(数组1,数组2/字符串);
Puts(数组1);
功能:将数组2的内容完全拷贝给数组1,包括‘\0’,相当于完全拷贝
strncpy(数组1,数组2/字符串,n);
功能:将数组2的前n个拷贝给数组1,不包含’\0’;
3 字符串连接函数
Strcat(数组1,数组2/字符串)
功能:将数组2的内容连接至数组1中,会覆盖数组1的‘\0’
注意:数组1的内存大小要能够存储下两个数组1和数组2连接出来的结果
Char str1[20] = “hello”;
Char str2[20] = “world”;
Strcat(str1,str2);
Puts(str1);
Strncat
Strncat(数组1,数组2/字符串,n)
功能:将数组2 的前n个字符连接到数组1后面
4字符串比较函数
Strcmp(数组1,数组2/字符串);
功能:比较两个字符串的大小
返回值:
当字符串1 > 字符串2,返回值大于0
当字符串1 == 字符串2,返回值等于0
当字符串1 < 字符串2,返回值小于0
如何比较:从左往右依次对字符串中的ascii码值就行比较,直到遇到ascii码值不同时或‘\0’结束比较
二维数组
概念
一组数据类型相同的元素组合在一起
- 数据类型相同 2、地址连续
二维数组:他是元素为一维数组的一维数组,他的本质还是一维数组
定义
存储类型 数据类型 数组名[元素的个数];
存储类型 数据类型 数组名[行数][列数];
Int a[2][3];
行数:二维数组中有几个一维数组
列数:一维数组中元素的个数
数据类型: 元素的数据类型
二维数组的数据类型: int [2][3];
二维数组中存储了几个元素: 行数*列数
初始化
2.3.1 部分初始化
Int a[2][3]= {1,2};
a[0][0]= 1, a[0][1]= 2,a[0][2]= ?,a[1][0]=?,a[1][1]=?,a[1][2]= ?
部分初始化,未初始化的部分值为0
利用部分初始化的特性可以给数组清零:
Int a[2][3]= {0};
2.3.2 全部初始化
Int a[2][3]={1,2,3,4,5,6};
Int a[2][3]= {{1,2,3},{4,5,6}};
思考:行数和列数是否可以省略?(行可以省略,列不可以)
省略行数: a[ ][3]= {1,2,3,4,5,6,7,8}; //可以省略行数
省略列数: a[2][ ]= {1,2,3,4,5,6}; //不可以省略列数
访问
下标【】从零开始
二维字符数组
Int str[10];
Char atr[10];字符数组的本质是字符串
Int a[3][4];
Char btr[4][5];
存储类型 数据类型 数组名[行数][列数];
Char str[4][10];
行数:一维字符数组的个数(字符串的个数)
列数:一维数组里面元素的个数
day8
函数
具有独立功能的模块
为什么要使用函数
1、为了让程序变得模块化
2、提高代码的复用率
函数的分类
1 库函数
Printf scanf strlen
2 引用文件
#include<stdio.h> #include <string.h>
3 调用函数
Strlen(str);
返回值:求到的字符串的实际长度,int类型
函数名(实际参数列表);
注意:有几个参数,数据类型是什么,返回值
自定义函数
1 定义一个函数
存储类型 数据类型 函数名(形式参数列表)
{
函数体;
返回值;
}
数据类型:返回值的数据类型
函数名:见名知意,标识符(3点要求)
形式参数列表:需要传的参数类型,需要调用者传入
函数体:具体功能的实现
返回值:不需要,可以不写,如果需要返回值,有且只能有一个返回值
2 调用函数
函数名(实际参数列表);
注意:
- 需要将实参的值传递给形参,实参的个数和数据类型必须和形参一样
- 实参可以是变量,常量,表达式,必须是一个确定的值
- 实参和形参是两块独立的空间
- 传参实际上是将实参的值拷贝给形参
- 形参在函数调用时被定义,函数调用完毕之后,释放
3 调用函数2
4 函数调用完毕
5 函数的声明
如果函数没有在main函数之前,需要添加声明;
未声明:
声明:将函数头部复制粘贴至main函数之前,加上;
加上声明之后:
声明的作用:帮助编译器做检查
案例:封装实现加减乘除的函数,并调用输出
指针
1 指针是什么?
指针是一种数据类型,他是一种保存地址的数据类型。
Int 类型是用来保存整型数据的
Int a;//保存整形数;
Float b;//保存小数
指针://保存地址的数据类型
2 指针的定义
内存分配的最小单元是字节,每个字节都有一个编号。这个编号就是地址
地址:内存单元的编号
Int a;
%p,打印a的地址;0x100(&a 为 0x100)
指针就是地址
指针的本质也就是内存单元的编号
3 访问
存储类型 数据类型 *指针变量名
Int *p;
数据类型:指针指向的数据类型
指针的数据类型:int *;
数组的首元素的地址:
数组名:表示数组首元素的地址
4 赋值
注意:给指针赋值的时候要注意数据类型匹配
思考:
- 什么是指针?
- 地址是什么?
- 什么是指针变量?
- 指针变量如何去定义?
- 如何去给指针变量赋值?
- 指针变量赋值之后,可以干什么?
-
注意:在32OS中,指针类型占4个字节
-
在64OS中,指针类型占8个字节
5 野指针
野指针:不知道指向哪里的指针
怎样避免野指针:定义时先让指针指向0号地址
6 空指针
没有指向指针(值为0的指针,指向NULL)
规定:0号地址不允许操作;
如果想要操作空指针,改变指针的指向
7 值传递
8 地址传递
作业:用函数封装实现数组的输入输出
- 先思考需要传递什么参数
- 是否需要返回值
- 给函数起名:见名知意
day9
二级指针
1概念
二级指针:保存一级指针的地址
存储类型 数据类型 *指针变量名;
定义一个一级指针:int *p;指向整型的一个指针;
一级指针的数据类型: int *;
2定义
存储类型 数据类型 *指针变量名;
数据类型:指针指向的数据类型(二级指针现在要指向一级指针)
Int **pp;
二级指针的数据类型: int **
3总结
1、指针的数据类型,(去掉指针变量名)
Int *p;//int *
Int **pp;//int **
Int ***ppp;//int ***
2、指针指向的数据类型,(去掉变量名和一个*)
Int *p;//指向int
Int **pp;//指向 int *
Int ***ppp;//指向int**
- 三级指针
Int ***ppp= NULL;
三级指针:保存二级指针的地址
Int **pp;
ppp= &pp;
4指针的算术运算
总结:
p+n:p+n相当于向地址增大的方向移动n个数据类型
实际的变化:向地址增大的方向移动:n *sizeof(p指向的数据类型)个字节
p-n: p-n相当于向地址减小的方向移动n个数据类型
实际的变化:向地址减小的方向移动:n*sizeof(p指向的数据类型)个字节
p++:p向地址增大的方向移动一个数据类型(p指向的数据类型)
p--:p向地址见效的方向移动一个数据类型(p指向的数据类型)
p-q:(p和q的数据类型要相同)//两个之间相差的元素
注意:1、指针可以进行计算,同时指针常量也可以进行计算,++,--除外
2、只有在访问连续的空间时,指针的运算才有意义
注意:printf又结合
5指针与一维数组的关系
1 通过指针常量访问数组元素
注意:指针常量(数组名)不可以自加自减
2 通过指针变量访问数组元素
通过指针变量取访问数组,但是指针的指向并没有改变
3 总结
1、访问数组的元素
2、数组名代表的是,数组首元素的地址,是一个指针常量,不可以++ ,--;
3、上面三种情况都相当做指针处理,在64os占8个字节,在32os占4个字节
4 案例:用指针实现冒泡排序
5.4.1 用指针变量实现
5.4.2 用指针移动实现
day10
指针与二维数组的关系
通过指针常量去访问数组的元素
数组指针和指针数组
数组指针
谁在后面,那么这个东西的本质就是谁
数组指针:本质是一个指针
概念
指向数组的指针
定义
存储类型 数据类型 (*指针变量名) [元素的个数];
数据类型:数组指针指向的数组中元素的数据类型
* 和 [] :谁的优先级更高,[],可是,我们现在要定义的是一个指针,所以要让变量名先与*接触,所以,要将*与变量名用()括起来;
元素的个数:一维数组中元素的个数
int a; //数据类型 int
Int *p;//数据类型int*
P = &a;//一个指向整型变量的指针
Int arr[5]={0};//定义了一个整形数组 int [5]
Int (*p)[5]= NULL;//数据类型,int(*)[5]
P = &arr;
数组名:
1、表示数组中首元素的地址
- 整个数组
数组指针与一维数组
注意:数组指针几乎是不用来操作一维数组,更多的是用来操作二维数组。因为指针在访问连续的内存空间才有意义,如果是一维数组,p+1就会越界
数组指针与二维数组
指针数组
本质:指针数组,是一个数组
整型数组:数组中的元素是整型
字符数组:数组中的元素是字符
指针数组:数组中的元素是指针(地址)
概念
元素为指针的数组
定义
以前定义一个整型数组:
Int arr[5];//定义了一个数组,数组中有五个元素,元素都是int类型
定义一个指针数组:
存储类型 数据类型 *变量名[元素的个数];
数组名先和*还是[ ]结合?
:此时变量名先和[ ]结合,所以定义的这个本质是一个数组
数据类型 * :数组中元素的数据类型
Int * arr[3];
//定义了一个数组,数组名为arr,数字组中有三个元素,每一个元素都是int *;
指针数组与二维数组