数据结构相关C语言
第一章 数据类型
1.1基本数据类型
- 整型——int
- 浮点型——float
- 字符型——char
- 布尔型——只有两种类型:true(1)、false(0)
1.2输入输出
1.2.1 输入
- 整型:scanf("%d",&a);
- 浮点型:scanf("%f",&b);
- 字符型:scanf("%c",&c);
- 多个变量连续输入:scanf("%f %c",&a,&b);
&为取地址运算符,用于获取变量的地址,在变量前使用&,会返回该变量在内存的地址 %为占位符,用于告诉计算机这个位置的数据类型,占位符和变量的个数与类型一一对应
int a=0;//定义整型a并初始化为0
int *p=&a;//取变量a的地址存放到整型指针变量p中
int age;
scanf("%d",&age);//使用scanf输入函数,为age变量赋值
1.2.2 输出
- 整型:printf("%d",a);
- 浮点型:printf("%f",b);
- 字符型:printf("%c",c);
- 多个变量连续输入:printf("%f %c",a,b);
%为占位符,用于告诉计算机这个位置的数据类型,占位符和变量的个数与类型一一对应
第二章 基本运算
2.1常用算术运算符
+、-、*、\、%
int a =10,b=6;
printf("%d",a+b);//16
printf("%d",a-b);//4
printf("%d",a*b);//60
printf("%d",a/b);//自动向下取整,10除以6为1.666,输出整数,自动向下取整,结果为1
printf("%d",a%b);//a对b取余,结果为4
- 两个操作数都为整型时,其运算结果也为整型,如果运算结果为小数时,则直接舍去小数部分,即自动向下取整;
- 当操作数中有一个为浮点型时,运算结果为浮点型,例如int a=3;a*2.0=6.0;
- 取余运算符的操作数只能是整型,因为浮点型没有余数。
2.2赋值运算符
int a=3;
赋值运算符 | 例子 | 说明 | 结果 |
---|---|---|---|
= | a=5 | 将右边的值赋给左边 | a=5 |
+= | a+=5 | a=a+5 | a=8 |
-= | a-=5 | a=a-5 | a=-2 |
*= | a*=5 | a=a*5 | a=15 |
/= | a/=5 | a=a/5 | 0 |
%= | a%=5 | a=a%5 | 3 |
- =具有方向性,把右边的值赋给左边
- 不允许连续赋值,只能int x=1,int y=1;
- 假设a的变量为3,b的变量为2,执行a=b+3后,a的值为5,b的值不变
2.3关系运算符
int a =3,b=2;
关系运算符 | 例子 | 说明 | 结果 |
---|---|---|---|
> | a>b | a大于b | 真(1) |
>= | a>=b | a大于等于b | 真(1) |
< | a<b | a小于b | 假(0) |
<= | a<=b | a小于等于b | 假(0) |
== | a==b | a等于b | 假(0) |
!= | a!=b | a不等于b | 真(1) |
2.4逻辑运算符
逻辑运算符 | 说明 |
---|---|
&& | 逻辑与(并且) |
|| | 逻辑或(或者) |
! | 逻辑非(相反) |
a | b | a&&b | a||b | !a | !b |
---|---|---|---|---|---|
真 | 真 | 真 | 真 | 假 | 假 |
真 | 假 | 假 | 真 | 假 | 真 |
假 | 真 | 假 | 真 | 真 | 假 |
假 | 假 | 假 | 假 | 真 | 真 |
- 表达式或者变量值如果非0代表为真,0代表为假,非0包括所有正数或者负数
- 有三个变量a,b,c,且值都为3时,判断三个变量是否相等:(ab)&&(bc)为真,三个变量才相等
2.5 自增运算符和自减运算符
2.5.1 自增运算符 ++
- 用途:将变量的值增加1
- ++i:先让i 的值增加1,在使用
- i++:先使用i,然后再让i 的值增加1
int i=0,x,y;//定义整型i,x,y,并且将i赋值为1
x=++i;//先让i的值增加1,然后再使用i给x赋值
y==i++;//先使用i给y赋值,然后将i的值增加1
printf("%d %d %d",x,y,i);//打印结果为:1,1,2
int i=0,j=0;//定义i和j,初始化值为0
++i;//先让i自增1,然后在使用
j++;//先使用j,然后j再增加1
printf("%d %d",i,j);//打印结果为:1,1
2.5.2 自减运算符
- 用途:用于将变量的值减去1
- –i:先将i 的值减去1,然后再使用i
- i++:先使用i ,然后再将i 的值减去1
2.5.4
- 从左往右看,先看见变量名,就先使用,先看见符号就先自增或者自减
2.6 其他运算符
- &:取地址运算符
- sizeof();用于计算括号内变量或者数据类型所占字节数
- 表达式1?表达式2:表达式3;条件运算符,如果表达式1为真,则执行表达式2,如果表达式1为假,则执行表达式3
2.7 运算符优先级
运算符 | 说明 | 优先级 |
---|---|---|
() | 小括号 | 1 |
++ | 后置自增 | 2 |
– | 后置自减 | 3 |
! | 逻辑反 | 4 |
+ | 正值 | 5 |
- | 负值 | 6 |
++ | 前置自增 | 7 |
– | 前置自减 | 8 |
& | 取地址符 | 9 |
sizeof | 计算长度 | 10 |
* | 乘法 | 11 |
/ | 除法 | 12 |
% | 取余 | 13 |
+ | 加法 | 14 |
- | 减法 | 15 |
> | 大于 | 16 |
>= | 大于等于 | 17 |
< | 小于 | 18 |
<= | 小于等于 | 19 |
== | 等于 | 20 |
!= | 不等于 | 21 |
&& | 逻辑且 | 22 |
|| | 逻辑或 | 23 |
?: | 条件运算 | 24 |
= | 直接赋值 | 25 |
+= | 复合赋值 | 26 |
-= | 复合赋值 | 27 |
*= | 复合赋值 | 28 |
/= | 复合赋值 | 29 |
%= | 复合赋值 | 30 |
第三章 条件判断语句
3.1 if语句
-
if 语句语法结构
if(表达式){ 语句1; 语句2; ... 语句n; }
-
表达式为真,执行代码块内的所有代码,表达式为假,if语句结束
3.2 if else语句
-
if else语句语法结构
if(表达式){ 语句1; ... } else{ 语句2; ... }
-
表达式为真,执行语句1所在代码块内的代码,表达式为假,执行语句2所在代码块内的代码(二选一)
3.3 if else if else语句
-
if else if if语句语法结构
if(表达式1){ 语句1; ... } else if(表达式2){ 语句2; ... } else{ 语句3; ... }
-
表达式1为真,执行语句1所在代码块内的所有代码,表达式2为真,执行语句2所在代码块内的所有代码,表达3为真,执行语句3所在代码块内的所有代码
-
else if语句可以有多个(多选一)
-
如果条件判断语句代码块只有一句代码,{}可以省略
3.4 switch case 语句
-
switch case语句语法结构
switch(变量){ case 1: 语句1; case 2: 语句2; break; ... default: 语句n; }
-
根据switch后的变量,找到程序入口,开始执行
-
break:跳出switch case语句,如果没有break,程序找到匹配的case之后,会一直依次向下执行,直到遇到break语句
第四章 循环语句
4.1 while 循环
-
while循环语法结构
while(表达式){ 语句1; 语句2; ... 语句n; }
-
表达式为真时,执行花括号内循环体代码,执行完成后再次判断表达式真假,如果为真,则继续重复执行循环体内容,直到表达式为假,才跳出while循环
-
while循环内要更新循环变量的值,否则可能出现死循环的情况
-
while循环中的break和continue
break:直接结束整个while循环
continue:结束本次while循环,本次循环continue以及后面的循环体代码不再执行,直接跳转判断表达式
4.2 for 循环
-
for循环语法结构
for(表达式1;表达式2;表达式3){ 语句1; 语句2; 语句3; ... 语句n; }
-
表达式1:初始化循环变量
表达式2:判断循环是否继续执行
表达式3:更新循环变量
-
先执行表达式1的代码,初始化循环变量,然后判断表达式2是否为真,如果为真,则执行花括号内循环体代码,执行完成后执行表达式3的代码,更新循环变量,然后再次执行表达式2,判断表达式真假,如果真表达式为真,继续重复此过程,直到表达式为假,才可跳出for循环
-
表达式1的循环变量只在该循环内使用
-
如果for循环不需要省略,则表达式1可以省略,但是分号不能省略 比如for(;i <= 100;i ++)
-
for循环可以用多个循环变量,循环变量的初始化和更新代码可以有多个,用逗号隔开,比如for(i =1,j=100 ; i<=50&&j>=51 ; i++, j–)
-
for循环中break和continue
break:直接结束整个for循环
continue:结束本次for循环,本次循环continue以及后面的循环体代码不再执行,直接跳转到表达式3,更新循环变量
4.3 do while 循环
-
do while循环语法结构
do{ 语句1; }while(表达式)
-
先执行一次语句1所在代码块的循环体代码,然后判断while内的表达式,如果为真,继续执行循环体,重复进行这个过程,直到表达式为假,则跳出循环
-
do while循环至少执行一次循环体
4.4 写循环的条件判断表达式时,建议把循环的临界条件写出来,再去写循环条件会更直观
第五章 指针
5.1 指针基本概念
-
指针通俗的来说,就是一个地址
-
口头语所说的指针其实是指针变量,也就是保存地址的变量
-
int main(){ int a;//定义整型变量a char c;//定义字符型变量c int* p=&a;//定义整型指针p char* q=&c;//定义字符型指针q return 0; }
-
指针变量保存的是地址,在32位的系统中,指针变量大小是4字节,在64位系统中,指针变量大小是8字节
-
指针变量区分类型的原因是,不同类型指针变量访问内存空间权限不同,整型指针可以访问4个字节,字符型指针可以访问1个字节
5.2 指针的使用
int age =24;//定义整型变量age,值为24,地址为0x0000 0002
char eva = 'A';//定义字符型变量eva,值为A,地址为0x0000 0026
int* p=&age;//定义整型指针p
char* q=&eva;//定义字符型指针q
*p=25;//修改age的值为25
printf("age=%d, eva=%c",*p,*q);
如果把指针看作地址,*可以看作钥匙,因此可以查看变量值或者改变变量值
*p可以看作变量age
*q可以看作变量eva
5.3 如何定义一个指针
-
int* p
*放在数据类型后
优点:符合基本数据类型变量的定义习惯
缺点:当定义同一个类型的多个变量指针时,*只会和相邻的结合
int* p,r,q中,p为整型指针,r和q为整型变量
-
int *p
*放在变量名前
优点:定义同一个类型的多个指针变量时,不容易造成误会
缺点:不符合基本数据类型的定义习惯
5.4 空指针
- 如果一个指针没有指向任何变量,或者没有保存任何变量的地址,则称其为空指针(NULL)
5.5 malloc函数和free函数
int main(){
int a=0;//定义整型变量a
int *p=NULL;//定义整型指针并初始化
p=(int *)malloc(sizeof(int));//动态分配4个字节(整型)的内存
*p=3;//为p指向的内存空间赋值为3
printf("p指向地址存储数据为%d",*p);
free(p);//释放指针p指向的内存空间
p=(int *)malloc(sizeof(int)*10);//为指针p动态分配10个整型变量的内存
free(p);//释放指针p所指的内存空间
renturn 0;
}
sizeof() :用于计算括号内变量或者数据类型所占的字节数
5.5.1 malloc函数
- 动态分配指定大小的内存空间
- 语法为(强制转换起始地址类型)malloc(分配内存空间大小);
- 默认返回空指针类型,所以要强转
5.5.2 free 函数
- 释放动态分配的内存空间
- 语法为 free(释放内存空间地址);
- 执行free(q)之后,只是把指针p指向的内存空间释放了,指针p并没有消失,只是此时指针p存储的地址没有意义了,但是指针p可以继续使用
第六章 数组
6.1 数组的基本概念
- 数组是用来存储相同类型元素的集合
- 数组的各个元素在内存中是连续存储的,第一个元素在低地址,第二个元素在高地址
- 数组下标从0开始,即下标为0的元素是第一个元素
6.2 数组如何定义
#define MAXSIZE 100
int main(){
int A[10];//定义静态数组A,长度为10
int n;//定义整型变量n
scanf("%d",&n);//输入n的值
int B=(int *)malloc(sizeof(int)*n);//定义动态数组B,元素个数为n个,数据类型为int
char C[MAXSIZE];//定义静态数组C长度为MAXSIZE
for(int i=0;i<10;i++){//用for循环为A数组赋值,即初始化A
A[i]=i;
}
free(B);
return 0;
}
6.2.1 静态数组
数组类型 数组名[元素个数];
6.2.2 动态数组
(指针类型)malloc(sizeof(数据类型)*元素个数);
6.2.3 如何确定数组类型
- 数组元素个数确定时,采用静态数组
- 数组元素个数不确定时,采用动态数组
6.2.4 数组的初始化
- 创建数组的同时给数组中的元素赋初始值
6.3 字符数组
int main(){
char A[4]={'a','b','c','d'};//定义数组A并初始化
char B[5]="azhi";//定义数组B并初始化
char C[5];//定义数组C
for(int i=0;i<4;i++){//打印数组A
printf("%c",A[i]);
}
printf("%s",B);//打印数组B
printf("%s",C);//打印数组C
renturn 0;
}
- 字符数组存储字符串,字符串后面默认跟一个’\0’作为字符串的结束符
- 字符串的占位符为%s
- 数组名就是数组的地址,所以使用scanf为数组赋值字符串时,后面不用取地址符,如scanf("%s",C);
- 为单个元素赋值时,需要加取地址符 ,如scanf("%c",&A[0]);
6.4 二维数组
int main(){
int A[3][5];//定义二维数组A,为3行5列
for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
scanf("%d",&A[i][j])
}
}//初始化二维数组A
for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
printf("%d",&A[i][j]);
}
}
return 0;
}
- 二维数组在内存中是连续的
第七章 结构体
7.1结构体定义
-
结构体是一种自定义的数据类型,可以包含不同的数据成员
-
结构体里面的内容叫结构体的成员变量,这些成员可以是不同的数据类型,如整数,浮点数,字符,其他数据结构或数组
-
结构体就相当于自己所定义的一种新的数据类型
-
使用该数据类型定义一个结构体变量,那该结构变量将包含结构体里的各个成员变量
-
结构体最后要有分号
struct student{//定义该结构体即新数据类型的名字叫struct student char name[20];//姓名 int age;//年龄 float weight;//体重 int score;//分数 }a;//声明结构体并定义结构体变量a
7.2 typedef的使用
-
typedef可以为数据类型起一个新名字,使用方法为:typedef 原类型名 新类型名;
-
typedef struct student{ char name[20];//姓名 int age;//年龄 float weight;//体重 int score;//分数 }stu,*stup;
-
使用typedef前 使用typedef后 结构体类型 struct student stu 结构体指针 struct student* stup 定义结构体变量a struct student a; stu a; 定义结构体指针b struct student* b; stup b;
7.3 结构体的使用
typedef struct student{
char name[20];//姓名
int age;//年龄
float weight;//体重
int score;//分数
}stu,*stup;
int main{
stu a;//定义结构体变量a
stup b;定义结构体指针b
(stup)malloc(sizeof(stu));//定义结构体b
scanf("%s",a.name);//为a中的成员name赋值
a.age=24;//为a中成员age赋值
a.weight=75.5;//为a中成员weight赋值
a.score=150;//为a中成员score赋值
printf("%s,%d,%f,%d",a.name,a.age,a.weight,a.score);
scanf("%s",b->name);//为b中成员name赋值
b->age=25;//为b中成员age赋值
printf("%s的年龄为%d",b->name,b->age);
return 0;
}
- 结构体变量访问结构体内成员用**.**
- 结构体指针访问结构体内成员用->
7.4 数据结构中的结构体实例
-
顺序表结构体
#define MAXSIZE 100 typedef struct SqList{//顺序表结构体 int date[MAXSIZE]; int length; }SqList;
未省略原结构体名
#define MAXSIZE 100 typedef struct{//顺序表结构体 int date[MAXSIZE]; int length; }SqList;
已省略原结构体名
-
链表结构体
typedef struct LNode{ int data; struct LNode *next; }LNode,*LinkList;
-
当结构体内含有本结构体指针成员时,原结构体名不能省略而且结构体指针成员也要写原结构体名,因为typedef重命名操作还没完成
第八章 函数
8.1 函数的基本概念
8.1.1 定义:
将一组完成一个功能或者多个功能的语句放在一起的代码结构
8.1.2 函数的组成
double area (double a,double b){
double S;
S=a*b;
return S;
}
double 返回类型 area函数名 (double a,double b 形式参数){
double S;函数体
S=a*b;函数体
return S;返回值
}函数:工厂,形式参数:商品生产原材料,函数体:流水线,返回值:生产出的商品
8.2 函数的返回类型与返回值
返回类型 | 返回值 |
---|---|
void | return;(也可省略此句代码); |
int | return 整型变量或整型值; |
float | return 单精度浮点型变量或浮点数; |
double | return 双精度浮点型变量或浮点数; |
char | return 字符型变量或单个字符; |
bool | return true或false; |
结构体类型 | return 结构体变量; |
指针类型 | return 指针变量或NULL; |
- 函数返回值的类型必须和函数的返回类型相匹配
- 如果函数没有返回值,则返回类型为void,返回值可以写return或者直接省略不写返回值
- 执行return语句将直接结束本次函数的执行,并返回值,不再执行函数内的后续代码
8.3 函数的参数
double area (double a,double b){
double S;c
S=a*b;
return S;
}
int main(){
double length=2.0,width=1.0;
double S=area(length,width);
printf("长方形的面积为%lf",S);
return 0;
}
8.3.1 形式参数
- 又称形参,是指定义函数时,小括号中的变量,在上述代码中,形参为a和b
- 形参是想要完成题目要求,题目需要提供的东西
- 形参可以没有,也可以有很多个,多个形参需要用逗号隔开
- 如果有形参,需要写明其数据类型和名字
8.3.2 实际参数
- 又称实参,是指调用函数时,传给函数的参数,在上述代码中为length和width
- 调用函数方法:函数名(实参,…,实参);示例:area(length,width);
- 调用函数 时写实参不需写明数据类型,但是实参的数据类型,个数,形式应与形参一致
8.4 主函数
主函数是程序执行的起点,其函数名固定为main,返回类型固定为int,不需要写参数,主函数最后返回0代表其正常执行结束