1.结构体的介绍
结构体的格式
struct 类型名{
类型1 变量1;
类型2 变量2;//其中变量的数目可以根据自己所需要的数目进行定义
... //其中类型可以不相同,也可以相同.
};
结构体是构造类型,简单来说就是构造了个类似于基本类型的一种类型,只不过构造类型可以自己定义里面的成员类型.
定义变量的过程:struct l类型名 变量名. 此处与以往所见有所不同,以往的类型(例如int,char,float)等都是一个单词,而结构体变量的定义为 struct 类型名 两个.对比下例中stu为变量名.
如同 int a;中的a .
结构体内成员的空间是连续的,类似于二维数组的存储.
例如:
//构造结构体类型中的成员
struct student{
char name[20];//其中变量类型可以自己定义.
char sex;
int age;
};
//定义变量
struct student stu;
//定义指针变量
struct student *stu;//要注意给指针分配空间,否则为野指针
stu=malloc(sizeof(struct student));
几点注意事项:
1.其中struct是定义结构体的关键字,后面的类型名可以根据自己需要自行输入.
2.其中变量的数目可以根据自己所需要的数目进行定义,而且变量类型可以不相同,也可以相同.
但有一点需要注意,定义的内部成员必须要有明确的大小,如里面不能定于函数,但是可以定义函数指针,函数指针的大小是可以确定的.(32位4字节,64位8字节)
3.结构体变量是可以直接赋值的.(此处要与数组区分)
4.声明一个指针变量其只有指针变量大小的内存,而指针指向的内存为空,不进行分配空间则为野指针。所以,对结构体指针指向的元素赋值之前必须给其分配一个固定的内存空间,其大小最好为结构体的大小sizeof(struct student).
4.最后的;不能忘记.
//可以定义两个变量
sturct student stu1;
sturct student stu2;
//此处可以stu1=stu2;
//而数组不可以直接赋值
int arr1[10];
int arr2[20];
arr1=arr2;//错误的(数组名为常量)
2.结构体变量定义的多种方法
方式1:先定义结构体类型,在用结构体类定义
struct student{
char name[20];
char sex;
int age;
};
struct student stu;
方式2:定义结构体类型是直接定义
struct student{
char name[20];
char sex;
int age;
}stu;//直接定义
方式三: 无名结构体定义
struct {
char name[20];
char sex;
int age;
}stu;//这种方法只能在定义结构体类型是直接定义,因没有类型名后续无法定义新的变量
3.结构体成员初始化的多种方法
方式1:定义的同时初始化
struct student{
char name[20];
char sex;
int age;
};
struct student stu={"zhangsan",'m',18};
struct student{
char name[20];
char sex;
int age;
}stu={"zhangsan",'m',18};
方式2:定义后初始化
struct student{
char name[20];
char sex;
int age;
};
struct student stu;
strcpy(stu->name,"zhangsan");//直接写stu.name="zhangsan"错误的.不能将字符串直接复制给数组,可以借助字符串拷贝函数strcpy.
stu->ex='m';
stu->age=18;
struct student{
char name[20];
char sex;
int age;
}stu;
strcpy(stu->name,"zhangsan");
stu->ex='m';
stu->age=18;
方式3:不完全初始化,可以跳过部分成员
struct student{
char name[20];
char sex;
int age;
}stu={
.-name="zhangsan",
.age=18
};
4.结构体成员的访问
1.定义的为结构体变量直接用.进行访问.
struct student stu;
strcpy(stu.name,"zhangsan");//直接写stu.name="zhangsan"错误的.不能将字符串直接复制给数组,可以借助字符串拷贝函数strcpy.
stu.sex='m';
stu.age=18;
printf("stu.name=%s stu.sex=%c stu.age=%d\n",stu.name,stu.sex,stu.age);
2.定义的为结构体指针变量用->访问
struct student *stu;
strcpy(stu->name,"zhangsan");
stu->ex='m';
stu->age=18;
printf("stu.name=%s stu.sex=%c stu.age=%d\n",stu->name,stu->sex,stu->age);
4.结构体的简单应用
1.结构体变量的应用
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct student {
char name[20];
char sex;
int age;
};
int main(int argc, const char *argv[])
{
struct student stu;
strcpy(stu.name,"zhangsan");
stu.sex='m';
stu.age=18;printf("stu.name=%s stu.sex=%c stu.age=%d\n",stu.name,stu.sex,stu.age);
return 0;
}
//结果stu.name=zhangsan stu.sex=m stu.age=18
2.结构体指针的应用
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct student {
char name[20];
char sex;
int age;
};
int main(int argc, const char *argv[])
{
struct student *stu;
stu=malloc(sizeof(struct student));//注意采用结构体指针变量时要定义空间给结构体变量,不然直接为野指针.
strcpy(stu->name,"zhangsan");//成员访问为->
stu->sex='m';
stu->age=18;printf("stu->name=%s stu->sex=%c stu->age=%d\n",stu->name,stu->sex,stu->age);
return 0;
}
//结果stu->name=zhangsan stu->sex=m stu->age=18
3.终端输入结构体内部成员信息
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct student {
char name[20];
char sex;
int age;
};
int main(int argc, const char *argv[])
{
struct student stu;
int ret = 0;
ret = scanf("%s %c %d",stu.name,&stu.sex,&stu.age);//stu.name不加&,因为name为数组名,数组名为首元素地址.
if(3 != ret){//判断输入的是否为三项,如果不是直接推出程序
printf("错误\n");
return -1;
}printf("stu.name=%s stu.sex=%c stu.age=%d\n",stu.name,stu.sex,stu.age);
return 0;
}
//结果zhangsan m 18
stu.name=zhangsan stu.sex=m stu.age=18
4.封装输入和输出的函数
//这个代码是否正确
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct student {
char name[20];
char sex;
int age;
};int myscanf(struct student p);
void myprintf(struct student p);
int main(int argc, const char *argv[])
{
struct student stu;
myscanf(stu);
myprintf(stu);
return 0;
}//输入函数
int myscanf(struct student p)
{
int ret = 0;
ret = scanf("%s %c %d",p.name,&p.sex,&p.age);
if(3 != ret){
printf("错误\n");
return -1;
}
return 0;
}
//输出函数
void myprintf(struct student p)
{
printf("p.name=%s p.sex=%c p.age=%d\n",p.name,p.sex,p.age);
}
//结果zhangsan m 18
p.name=�)v�k p.sex=" p.age=-601237920
此代码看着没有什么问题,但是输出的结果就是错误的.可以看出输出为乱码.
那么问题出在哪里呢?
首先我们要了解一下变量的生命周期和作用域的问题和函数中局部开辟空间的问题.
可以参考:全局变量、静态变量、局部变量的生存周期与作用域_全局变量的生命周期-优快云博客
简单来说:全局变量的生命周期是到程序结束,作用域为这个程序;局部变量的生命周期在它所在的{}内,一旦退出{},局部变量就会消失.所以看上面代码,myscanf(stu)将stu的值传给了int myscanf(struct student p);中的p,函数中的p很显然是局部变量,当程序进入输入函数时,程序会在栈区开辟一个struct student 大小的空间给p,在函数中成功给p变量赋值,但是当程序到return 0;时函数程序结束,局部变量p就会被释放,相当于并没有对主函数中的stu进行修改,所以当在下面输出stu的成员时,stu并没有被赋值所以就会出现乱码这种结果.
改进思路:
根据以往采用函数将两个变量交换值的经验,这里可知道在输入函数中传入stu的地址,使得输入函数中的指针p指向stu,就能解决问题.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct student {
char name[20];
char sex;
int age;
};int myscanf(struct student *p);
void myprintf(struct student p);
int main(int argc, const char *argv[])
{
struct student stu;
myscanf(&stu);
myprintf(stu);
return 0;
}//输入函数
int myscanf(struct student *p)
{
int ret = 0;
ret = scanf("%s %c %d",p->name,&p->sex,&p->age);
if(3 != ret){printf("错误\n");
return -1;
}
return 0;
}
//输出函数
void myprintf(struct student p)
{
printf("p.name=%s p.sex=%c p.age=%d\n",p.name,p.sex,p.age);
}
//结果zhangsan m 18
p.name=zhangsan p.sex=m p.age=18
注:如果在函数内想修改结构体中的内容就定义成结构体指针,如果在函数内不想修改结构体的内容,直接传递结构体变量即可
5.结果体与typedef结合
1.#define与typedef的区别
#define 为宏定义,是机械的字符串替换
typedef为类型重定义
例如:
#define INT_T int*
typedef int* INT_P;//需要加;
int_t a,b;//a为int* 的指针,而b为int 的变量
int_p c,d;//a为int* 的指针,而b为int* 的指针
2.typedef的使用
typedef为类型重定义,会将原来的变量名变成类型
typedef struct student {
char name[20];
char sex;
int age;
}STU;//此时STU不再是变量,而是结构体类型
STU stu;//定义了struct student 类型的stu;
//不仅仅在结构体中适用,适用于任何类型
typedef int (*P)[10];//数组指针类型 此时P为数值指针类型 可以定义 P=p;
...
6.结构体变量的嵌套
顾名思义就是在结构体中在创建一个结构体.
struct AA{
int a;
int b;
};
struct BB{
struct AA t;
int c;
};
此时结构体成员的访问会在原本的基础上再加一层.
相当于这样:
struct BB{
struct AA{
int a;
int b;
}t;
int c;
};
先定义后赋值
struct BB u;
u.t.a=10;
u.t.b=20;
u.c=30;
定义式直接赋值
struct BB u={
{
10,
20
};
30
};