问题定义:
有时需要将不同类型的数据组合成一个有机的整体,以便于引用。如: 一个学生有学号、姓名、性别、年龄、地址等属性 int num;char name[20]; char sex; int age; int char addr[30];
定义一个结构的一般形式为: Struct 结构名 { 成员列表 } ; 成员列表由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为: 类型说明符 成员名;
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}
2.在声明类型的同时定义变量 这种形式的定义一般形式为: Struct 结构体名 { 成员表列 }变量名表列; 例如:
Struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}student1,student2;
在定义了结构体变量后,系统会为之分配内存单元。 例如:student1 和student2 在内存中各占? 字节
3.直接定义结构体类型变量 其一般形式为: Struct { 成员表列 }变量名表列; 即不出现结构体名
结论: 这是一个 嵌套的定义
#include <stdio.h>
#include <stdlib.h>
void main()
{
struct date
{
int mouth;
int day;
int year;
};
struct
{
int num;
char name[20];
struct date biethday;
}boy1,boy2;
printf("please input birthday(yy:)");
scanf("%d",&boy1.biethday.year);
printf("please input birthday(m:)");
scanf("%d",&boy1.biethday.mouth);
printf("please input birthday(d:)");
scanf("%d",&boy1.biethday.day);
printf("please input num: ");
scanf("%d",&boy1.num);
printf("please input name: ");
scanf("%s",&boy1.name);
printf("%d %d %d %d %s",boy1.biethday.year,boy1.biethday.mouth,boy1.biethday.day,boy1.num,boy1.name);
}
正确引用结构体变量中成员的方式为: 结构体变量.成员名 Student1.num 表示student1变量中的num成员,即student1的num(学号)项,可以对变量的成员赋值,例如: student1.num = 100; “.” 是成员运算符,它在所有的运算符中优先级最高,因此可以把student1.num作为一个整体来看待。上面赋值语句的作用是将整数100 赋值给 student1 变量中的成员num。
2.如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。 对上面定义的结构体变量student1,可以这样访问各变量: student1.num student1.birthday.month
3.对于结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。 例如:student2.score = student1.score; sum = student1.score + student2.score; student.age ++; ++student2.age;
4.可以引用结构体变量成员的地址,也可以引用结构体变量的地址。 但不能用以下语句整体读入结构体变量: Scanf(“%d,%s,%c,%d,%f,%s”,&student1); 结构体变量的地址主要用作函数参数,传递结构体变量的地址。
一个结构体变量中可以存放一维数据(如一个学生的学号、姓名、成绩等数据) 如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。 结构体数组与以前介绍过的数值型数组不同之处在于每个数组元素都是一个结构体类型的数据,它们都分别包含各个成员项。
For(i=0;i<3;i++)
{
printf(“input name: \n”);
gets(man[i].name);
printf(“input phone:\n”);
gets(man[i].phone);
}
Printf(“name\t\t\tphone\n\n”);
For(i=0;i<3;i++)
{ printf(“%20s \t\t\t\ %20s\n”,man[i].name,man[i].phone); }
和定义结构体变量的方法相仿,只需说明其为数组即可,例如:
Struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30]; };
struct syudent student[3];
与其他类型的数组一样,对结构体数组可以初始化 ,例如:
Struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu[2] = {
{101,”Wang”,’M’,18,87.5,”Fuzhou”},
{102,”Zhang”,’F’,19,99,”Shanghai”}
};
当然,数组的初始化也可以用以下形式: Struct student { int num; }; Struct student str[] = {{…},{…},{…}}; 即声明结构体类型,然后定义数组为该结构体类型,在定义数组时初始化。
一个结构体变量的指针就是该结构体变量所占据内存段的起始地址。 可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的其实地址。 指针变量也可以用来指向结构体数组中 的元素。
赋值是把结构体变量的首地址赋予该指针变量,不能把结构名赋予该指针变量。 如果boy 是被说明为stu类型的结构变量,则: pstu = &boy; //是正确的 pstu = &stu ; //是错误的
因为,结构名和结构变量是两个不同的概念,不能混淆。结构名只能表示一个结构形式,编译系统并不对它分配内存空间。 只有当某变量被说明为这种类型的结构时,才对该变量分配存储空间。 因此上面&stu 这种写法是错误的,不可能去取一个结构名的首地址。有了结构体指针变量,就能更方便地访问结构体变量的各个成员。
其访问的一般形式为: (*结构体指针变量).成员名 或为: 结构指针变量 -> 成员名 例如: (*pstu).num 或者 pstu ->num
#include <stdio.h>
#include <stdlib.h>
struct stu
{
int num;
char *name;
char sex;
float score;
}boy1 = {102,"yyy",'M',88};
int main()
{
struct stu *pst;
pst = &boy1;
printf("%d %s %c %f\n",boy1.num,boy1.name,boy1.sex,boy1.score);
printf("%d %s %c %f\n",(*pst).num,(*pst).name,(*pst).sex,(*pst).score);
printf("%d %s %c %f\n",pst->num,pst->name,pst->sex,pst->score);
return 0;
}
将一个结构体变量的值传递给另一个函数,有3个方法: 1.用结构体变量的成员作参数 2.用结构体变量作实参 3.用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。
例题,有一个结构体变量stu,包含学生的学号,姓名,和三门课程的成绩,通过函数print输出。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int num;
char name[20];
float score[3];
};
void print(struct student);
void main()
{
struct student stu;
stu.num = 8;
strcpy(stu.name,"Moumou");
stu.score[0] = 99.5;
stu.score[1] = 96.5;
stu.score[2] = 92.5;
print(stu);
}
void print( struct student stu)
{ printf("num :%d\n",stu.num);
printf("name :%s\n ",stu.name);
printf("score_1 :%5.2f\n", stu.score[0]);
printf("score_2 :%5.2f\n", stu.score[1]);
printf("score_3 :%5.2f\n", stu.score[2]);
printf("\n");
}
例题,有一个结构体变量stu,包含学生的学号,姓名,和三门课程的成绩,通过函数print输出。 1.用结构体变量作函数参数: 2.改用指向结构体变量的指针作实参
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int num;
char name[20];
float score[3];
};
void print(struct student *p);
void main()
{
struct student stu;
stu.num = 8;
strcpy(stu.name,"Moumou");
stu.score[0] = 99.5;
stu.score[1] = 96.5;
stu.score[2] = 92.5;
print(&stu);
}
void print( struct student *p)
{ printf("num :%d\n",p->num);
printf("name :%s\n ",p->name);
printf("score_1 :%5.2f\n",p->score[0]);
printf("score_2 :%5.2f\n",p->score[1]);
printf("score_3 :%5.2f\n",p->score[2]);
printf("\n");
}
在数组一章里,介绍过数组的长度是预先定义好的,在整个程序中固定不变,C语言中不允许动态数组类型。 例如: int a[n]; 用变量表示长度,想对数组的大小作动态说明,这是错误的。 但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。
对于解决这种问题,用数组的办法很难解决 为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。 常用的内存管理函数有以下三个:
1.分配内存空间函数 malloc, calloc 2.释放内存空间函数 free
函1.数原型为 void * mallc(unsigned int size); 其作用是在内存的动态存储区分配一个长度为size的连续空间(size是一个无符号型) 此函数的返回值是一个指向分配域起始地址的指针(类型为void)。 如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。函数原型为 void * mallc(unsigned int size); 其作用是在内存的动态存储区分配一个长度为size的连续空间(size是一个无符号型) 此函数的返回值是一个指向分配域起始地址的指针(类型为void)。 如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。
函2.数原型为: void *calloc(unsigned n,unsigned size); 其作用是在内存的动态存储区中分配n个长度为size的连续空间。 函数返回一个指向分配域起始地址的指针; 如果分配不成功,返回NULL; 用calloc 函数可以为一维数组开辟动态存储空间,n维数组元素个数,每个元素长度为size。
函3数原型为 void free(void *p); 其作用是释放由p指向的内存区,使这部分内存区能被其他变量使用。 P是最近一次调用calloc或malloc函数时返回的值。 Free函数无返回值