第 16讲动态内存分配结构体
2
学习方法
读程序:上机单步执行(跟踪法)观察程序的执行顺序以及程序中各变量的值的变化。或者人工模拟计算机执行,要手工进行计算。
写程序,先逐层地写算法! 再写程序!
3
重要提示:
什么时候用指针:
当想用指针间接引用变量的时候
当想希望用指针提高程序效率的时候
不要:
能直接引用变量的时候不要用指针
能用数组名字指针数组的时候不要用指针
4
问题
当我们处理实际问题时,如何申请空间?
int a[100]; /*总是有一定的浪费 */
int a[n]; /*不合法 */
如何根据实际需要申请 n个内存存放 n个数据?
5
四、动态分配内存
? 问题:如何解决根据班级实际人数来定义数组?
自己根据实际需要向系统申请内存如何申请呢?
6
三个相关库函数
#include <stdlib.h>
void* malloc(unsigned int size);
向系统申请大小为 size的内存块,把首地址返回。如果申请不成功,返回 NULL
void* calloc(unsigned int num,
unsigned int size);
向系统申请 num个 size大小的内存块,把首地址返回。
如果申请不成功,返回 NULL
void free(void* p);
释放由 malloc()和 calloc()申请的内存块。 p是指向此块的指针
void*类型的指针可以指向任意类型的变量
7
动态数组举例
1 动态一维数组
2 动态二维数组,但看成一维数组
3 动态二维数组
8
动态一维数组
#include<stdio.h>
#include<stdlib.h>
void main()
{
int i,n,*p = NULL;
printf("Please enter array size:");
scanf("%d",&n);
p = (int *) malloc(n * sizeof (int)); //根据上边输入的人数申请内存
printf("please input %d intergers",n);
for(i=0;i<n;i++) //为动态数组输入数据
scanf("%d",&p[i]); //也可以用 scanf("%d",p+i);
puts("the array is:");
for(i=0;i<n;i++)
printf("%4d",p[i]);
free(p); //释放申请的内存空间
}
9
动态二维数组,但看成一维数组来处理
(通过列地址引用二维数组元素 )
#include<stdio.h>
#include<stdlib.h>
void main()
{
int i,j,m,n,*p = NULL;
printf("Please enter size of row:");
scanf("%d",&m);
printf("Please enter size of line:");
scanf("%d",&n);
p = (int *) calloc(n*m,sizeof (int));
//根据前边输入的行、列宽度申请内存空间
printf("please input %d intergers",m*n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&p[i*n+j]);
//为二维数组输入数据,但使用的是一维数组的引用形式
puts("the array is:");
for(i=0;i<m;i++)
{ for(j=0;j<n;j++)
printf("%4d",p[i*n+j]);
putchar('\n');
}
free(p);//释放 申请的内存空间
}
10
#include<stdio.h>
#include<stdlib.h>
void main()
{
int i,j,m,n,*p= NULL,**Parray=NULL;
printf("Please enter size of row:");
scanf("%d",&m);
printf("Please enter size of line:");
scanf("%d",&n);
p = (int *) calloc(m,n*sizeof (int));//根据前边输入的行、列宽度申请内存空间
Parray=(int **)calloc(m,sizeof(int *));//根据前边输入的行宽度申请一个指针数组要用的内存空间
for(i=0;i<m;i++)//指针数组中存储二维数组每一行的首个元素的地址 (列地址 )
Parray[i]=p+i*n;
printf("please input %d intergers",m*n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",(*(Parray+i))+j);//为二维数组输入元素。指针数据名就相当于二维数组名
puts("the array is:");
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
printf("%4d",Parray[i][j]);
putchar('\n');
}
free(p);//释放内存空间
free(Parray);
}
动态二维数组
(通过行地址引用二维数组元素 )
P列地址Parray行地址
&P[0]
&P[3]
1 2 3
4 5 6
11
P227例 6-35,输出表 6-4
学号 姓名 性别 数学 英 语 计算机 C语言 通信网 平均分
101 张三 M 80 90 98 86 90 88.8
102 李四 M 82 89 94 81 91 87.4
103 王五 F 92 78 86 79 89 84.8
104 何六 M 89 81 78 63 76 77.4
105 周七 F 98 69 91 85 67 82
106 … …
用什么样的数据类型存储?缺点?分配内存不集中,寻址效率不高
对数组进行赋初值时,容易发生错位
结构显得比较零散,不容易管理按行处理如何定义数据类型呢?
? stu [30];
12
结构体类型
C语言没有为我们提供相应的数据类型,
但我们可以根据需要自己定义数据类型。
根据题意,我们定义如下的结构体类型:
struct student
{int num;
char name[20];
char sex;
float score[5];
float aver;
};
结构类型的 成员
!!!注意:
struct student
是一个 数据类型
13
结构体变量的定义
struct student stu[30];
含义:定义一个一维数组,有 30个元素,其数据类型为 struct student
为了方便后边的使用,我们可以用 typedef
为这个数据类型起个 别名,
typedef struct student STU;
STU 和其它类型一样使用。
下列语句什么含义?
STU a;STU stu1[30];
14
内存分配
共 30个数组元素,每个数组元素分配多少字节?
可用 sizeof(struct student )求得,
101 张三 M 80 90 98 86 90 88.8
102 李四 M 82 89 94 81 91 87.4
103 王五 F 92 78 86 79 89 84.8
104 何六 M 89 81 78 63 76 77.4
105 周七 F 98 69 91 85 67 82
106 … …
stu
stu[0]
stu[1]
stu[2]
stu[3]
stu[4]
……?那每个学生的学号、姓名,… 又如何表示呢?
15
引用 结构体变量的 成员
结构体变量的 成员 (member),也称 元素
( element) 或 域( filed) 。
使用引用运算符,对结构类型变量 stu[i]中每个成员进行引用
例:
stu[i].num
stu[i].name
它们都是变量,与其它同类型变量同样使用。
注意区分:
结构体 类型 ;
结构体 变量 ;
结构体变量的 成员
16
例题的实现
算法
定义结构体类型
定义结构体变量
输入表 6-4
输出表 6-4
17
例 6- 35( 1)
#include <stdio.h>
struct student
{int num; /* 学号 */
char name[20]; /* 姓名 */
char sex; /* 性别,m-男,f-女 */
float score[5]; /* 成绩 */
float aver; /* 平均分 */
}; /* 定义结构体类型 struct student,一般都定义为全局可用的数据类型 */
typedef struct student STU;/*为数据类型起别名 */
void main()
{ int i,j;
float sum;
STU stu[30]; /* 定义结构体变量 */
18
例 6- 35( 2)
for(i=0;i<30;i++) /* 输入每个学生的信息 */
{printf(“please input the number\n:”);
scanf(“%d”,&stu[i].num);getchar();
printf(“please input the name\n:”);
scanf(“%s”,stu[i].name);getchar();
printf(“f or m(female or mail)?\n:”);
scanf(“%c”,&stu[i].sex);
printf(“please input 5 scores:\n:”);
for(j=0;j<5;j++) /*输入 5门课的成绩 */
scanf(“%f”,&stu[i].score[j]);
sum=0; /*下边计算 5门课的平均分,并存放在相应成员变量中 */
for(j=0;j<5;j++)
sum+=stu[i].score[j];
stu[i].aver=sum/5;
}
printf("num\tname\t\t sex c1 c2 c3 c4 c5 aver\n");
for(i=0;i<30;i++) /* 输出学生基本信息 */
{printf("%d\t%s\t %c %3.0f %3.0f %3.0f %3.0f %3.0f %4.1f\n",
stu[i].num,stu[i].name,stu[i].sex,stu[i].score[1],stu[i].score[2],
stu[i].score[3],stu[i].score[4],stu[i].score[5],stu[i].average);
}
19
对数组元素的成员进行 引用有三种方式
stu[i].num
101 张三 M 80 90 98 86 90 88.8
102 李四 M 82 89 94 81 91 87.4
103 王五 F 92 78 86 79 89 84.8
104 何六 M 89 81 78 63 76 77.4
105 周七 F 98 69 91 85 67 82
106 … …
stu
stu[0]
stu[1]
stu[2]
stu[3]
stu[4]
……
1.如果有指针变量 p指向数组 stu,
如何定义指针,如何用指针引用数组元素的成员呢?
2.? *p;
3.P=?;
4.?num
5.P++以后到哪儿?
struct student *p;
p=stu;
… p->num或 (*p).num stu[i].num
20
用指针:例 6- 35( 1)
#include <stdio.h>
struct student
{int num; /* 学号 */
char name[20]; /* 姓名 */
char sex; /* 性别,m-男,f-女 */
float score[5]; /* 成绩 */
float aver; /* 平均分 */
}; /* 定义结构体类型 struct student,一般都定义为全局可用的数据类型 */
typedef struct student STU;/*为数据类型起别名 */
void main()
{ int i,j;
float sum;
STU stu[30]; /* 定义结构体变量 */
STU *p;
21
例 6- 35( 2)
for(p=stu;p<stu+30;p++) /* 输入每个学生的信息 */
{printf(“please input the number\n:”);
scanf(“%d”,&p->num);
printf(“please input the name\n:”);
scanf(“%s”,p->name);
printf(“f or m(female or mail)?\n:”);
scanf(“%c”,&p->sex);
printf(“please input 5 scores:\n:”);
for(j=0;j<5;j++) /*输入 5门课的成绩 */
scanf(“%f”,&p->score[j]);
sum=0; /*下边计算 5门课的平均分,并存放在相应成员变量中 */
for(j=0;j<5;j++)
sum+=p->score[j];
p->aver=sum/5;
}
printf("num\tname\t\t sex c1 c2 c3 c4 c5 aver\n");
for(p=stu;p<stu+30;p++) /* 输出学生基本信息 */
{printf("%d\t%s\t %c %3.0f %3.0f %3.0f %3.0f %3.0f %4.1f\n",
(*p).num,(*p).name,(*p).sex,(*p).score[1],(*p).score[2],
(*p).score[3],(*p).score[4],(*p).score[5],(*p).average);
}
22
小结
动态数组的申请及数据处理
结构类型以及结构体变量和数组的处理
23
作业 1
1.习题 6.10,查询功能写成函数。要求:
1.定义结构体数组实现
2.用动态数组实现
24
#include<stdio.h>
#include<string.h>
struct salary
{
char n[15],d[10];
float s,t;
};
void input(struct salary w[],int n);
void output(struct salary w[],char *a,int n);
习题 6.10
void input(struct salary w[],int n)
{ int i;
for(i=0;i<n;i++)
{ printf("Input No.%d(name,department,salary):",i+1);
scanf("%s%s%f",w[i].n,w[i].d,&w[i].s);
if(w[i].s>800)
w[i].t=0.05*(w[i].s-800);/*税金是根据工资算出来的 */
else
w[i].t=0;
}
}
void output(struct salary w[],char *a,int n)
{int i,fl=0;
for(i=0;i<n;i++)
if(strcmp(w[i].n,a)==0)
{fl=1;break;}
if(fl)
printf("Name:%s\nDepartment:%s\nSalary:%.2f\nTax:%.2f\n",
w[i].n,w[i].d,w[i].s,w[i].t);
else
printf("Can't find!");
}
void main()
{int n;char a[15];
struct salary w[30];
printf("Input the number of workers(n<30):");
scanf("%d",&n);
input(w,n);
printf("Input the worker's name:");
scanf("%s",a);
output(w,a,);
}
25
对数组元素的成员进行 引用三种方式


“xiejb”
“computer”
1500
15
w[0]
w[1]
w[2]
stu[0].name
stu[0].department
stu[0].salary
stu[0].tax

p
P->name
P->department
P->salary
P->tax

(*p).name
(*p).depar t
(*p).salar
(*p).tax

26
#include<stdio.h>
#include<string.h>
struct salary
{
char n[15],d[10];
float s,t;
};
void input(struct salary *w,int n);
void output(struct salary *w,char *a,int n);
习题 6.10
void input(struct salary *w,int n)
{ int i;
struct salary *p;
for(p=w;p<w+n;p++)
{ printf("Input name,department,salary:");
scanf(“%s%s%f”,p->n,p->d,&(p->s));/*用指针变量 p引用数组元素 */
if(p->.s>800)
p->t=0.05*(p->s-800);/*税金是根据工资算出来的 */
else
p->t=0;
}
}
void output(struct salary *w,char *a,int n)
{int i,fl=0;
struct salary *p;
for(p=w;p<w+n;p++)
if(strcmp(p->n,a)==0)
{fl=1;break;}
if(fl)
printf("Name:%s\nDepartment:%s\nSalary:%.2f\nTax:%.2f\n",
p->n,p-> d,p-> s,p-> t);
else
printf("Can't find!");
}
void main()
{int n;char a[15];
struct salary w[30];
printf("Input the number of workers(n<30):");
scanf("%d",&n);
input(w,n);
printf("Input the worker's name:");
scanf("%s",a);
output(w,a,);
}