在学习c语言时,系统会为我们提供大量的数据类型,比如int、float、char等等,我们可以借助这些数据类型定义变量,处理一般的问题,但是当我们需要处理的问题过于复杂时,只有系统提供的类型还不能满足应用的要求,c语言允许人们根据自己的要求创建一些数据类型,并用它创建变量。
一、结构体的定义与使用
在前面所见的程序中,所有的变量都是相互独立的,无内在联系,但实际生活中有些数据是有内在联系、成组出现的,例如,一个人的性命、年龄、体重、身高是相互独立的,同属于一个人,但是不同的人都具有这些属性,因此人们想到,定义一个变量,能够将这些属性都会包括在内,这样使用起来就方便的多了。
在学习数组的时候,我们说,数组是 一组相同元素的集合,但是我们发现上述问题中,这些属性是不同的变量,仅靠数组是无法解决的,因此,我们引入结构体变量的概念。
结构体:是C语言中允许用户自己建立不同类型数据组成的组合型的数据结构。简单来说,结构体是一些值的集合,这些值是成员变量,结构体的每个成员可以是不同的类型。
struct peo//结构体类型
{
char name[20];
char tele[12];
char sex[5];
int high;
} p1,p2;如上所示,为一个结构体的定义,struct为关键字(不能省略),说明其为结构体的类型变量,peo为标签,也为结构体名,{}内部为结构体的成员列表包括不同的成员变量,p1,p2为结构体变量名。
因此,结构体类型的一般形式为:
struct 结构体名
{成员列表};
结构体花括号中所包含的子项,称为结构体的成员,上述name,sex等都为它的成员,对成员都应该进行相应的类型声明。
类型名 成员名;
当然结构体中也可以包含另外一种结构体,我在此的理解是如同函数,函数中可以调用其他函数,但是不能在函数内部进行另外函数的定义,结构体也是一样的;比如:
struct peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
struct st
{
struct peo p;//结构体成员变量可以是,标量、数组、指针,甚至是其他结构体;
int num;
float f;
};
此处结构体st内部就包含peo结构体;
1、先声明,在定义
先声明一个结构体类型,在定义该类型的变量;
#include <stdio.h>
struct peo//定义结构体类型
{
char name[20];
char tele[12];
char sex[5];
int high;
}
int main()
{
struct peo s1;//定义结构体变量s1
struct peo s2;//定义结构体变量s2
return 0;
}
其结果为:
2、在声明时同时定义变量
#include <stdio.h>
struct peo//定义结构体类型
{
char name[20];
char tele[12];
char sex[5];
int high;
}s1,s2;//定义结构体变量s1、s2
int main()
{
return 0;
}
在声明结构体时顺便定义变量,其结过是相同的。
结构体变量的初始化与引用
在结构体进行定义时,顺便赋予初值,称为结构体的初始化,再将其输出引用;
例如:
#include <stdio.h>
struct peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
struct st
{
struct peo p;//结构体成员变量可以是,标量、数组、指针,甚至是其他结构体;
int num;
float f;
};
int main()
{
struct peo p1={"张三","1559668862","男", 187};
struct st s={{"lisi","1559668862","女",166},100,3.14};//浮点数在内存中,不能精确保存
printf("%s %s %s %d\n",p1.tele,p1.sex,p1.name,p1.high);//结构体变量 成员变量
printf("%s %s %s %d %d %f\n",s.p.tele,s.p.name,s.p.sex,s.p.high,s.num,s.f);//结构体指针 成员变量
return 0;
}
程序中声明结构体类型后,在主函数进行赋初值,进行初始化,在变量 p1与变量s花括号的后面进行初值赋予,按照顺序依次进行赋予。
注意:
1、在初始化时,是对结构体变量(p1)进行初始化,不是对结构体类型初始化(peo);
2、引用结构体变量的成员时,采用结构体变量.成员名(p1.name)其作用与普通变量相同,可以直接进行赋值等操作。
3、结构体的“.”是成员运算符,它在所有的运算符中优先级最高,因此可以将p1.name看作一个整体,相当于一个整型变量。
二、结构体传参
#include <stdio.h>
struct peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
struct st
{
struct peo p;//结构体成员变量可以是,标量、数组、指针,甚至是其他结构体;
int num;
float f;
};
void print2(struct peo*r)
{
printf("%s %s %s %d\n",r->name,r->sex,r->tele,r->high);
}
void print1(struct peo r)
{
printf("%s %s %s %d\n",r.name,r.sex,r.tele,r.high);
}
int main()
{
struct peo p1={"张三","1559668862","男", 187};
struct st s={{"lisi","1559668862","女",166},100,3.14};//浮点数在内存中,不能精确保存
printf("%s %s %s %d\n",p1.tele,p1.sex,p1.name,p1.high);//结构体变量 成员变量
printf("%s %s %s %d %d %f\n",s.p.tele,s.p.name,s.p.sex,s.p.high,s.num,s.f);//结构体指针 成员变量
print2(&p1);
print1(p1);
return 0;
}
运行结果为:
在结构体传参中,分为结构体变量(p1)传参与结构体变量地址传参(&p1)如上述代码,作用是相同的,不同的是在使用结构体成员变量时,一个采用“.”一个采用“->”; 在结构体传参的时候,参数是需要压栈的,如果传递一个结构体对象时,结构体过大,参数压栈的系统开销比较大,所以导致性能的下降;结构体传参的时候尽量传结构体的地址。
三、结构体数组
一个结构体变量中可以存放一组相关的数据(如:一个学生的学号、姓名、成绩等),如果有十个学生的数据,显然此处应该用作数组,这就是结构体数组。
定义结构体数组的一般形式为:
struct 结构体名
{成员列表}数组名 [数组长度];
或先声明一个结构体,在进行定义;
struct 结构体名
{成员列表};
struct 结构体名 数组名[数组长度];
对结构体数组初始化的形式是在定义数组的后面加
={初值表列};
举例:有n个学生信息(学号、姓名、成绩)要求按照成绩的由高到低排序输出;
#include <stdio.h>
struct stu//声明结构体类型
{
int num;
char name[20];
float score;
};
int main()
{
struct stu s[5]={{1001,"lihua",95.6},{1003,"wangqiang",85},{1004,"zhanglan",98.5},{1002,"liuliu",75},{1005,"lili",97}};//定义结构体数组,并赋初值;
printf("按照成绩排序为:\n");
int i=0;
int j=0;
struct stu temp;
for(i=0;i<4;i++)//采用冒泡排序进行成绩排序
{
for(j=0;j<4-i;j++)
{
if(s[j].score<s[j+1].score)
{
temp=s[j];
s[j]=s[j+1];
s[j+1]= temp;
}
}
}
for(i=0;i<4;i++)//输出结构体数组
{
printf("%d %8s %6.2f\n",s[i].num,s[i].name,s[i].score);
printf("\n");
}
return 0;
}
运行结果:
四、结构体指针
所谓的结构体指针,就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就是结构体变量。
1、指向结构体变量的指针
#include <stdio.h>
int main()
{
struct stu
{
int num;
char name[20];
char sex;
};
struct stu a1={100,"linhua",'m'};
struct stu *p;
p=&a1;
printf("No.:%d\n name:%s\n sex:%c\n",a1.num,a1.name,a1.sex);
printf("No.:%d\n name:%s\n sex:%c\n",(*p).num,(*p).name,(*p).sex);
printf("No.:%d\n name:%s\n sex:%c\n",p->num,p->name,p->sex);
return 0;
}
指针p指向结构体的起始地址,在后面输出时,以下3种用法等价:
1、a1.成员名,如(a1.num);
2、(*p).成员名,如(*p).num;
3、p->成员名,如p->num;
运行结果:
2、指向结构体数组的指针
我们知道结构体数组的本质还是数组,对于数组指针,我们之前已经分析的很透彻了,而结构体数组我们可以认为是数组的每个元素都是一个结构体变量,然后指针指向数组元素也就是指针指向每个结构体的地址。
举例:有3个学生的信息,放在结构体数组中,要求输出全部学生的信息;
#include <stdio.h>
struct student
{
int num;
char name[20];
char sex;
int age;
};
struct student s[3]={{1001,"lili",'M',20},{1002,"liuliu",'F',25},{1003,"zhangzhang",'M',31}};
int main()
{
struct student *p;
p=s;
for(p=s;p<s+3;p++)
printf("%d %s %c %d\n",p->num,p->name,p->sex,p->age);
return 0;
}
此处,运用到了指向结构体数组的指针来完成结构体内容的输出。p指向第一个结构的内容,p+1指向第二个结构体的内容,依次进行结构体数组中数组元素的输出;
综上所述,本节我们学习的结构体的相关内容,其中包括结构体的结构体的定义与使用,结构的传参,结构体数组以及结构体指针,在后面的使用中将大量使用本节内容,还希望读者多多理解多多练习。
创作不易,还请大家多多点赞支持。