012-堆,结构体
堆空间的申请和释放
堆空间特点?
栈空间的特点是,自动申请自动释放
堆空间由用户自己主动申请,主动释放
利用函数malloc进行堆空间的申请
利用函数free进行堆空间使用完毕后的释放
问题:
局部变量的存储空间在栈区;
全局变量的存储空间在data/bss区;
区别是有初始化data,无初始化bss;
常量字符串的存储空间在rodata区;
通过malloc申请的空间在堆区;
如何申请堆空间?如何释放空间?
函数malloc用来申请堆空间
函数free用来释放堆空间
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
参数:
size:用来向系统表明将要申请的堆空间的大小
单位字节
返回值:
成功时,返回申请的堆空间的首地址
失败时,返回NULL
参数:
ptr:申请的堆空间的地址
注意:
释放时,必须释放的是申请的堆空间
注意:
对空间申请成功时,会被初始化为0
释放时,首个类型空间会被初始化0
例子:
int a[10];
想要申请一块和a一样的堆空间,怎么办?
malloc(sizeof(a));
或者
malloc(sizeof(int)*10);
或者
malloc(4*10);
int *p = (int *)malloc(40);
申请了一块40字节的堆空间进行使用
把malloc的返回值强制类型转换成int *
就相当于把malloc申请的空间切割成一个又一个的4字节空间进行使用
char *q = (char *)p;
请指出下面每一行代码的含义,如果有错误,则说明原因?
1)
char A[10] = "hello";
在栈区连续申请10个字节,然后使用变量A间接访问这片内存空间。
在常量区连续申请6个字节,然后存放着字符串hello。
然后将常量区的hello拷贝到A所对应的空间上。
strcpy(A,"world");
在常量区连续申请6个字节,然后存放字符串world
将常量区的字符串world复制到地址A所在的存储空间上
2)
char *p = "hello";
在常量区连续申请6个字节,然后存放字符串hello
在栈区连续申请4个字节,然后使用变量p间接访问这片存储空间
用来存放一个char型地址值
然后将常量区的hello的首元素h的地址存放在p的存储空间上
以下两句有问题:
strcpy(p,"world");
在常量区连续申请6个字节,然后存放字符串world
将常量区的字符串world复制到指针p所指向的存储空间上
该语句写法正确,但是意义错误
因为常量区不能被更改
*p = "world";
在常量区连续申请6个字节,然后存放字符串world
表示的意义是想把字符串world放在p所指向的地址空间上
但是类型上不匹配
p = "world";
在常量区连续申请6个字节,然后存放字符串world
使char型指针p重新指向一个新的常量字符串,是可以的
3)
char A[10];
在栈去连续申请10个字节,然后使用变量A间接访问这块存储空间
A这块空间没有进行初始化,所以是随机内容
strcpy(A,"hello");
在常量区连续申请6个字节,然后存放字符串hello
将常量区的字符串hello复制到地址A所在的存储空间上
4)
char A[10];
在栈去连续申请10个字节,使用变量A间接访问这块存储空间
char *p = A;
在栈区连续申请4个字节,使用变量p间接访问这块存储空间
用来存放一个char型的地址值
A在这里表示数组A的首元素的地址
使char型指针p指向数组A的首元素的地址
strcpy(p,"hello");
在常量区连续申请6个字节,然后存放字符串hello
将常量区的字符串hello复制到地址p所指向的地址空间上
即是数组A的存储空间
5)
char A[10];
在栈区连续申请10个字节,然后使用变量A间接访问这块存储空间
数组A的存储空间中的数据是随机的
char *p = A;
在栈区连续申请4个字节,使用变量p间接访问这块存储空间
用来存放一个char型的地址值
A在这里表示数组A的首元素的地址
使char型指针p指向数组A的首元素的地址
p = "hello";
在常量区连续申请6个字节,然后存放字符串hello
使char型指针p重新指向一个新的常量字符串,是可以的
6)
char *p = malloc(sizeof(char)*10);
在堆区申请一块连续的10字节大小的存储空间
在栈去申请一块连续的4字节大小的存储空间,使用p间接访问该块空间
然后使用p访问对应空间,保存申请的堆空间的首地址
p = "hello";
在常量区连续申请6个字节,然后存放字符串hello
使char型指针p重新指向一个新的常量字符串,是可以的
7)
char *p = malloc(sizeof(char)*10);
在堆区申请一块连续的10字节大小的存储空间
在栈去申请一块连续的4字节大小的存储空间,使用p间接访问该块空间
然后使用p访问对应空间,保存申请的堆空间的首地址
strcpy(p,"hello");
在常量区连续申请6个字节,然后存放字符串hello
将常量区的字符串hello复制到地址p所指向的地址空间上
即是申请的堆空间
结构体:
什么是结构体?
- 不同变量类型的集合
- 当目标比较复杂,需要多维的数据进行描述时
- 进行结构体类型的定义打包,方便对某一个体的信息进行统一管理
结构体可以包含什么类型?
- 基本数据类型:
char/short/int/long/float/double - 复合类型:
数组 - 整型数组/字符数据、、、
指针数组
结构体数组
指针 - 整型指针/字符指针、、、
数组指针/函数指针
结构体指针
函数?
不能
怎样定义结构体类型?
格式:
struct 结构体类型名
{
char a;
short b;
int c;
long d;
float e;
double f;
int g[5];
char *h;
int (*i)();
...
...
}
理解:
结构体类型是被自由定义
(struct 结构体类型名)就相当于int、char、、、
它可以被认为是一种的新的自定义的变量类型
例子:
struct stu //用来描述学生的相关信息
{
char name[20];
char sex[6]; //man/woman
int year;
char num[20];
};
(struct stu)将被视为一种新的变量类型,由自定义而成
结构体的大小怎么算?
由结构体内的所有成员共同决定;
例子:
struct stu
{
char name[20]; //20字节 20
char sex[6]; //6字节 8
int year; //4字节 4
char num[20]; //20字节 20
};
请问sizeof(struct stu)=? 52
struct a
{
char a[5];//5 8
int b; //4 4
char c; //1 4
int d; //4 4
short e; //2 4
};
请问sizeof(struct a)=? 24
struct b
{
int a; //4 8(64bit)
long long b; //8 8
};
请问sizeof(struct b)=? 12 32bit
16 64bit
struct c
{
long long b;
int a;
};
请问sizeof(struct c)=? 12 32bit
16 64bit
练习:
struct temp
{
char a[4]; //4 4
short b[2]; //4 4
char c; //1 2(最大类型是short,所以补2即可)
short d; //2 2
char e; //1 2(最大类型是short,所以补2即可)
};
sizeof(struct temp)=? 14
怎样定义结构体变量?
例子:
struct stu
{
char name[20]; //20字节
char sex[6]; //6字节
int year; //4字节
char num[20]; //20字节
};
声明一个对应结构体类型的变量
格式:
结构体类型+变量
例子:
struct stu student_1;
student_1就是对应的(struct stu)类型的结构体变量
怎样定义结构体指针变量?
例子:
struct stu
{
char name[20]; //20字节
char sex[6]; //6字节
int year; //4字节
char num[20]; //20字节
};
声明一个对应结构体类型的指针变量
格式:
结构体类型+*+变量
例子:
struct stu *p;
p就是对应的(struct stu)类型的结构体指针
怎样访问结构体成员?
1.
利用结构体的变量
首先需要定义一个结构体类型变量
想要访问结构体的成员变量时
需要与结构体类型变量产生联系
格式:
结构体变量名.结构体的成员变量名
例子:
struct stu student_1;
stpcpy(student_1.name,"张三");
stpcpy(student_1.sex,"男");
student_1.year = 20;
stpcpy(student_1.num,"110119120");
2
利用结构的指针变量
2.1
首先需要定义一个结构体类型变量
其次需要定义一个结构体类型指针变量
且使结构体指针变量指向结构体普通变量
想要访问结构体的成员变量时
需要与结构体类型变量产生联系
格式:
结构体指针变量名->结构体的成员变量名
例子:
struct stu student_1;
struct stu *p = &student_1;
stpcpy(p->name,"张三");
stpcpy(p->sex,"男");
p->year = 20;
stpcpy(p->num,"110119120");
2.2
首先需要定义一个结构体类型变量
其次需要定义一个结构体类型指针变量
且使结构体指针变量指向为结构体申请的一块连续的堆空间
想要访问结构体的成员变量时
需要与结构体类型变量产生联系
格式:
结构体指针变量名->结构体的成员变量名
例子:
struct stu student_1;
struct stu *p = (struct stu *)malloc(sizeof(struct stu));
stpcpy(p->name,"张三");
stpcpy(p->sex,"男");
p->year = 20;
stpcpy(p->num,"110119120");
总结:
指针的指向必须有意义才能被使用
写程序是注意观察指针使用前的指向
结构体初始化
1.相同类型的结构体变量可以直接进行整体赋值;
2.定义对应的结构体类型变量时可直接进行整体初始化;
3.定义对应的结构体类型变量时可进行部分初始化;
按顺序对目标量进行初始化赋值;
未进行初始化赋值的结构体成员变量将被初始化为0;
4.不建议在定义对应的结构体类型变量时进行针对性的初始化;
练习:
定义个结构体,表示学生成绩档案
包括姓名、学号、语文成绩、数学成绩、英语成绩
以上数据均通过键盘进行输入
为5个学生进行数据输入
数据输入完毕之后打印查看
功能:
1.可通过学号或姓名查看指定目标的相关成绩
2.可指定查看对应学科或总分的排名
3.可查看对应学科或总分的平均分
参考答案:
#include<stdio.h>
#include <strings.h>
struct stu
{
char name[20];
char id[20];
int yw;
int sx;
int yy;
};
struct stu stu[5];
int switch_1()
{
char buf[20];
int i;
switch(1)
{
printf("请输入查询目标的姓名或学号\n");
bzero(buf,sizeof(buf));
scanf("%s",buf);
for(i=0;i<5;i++)
{
if(!strcmp(buf,stu[i].name))
{
printf("名字:%s",stu[i].name);
printf("学号:%s",stu[i].id);
printf("语文成绩:%s",stu[i].yw);
printf("数学成绩:%s",stu[i].sx);
printf("英语成绩:%s",stu[i].yy);
break;
}
if(!strcmp(buf,stu[i].id))
{
printf("名字:%s",stu[i].name);
printf("学号:%s",stu[i].id);
printf("语文成绩:%s",stu[i].yw);
printf("数学成绩:%s",stu[i].sx);
printf("英语成绩:%s",stu[i].yy);
break;
}
}
if(!strcmp,0)
{
break;
}
}
}
int main()
{
int i;
for(i=0;i<5;i++)
{
bzero(&stu[i],sizeof(stu[i]));
printf("请输入名字:");
scanf("%s",student[i].name);
printf("请输入学号:");
scanf("%s",student[i].id);
printf("请输入语文成绩:");
scanf("%f",&student[i].yw);
printf("请输入数学成绩:");
scanf("%f",&student[i].sx);
printf("请输入英语成绩:");
scanf("%f",&student[i].yy);
}
for(i=0;i<5;i++)
{
printf("名字:%s",stu[i].name);
printf("学号:%s",stu[i].id);
printf("语文成绩:%s",stu[i].yw);
printf("数学成绩:%s",stu[i].sx);
printf("英语成绩:%s",stu[i].yy);
}
int n;
switch(1)
{
printf("0.结束查询\n");
printf("1.可通过学号或姓名查看指定目标的相关成绩\n");
printf("2.可指定查看对应学科或总分的排名\n");
printf("3.可查看对应学科或总分的平均分\n");
printf("请输入对应编号,使用相关功能\n");
scanf("%d",&n);
if(0==n)
{
break;
}
switch(n)
{
case 1:
switch_1();
break;
case 2:
case 3:
}
}
}
}
for(i=0;i<5;i++)
{
printf("名字:%s",stu[i].name);
printf("学号:%s",stu[i].id);
printf("语文成绩:%s",stu[i].yw);
printf("数学成绩:%s",stu[i].sx);
printf("英语成绩:%s",stu[i].yy);
}
int n;
switch(1)
{
printf("0.结束查询\n");
printf("1.可通过学号或姓名查看指定目标的相关成绩\n");
printf("2.可指定查看对应学科或总分的排名\n");
printf("3.可查看对应学科或总分的平均分\n");
printf("请输入对应编号,使用相关功能\n");
scanf("%d",&n);
if(0==n)
{
break;
}
switch(n)
{
case 1:
switch_1();
break;
case 2:
case 3:
}
}
}