day6
假设我们要定义1000个int类型的变量,通过上周的学习挨个去定义无疑是没有效率的。
使用数组去进行1000个int类型的变量是非常快速的;//int str【1000】,其中有1000个元素,每一个元素类型都是int类型。str【0】----str【999】;
1、数组概念
一组数据类型相同的元素的集合
特点:1、数据类型相同2、地址连续。通过“%p”打印地址

2、定义数组
存储类型 数据类型 变量名;
int a;
存储类型:auto、static、extern、register
存储类型 数据类型 数组名【元素的个数】;
int arr【5】;
//分配了一片内存空间,该内存空间存放5个int类型的元素,
数据类型:数组中元素的数据类型
数组所占的内存空间 = sizeof (数据类型)*元素的个数
//注意:1、int【5】和int【6】数据类型不相同。
2、数组的数据类型:去掉变量名,剩下的就是数据类型

数组名:1、数组首元素的地址2、整个数组

元素的个数:必须为一个确定的值(分配的内存大小是固定的)
3、初始化
3.1部分初始化
int arr【5】={1,2,3};
arr【0】=1 ,arr【1】=2,arr【2】= 3 ,arr【3】,arr【4】???
//部分初始化时:没有初始化的部分,其值为0,利用此特性,可以给数组清零;
如何给数组清理?
int arr【100】={0};

3.2全部初始化
int arr【5】={1,2,3,4,5};
int【 】= {1,2,3};//此时元素的个数可以省略,编译器它会自动计算元素的个数(只有在全局初始化时,才可以省略元素的个数)

总结:
在函数体内,定义一个数组(相当于在函数体内,定义一个变量),其值为随机值
在函数体外,定义一个数组(相当于在函数体外,定义一个变量),其值为0
在函数体内,用static修饰的数组(static修饰是一个局部变量),其值为0

4、访问
数组名【下标】;
下标从0开始;


案例:实现对数组的输入和输出

案例:判断对错

5、冒泡排序

如上图所示,冒泡排序:从左往右依次比较,前一个数比后一个数大位置交换,反之,不变!
总结:5个数交换4趟,每一趟比较4-1次。N个数交换N-1趟,比较N-1-J次。i为趟数j为次数。

定义一个中间变量:实现交换,每一趟比较,都会得到一个最大的数!

案例:

6、字符数组
整型数组:存储一堆整型数
存储类型 数据类型 数组名【元素的个数】;
int a【10】;
//分配了10个4字节大小的空间;里面保存了10个int类型的元素
字符数组:存储一堆字符
存储类型 数据类型 数组名【元素的个数】;
char str【10】
数据类型:元素的数据类型
字符数组的数据类型:char【10】;
//分配了10个1字节大小的空间,里面保存10个char类型的元素
字符串在c语言中如何保存?
int :10,20,30,
char:‘a’,‘b’(保存字符)
float:3.14;
如何保存字符串?
“hello”有什么构成 ‘h’‘e’‘l’ 'l' 'o' '\0'
字符串用字符数组进行保存;
字符数组的本质:就是字符串
char str【6】={h’‘e’‘l’ 'l' 'o' '\0'};
char str【6】=“hello”;

字符串数组清零:
char str【10】={0};
char btr【10】={'\0'};
6.1字符串的输出函数
怎样去输出字符串:“%s”
puts(数组名);
功能:将数组中的内容打印到终端,并且自动换行;
注意:遇到'\0'结束


6.2字符串的输入函数
gets(数组名);
功能:将键盘接收到的字符串存放到数组中,并在末尾自动添加'\0'
注意:gets不会进行越界检查,所以输入的时候不要越界


7、总结
7.1gets和scanf的区别
1、scanf以空格、回车、tab作为输入结束的标志,gets以回车作为结束符
2、缓冲区:
gets:当字符串输入完毕之后,会清空缓冲区里面的东西
scanf:当字符串输入完毕之后,会在缓冲区内遗留空格、回车、tab键
3、gets先检查缓冲区内有没有东西,如果有,直接拿来用,没有的话,采取键入的方式
scanf:键入的方式
7.2puts和printf的区别
puts会自动添加换行,而printf不会。
day7
1、字符串的处理函数
strlen、strcpy、strcat、strcmp
头文件:#include <string.h>
1.1 求字符串的长度
strlen(数组名);
功能:求字符串的实际长度
返回值:求得的字符串的实际长度,不包含'\0'


