1> 将今天所敲课堂代码,自己手动实现一遍,并详细注释
2> 绘制思维导图
知识点一:值传递、地址传递、值返回、地址返回
#include <stdio.h>
//值传递
void swap(int m,int n)
{
int temp;
temp=m;
m=n;
m=temp;
printf("m=%d,n=%d\n",m,n);//123 0
}
//值传递
void fun(int *p,int*q)
{
int *temp;
temp=p;
p=q;
q=temp;
printf("*q=%d\t*p=%d\n",*q,*p);//123 0
printf("q=%p\tp=%p\n",q,p);
}
//地址传递
void gun(int *p,int *q)
{
int temp;
temp=*p;
*p=*q;
*q=temp;
printf("*q=%d , *p=%d\n",*q,*p);//123 0
printf("q=%p , p=%p\n",q,p);
}
//值返回
int hun()
{
int value=666;
return value;
}
//地址返回
int *iun()
{
static int value=666;
return &value;
}
int main(int argc, const char *argv[])
{
int num1=123;
int num2=0;
//调用swap函数交换两数
swap(num1,num2);
printf("swap使用后num1 = %d,num2 = %d\n",num1,num2);//123 0 成功交换
printf("swap调用后的地址num1=%p,num2=%p\n",&num1,&num2);
//调用fun函数交换两数
fun(&num1,&num2);
printf("fun使用后num1 = %d,num2 = %d\n",num1,num2);//123 0 成功交换
printf("fun调用后的地址num1=%p\tnum2=%p\n",&num1,&num2);
//调用gun函数交换两数
gun(&num1,&num2);
printf("gun使用后num1 = %d,num2 = %d\n",num1,num2);
printf("guh调用后的地址num1=%p\tnum2=%p\n",&num1,&num2);
//调用hun函数
int ret=hun();
printf("hun()=%d\n",ret);
//调用iun函数
int *ret1=iun();
printf("value=%p\n",ret1);
return 0;
}
运行结果:
m=123,n=0
swap使用后num1 = 123,num2 = 0
swap调用后的地址num1=0x7ffe66d3b0d4,num2=0x7ffe66d3b0d8*q=123 *p=0
q=0x7ffe66d3b0d4 p=0x7ffe66d3b0d8
fun使用后num1 = 123,num2 = 0
fun调用后的地址num1=0x7ffe66d3b0d4 num2=0x7ffe66d3b0d8*q=123 , *p=0
q=0x7ffe66d3b0d8 , p=0x7ffe66d3b0d4
gun使用后num1 = 0,num2 = 123
guh调用后的地址num1=0x7ffe66d3b0d4 num2=0x7ffe66d3b0d8hun()=666
value=0x55b65da46010
知识点二:内存分区
一个进程启动后,系统会为该进程分配4G的虚拟内存;3--4G是内核空间,主要与底层驱动打交道0-3G用户空间又被划分为三部分:栈区、堆区、静态区(全局区);全局区又分为四个段:.bss段、.data段、.ro段、.txt段
#include <stdio.h>
#include <stdlib.h>
int m; //未初始化的全局变量,在全局区的.bss段
int n=0; //已经初始化的全局变量,在全局区的.data段
static int k;//未初始化的静态变量,在全局区的.bss段
static int l=666;//已经初始化的静态变量,在全局区的.data段
char arr[100]="hello";//arr数组在全局的.data段,hello在全局区的.ro段
char *p="world";//指针在.data段,world 在全局区的.ro段
int main(int argc, const char *argv[])
{
int m1; //局部变量在栈区申请,初始值为随机值
int n1=0;//局部变量在栈区申请
static int k1;//静态局部变量,在全局区的.bss段申请
static int l1=666;//静态局部变量,在全局区的.data段申请
char arr1[100]="hello";//q在栈区申请的8字节,但是"hello"在全局区的.ro段
char *p1="world";//数组在栈区申请,"world"在全局区的.ro段
int *ptr=(int*)malloc(sizeof(int));//ptr是在栈区,而申请的空间在堆区
return 0;
}
知识点三:动态内存分配和回收(malloc、free)
C语言中可以使用malloc和free来对堆区空间进行操作
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
//在堆区申请一个int类型空间大小
int *p1 = (int *)malloc(4);//申请4字节大小
printf("*p1=%d\n",*p1);//随机值
int *p2 = (int *)malloc(sizeof(int));//申请一个int类型空间大小
*p2 = 520;//给堆区进行赋值
printf("*p2=%d\n",*p2);
//连续申请5个int类型的大小
int *p3=(int*)malloc(sizeof(int)*5);
//输出默认值
for(int i=0;i<5;i++)
{
printf("%d\t",*(p3+i));
}
printf("\n");
//释放堆区空间
free(p1);
p1=NULL;//防止野指针
free(p2);
p2=NULL;
free(p3);
p3=NULL;
return 0;
}
*p1=0
*p2=520
0 0 0 0 0
练习:要求在堆区申请6个int类型空间存放6名学生的成绩,分别使用函数实现申请空间、输入学生成绩、输出学生成绩、对学生进行升序排序、释放空间
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
//在堆区申请一个int类型空间大小
int *p1 = (int *)malloc(4);//申请4字节大小
printf("*p1=%d\n",*p1);//随机值
int *p2 = (int *)malloc(sizeof(int));//申请一个int类型空间大小
*p2 = 520;//给堆区进行赋值
printf("*p2=%d\n",*p2);
//连续申请5个int类型的大小
int *p3=(int*)malloc(sizeof(int)*5);
//输出默认值
for(int i=0;i<5;i++)
{
printf("%d\t",*(p3+i));
}
printf("\n");
//释放堆区空间
free(p1);
p1=NULL;//防止野指针
free(p2);
p2=NULL;
free(p3);
p3=NULL;
return 0;
}
运行结果: 申请成功
请输入第0学生成绩
33
请输入第1学生成绩
11
请输入第2学生成绩
100
请输入第3学生成绩
78
请输入第4学生成绩
7
请输入第5学生成绩
2
成绩录入完毕
排序成功
2 7 11 33 78 100
知识点四:类型重定义
(1)类型重定义与宏定义的区别
1> 宏定义只是单纯的替换,不做任何正确性检测,是一个预处理指令
2> 类型重定义,需要做正确性检测,是一条语句
3> 宏替换发生在预处理阶段,而类型重定义发生在编译阶段
4> 如果是对普通单个重命名没有问题,但是对指针重命名就有问题了
#include <stdio.h>
#define ptr_i int*
typedef int* pptr_i;
int main(int argc, const char *argv[])
{
ptr_i a,b; //a是指针类型,b是普通int类型
pptr_i m,n; //m和n都是指针类型
printf("sizeof a=%ld\n",sizeof(a));//8
printf("sizeof b=%ld\n",sizeof(b));//4
printf("sizeof m=%ld\n",sizeof(m));//8
printf("sizeof n=%ld\n",sizeof(n));//8
return 0;
}
//宏定义与类型重定义区别
知识点五:结构体
(1)结构体的格式
struct 结构体名
{
成员类型1 成员变量1;
成员类型2 成员变量2;
。。。
成员类型n 成员变量n;
};
注意: 1、struct是定义结构体的关键字
2、结构体名:是一个标识符,要符合标识符的命名规则,一般首字母大写
3、所有的成员属性使用一对花括号包裹,最后用分号结束,分号不能省略
4、成员属性类型可以是基本数据类型,也可以是构造数据类型
5、声明结构体不占内存空间,使用结构体类型定义变量时,变量会占用内存空间
6、一般将声明结构体放在文件头部或者头文件中,也可以声明在其他部分,但是,至少要声明在使用之前
(2)举例
//声明一个卡牌游戏人物结构体类型
struct Ssp
{
char name[20];//姓名
int Hp; //血量
char skill[20]; //技能
int kill; //击杀人数
};
(3)结构体变量的定义及初始化
#include <stdio.h>
//声明一个角色结构类型
struct Figue
{
char name[20];
char skill[20];
int Hp;
double speed;
};
int main(int argc, const char *argv[])
{
//定义角色变量
struct Figue f1={"暗夜英雄","审判,rua~",18000,6};
struct Figue f2={.skill="蹦蹦炸弹",.Hp=30000};
return 0;
}
(4)结构体指针访问成员
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//声明一个角色结构类型
struct Figue
{
char name[20];
char skill[20];
int Hp;
double speed;
};
int main(int argc, const char *argv[])
{
//使用角色类型定义一个角色变量
struct Figue f1={"暗夜英雄","审判,rua~",18000,6};
struct Figue f2={.skill="蹦蹦炸弹",.Hp=30000};
//输出角色变量f1中的所有内容
printf("f1.name=%s\n",f1.name);
printf("f1.skill=%s\n",f1.skill);
printf("f1.Hp=%d",f1.Hp);
printf("f1.speed=%lf",f1.speed);
//在堆区申请一个角色类型,完成初始化并输出相应属性
struct Figue *ptr=(struct Figue*)malloc(sizeof(struct Figue));
//给角色名字赋值
strcpy(ptr->name,"伞兵\n");//给姓名赋值
strcpy(ptr->skill,"把头低下\n");//给角色技能赋值
ptr->Hp=20000;
ptr->speed=20;
//输出角色指针指向堆区空间的内容
printf("角色名称为:%s\n",ptr->name);
printf("角色技能为:%s\n",ptr->skill);
printf("角色血条为:%d\n",ptr->Hp);
printf("角色速度为:%lf\n",ptr->speed);
return 0;
}
运行结果
f1.name=暗夜英雄
f1.skill=审判,rua~
f1.Hp=18000f1.speed=6.000000
角色名称为:伞兵角色技能为:把头低下
角色血条为:20000
角色速度为:20.000000