strlen和sizeof的区别:
strlen计算的是字符串的实际长度(不包含‘\0’),sizeof计算的是整个空间的大小
strlen是一个函数,sizeof是一个运算符
案例:不使用strlen求字符串的实际长度


1.2字符串的拷贝函数
strcpy(数组1,数组2/字符串2);
功能:将数组2中的内容拷贝到数组1中,包含‘\0’,相当于完全拷贝
注意:数组1的长度要大于数组2


strncpy(数组1,数组2/字符串,n);
功能:将数组2的前n个字符拷贝到数组1中




案例:不适用strcpy函数实现字符串的拷贝!


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、二维数组
概念
数组:一组数据类型相同的元素的集合
整型数组:一组int类型的数集合在一起
字符数组:一组char类型的字符集合在一起
二维数组:(数组的数组):一组(数组类型的)元素集合在一起
本质:概念:元素为一维数组的一维数组
特点:1、数组类型相同2、地址连续

2.定义
存储类型 数据类型 数组名【元素的个数】;
心态 a【3】;
数据类型:数组中元素的数据类型
数组的数组类型:int【3】(去掉数组名)
2.1定义二维数组
存储类型 数据类型 数组名【行数】【列数】;
int arr【行数】【列数】:
行数:一维数组的个数
列数:一维数组中元素的个数
数据类型:最里面的元素的数据类型
实际的元素的个数 = 行数*列数
内存空间:sizeof(最里面的元素的数据类型)*实际的元素的个数
3、初始化
3.1 部分初始化
int a【2】【3】={1,2};
int a【2】【3】={{1,2,3},{1}};
3.2全部初始化
int a【2】【3】={1,2,3,4,,5,6};
int a【2】【3】={{1,2,3},{4,5,6}};
int a【行数】【列数】;
思考:行数和列数是否可以省略?
行数是否可以省略?
int【】【3】={1,2,3,4};
行数:有几个一维数组,此时计算机可以自动计算出行数
列数是否可以省略?
int a【2】【】={1,2,3,4};
列数:一维数组中元素的个数?
有两个一维数组,但是每一个一维数组中不知道存放几个元素
注意:二维数组在进行全部初始化时,行数可以省略,列数不可以省略!!
4、访问
数组名【下标】


案例:打印杨辉三角



5、二维字符数组
二维整型数组:
存储类型 数据类型 数组名【行数】【列数】;
行数:一维整型数组的个数
列数:每一个一维整型数组中元素的个数
二维整型数组;
int a【2】【3】;
//定义了一个二维数组,该数组中有两个一维数组,每一个一维数组中有3个int类型的元素
二维字符数组:
存储类型 数据类型 数组名【行数】【列数】;
行数:(一维字符数组的个数)字符串的个数
列数:(一维字符数组中字符的个数)每一个字符串最多能够存几个字符
定义一个二维字符数组:
存储类型 数据类型 数组名【行数】【列数】;
char str【5】【20】;
//相当于定义了一个二维字符数组,该数组中有5个字符串,每个字符串最多能够使用20字节的空间。

day8
1、函数
函数:具有一定功能的模块
2、为什么要有函数
让程序变得模块化
提高代码的复用率
3、函数的分类
3.1库函数
printf scanf strlen strcpy strcat strcmp
3.1.1引入头文件
#include <stdio.h>
#include <string.h>
3.1.2调用函数
strlen(str);
函数名(实际的参数);
注意:参数的类型,参数的个数,返回值
int length;
length = strlen(str);
3.2 自定义函数
3.2.1 函数定义
存储类型 数据类型 变量名;
存储类型 数据类型 函数名(形式参数列表)
{
函数体;
返回值;return ;
}
存储类型:auto、static、extern、register
数据类型:返回值的数据类型
函数名:满足标识符的命名规则,见名知意:(用函数名描述当前函数要实现的功能)
形式参数列表:实现这个功能,需要什么参数(1、需要几个参数2、每个参数都是什么类型,)需要调用这自己区传入
函数体:实现功能所需要的代码
返回值:如果没有返回值,不需要写return,数据类型:void。如果有返回值,有且只能有一个返回值。
3.2.2 调用函数
函数名(实参);
注意:
需要将实参的值传递给形参,实参的个数和数据类型必须和形参一致
实参可以是变量、常量、表达式,必须是一个确定的值
实参和形参是两块独立的空间
传参实际上是将实参的值拷贝给形参
形参是局部变量,在函数调用的时候被定义,函数调用完毕释放

3.2.3 调用时:

3.2.4 调用完毕:

3.2.5 函数的声明:
如果自定义的函数在main函数之后,需要加上函数的声明
声明:将函数的头赋值,然后粘贴在程序的上面,加上分号;

声明的作用:帮助编译器做检查
案例:封装函数实现+-*/

4、指针
4.1什么是指针
指针是一种数据类型,一种保存地址的数据类型
int a;//int:用来保存整型数的数据类型
float b;//float:用来保存小数的数据类型
char c;//char:用来保存字符的数据类型
指针 d;//指针:用来保存地址的数据类型
4.2 地址是什么
整型数:1,2,3,4
小数:2.3,5.234
字符:‘a’ ‘B’
地址:0x100 0x104
内存分配的时候,最小的单位:字节;每一个字节都有一个编号,我们把这个编号叫做地址;
地址:内存单元的编号
地址就是指针
指针就是地址
指针的本质:内存单元的编号
4.3 指针变量
int a = 10;
a:整型变量 10:整型常量
a++;
10++;
0x100
指针常量:
什么是指针变量:
int a;//a就是整型变量
char b;//b就是字符变量
float c;//c就是浮点型变量
指针 d;//d就是指针变量
4.4 定义指针
存储类型 数据类型 *变量名;
int *p;
//定义了一个指针,编译器分配内存空间来保存地址,这片空间的名字叫做p
数据类型:指针指向的数据类型(去掉变量名和一个*,剩下的就是指针指向的数据类型)
指针的数据类型:int *(去掉变量名,剩下的就是数据类型)
存储类型:4个

间接访问
简介修改
*和&互逆:
int *p;
&a:获取a的地址
p = &a;//p指向a
*p = *(&a) = a;//取a这片地址里面的值

4.5指向(赋值:改变指针变量中保存的地址)
//将一个变量的地址赋值给指针,相当于指针指向他
int a = 10;
a = 20;

赋值时:注意类型匹配
指针变量中只能保存:他指向的数据类型的地址
注意:在所有的32os中,所有的指针都占据4个字节

在所有的64os中,所有的指针都占据8字节

4.6 空指针
零号地址:没有指针的指针,(NULL)
零号地址:禁止操作
但是可以指向

操作指针;改变指针的指向(赋值(地址))

4.7 野指针
不知道其指向的指针
局部变量:没有初始化,随机值
局部指针:没有指向NULL,随机指向

避免野指针:先让他指向零号地址
思考:为什么要有指针?
函数:实现两个数的交换
参数1:int
参数2:int
是否需要返回值?
在主函数中输出交换后的结果!
值传递

地址传递


day9
1、二级指针
1.1概念
本质:指针的指针(保存一级指针的地址)
二级指针的内存空间:用来保存一级指针的地址
1.2定义
定义一级指针:
存储类型 数据类型 *变量名;
int *p;
数据类型:指针指向的数据类型(p中保存的是整型数的地址)
一级指针的数据类型:(去掉变量名)int*
定义一个二级指针
存储类型 数据类型 *变量名;
int* *pp;
二级指针指向的数据类型:(二级指针中保存的是谁的地址):int*


总结:
指针的数据类型:(去掉变量名)
int *p//int *
int **p;//int **
int ***p;//int***
指针指向的数据类型:(去掉变量名和一个*,剩下的就是)
int *p;//int
char *p;//char
int **p;//int *
char **p;//char *
int ***p;//int **
指针能够访问到的内存空间的大小,由指针指向的数据类型所占的内存空间大小决定
int *p;//能够访问到的内存空间的大小:4字节:int
char *pp;//能够访问到的内存空间的大小:1字节:char
int **p;//所能访问到的内存空间的大小:4字节:int *
char **pp;//所能访问到的内存空间的大小:4字节:char *
2、指针的算术运算
测试:指针+1;加多大,加到了哪里(指向的数据类型)

总结:
p+n:p+n相当于指针向地址增大的方向移动了n个数据
(实际的变化:p+sizeof(指向的数据类型)*n)
p-n:p-n相当于指针向地址减小的方向移动了n个数据
(实际的变化:p-sizeof(指向的数据类型)*n)
p++:p向地址增大的方向移动了一个数据(移动sizeof(指向的数据类型)字节)
p--:p向地址减小的方向移动了一个数据(移动sizeof(指向的数据类型)字节)
p-q:(p和q的数据类型必须一致)这两个指针中相差的元素的个数
实际结果:(p-q)/sizeof(指向的数据类型)

注意:
指针的算术运算只有在操作连续的内存空间时,才有意义
p是指针变量,可以++,--,(指针常量也满足上面的算数运算规则,但是不可以++,--)
(数组名:1、数组首元素的地址(指针常量))
3、指针和一维数组的关系
3.1 指针常量与一维数组的关系
数组名:
数组首元素的地址,指针常量,不可以++,--
整个数组


数组名:指针常量,不可以++,--

3.2指针变量与一维数组的关系



注意:
1、printf中有表达式时,为右结合

2、

通过指针和数组之间的关系:(对数组进行输入输出)
指针移动:清楚指针在使用时指向谁!!!

冒泡排序
1、指针指向不发生改变

2、指针指向发生改变


4、指针和二维数组的关系



总结:
a、a【0】、&a【0】【0】、&a、&a【0】,他们的值都是一样的,但是意义不一样
a: int (*)【3】;此时a指向一维数组
为什么a不是int **
如果a时int **类型,那么a+1移动4字节,(int **类型指向的数据类型为int *)
但是我们发现a+1移动了12字节(一个一维数组),所以此时a不是int **类型
a指向a【0】,a【0】指向a【0】【0】
day10
1、数组指针
本质:指针
指向数组的指针
1.1概念
指向数组的指针
1.2定义
存储类型 数据类型 (*变量名)【元素的个数】;
int (*p)【5】;
此时p先和*结合,此时p的本质时一个指针
数据类型:指针指向的数组中的元素的数据类型
p的数据类型:int (*)【5】;
p指向的数据类型:int【5】;
*和【】的优先级:【】的优先级高于*的优先级;
p先和【】还是*结合,决定它的本质是什么东西;
【】:代表数组
*:代表指针
数组名:
数组首元素的地址:int *(指针常量)
整个数组:【5】(变量)
1.3 数组指针和一维数组的关系


注意:数组指针一般不去操作一维数组,因为p+1,移动了一个数组,指向了数组底部(我们没有申请到的内存空间),因此,我们一般使用数组指针操作二位数组。
1.4数组指针和二维数组的关系


2、指针数组
本质:数组
数组中保存的都是指针类型
2.1概念
数组中存放的元素都是指针类型
2.2定义
定义了一个数组;
存储类型 数据类型 数组名【元素的个数】;
数据类型:元素的数据类型 int
定义一个指针数组:
存储的元素的数据类型:int *
定义一个存储 int *类型的元素的数组
存储类型 数据类型* 数组名【元素的个数】;
int* a【3】;
此时变量名先和【】结合,所以此时a时一个数组


2.3 指针数组和二维数组的关系


3、const
const 修饰变量:
只读
(不能直接去修改!)



const修饰指针:
int *p
左数右指(const关于*的位置)
*p就是数,p指向
const int *p;
int const *p;

int *const p;

const int *const p;
int const *const p;

4、main函数传参
参数的个数
保存传入的字符串

本文详细介绍了C语言中的数组,包括概念、定义、初始化、访问以及特殊类型如字符数组和二维数组。指针部分讲解了指针的概念、定义、操作以及与一维和二维数组的关系。还讨论了函数的使用和自定义函数的声明、定义及调用。此外,文章提到了字符串处理函数如strlen、strcpy等,并简要介绍了函数参数传递中的值传递和地址传递。
1435

被折叠的 条评论
为什么被折叠?



