一、定义和使用结构体变量
1 结构体定义以及如何创建结构体
在C语言的常见程序中,所用的变量大多数是相互独立、无内在联系的。例如定义了整型变量a ,b ,c ,他们都是单独存在的变量,在内存的地址中也是互不相干的。但是在实际的生活中,有些数据是存在相互联系,成组的出现,比如一个学生的姓名,学号,性别,地址和成绩等。
那么是否可以把学生的数据放在数组中呢,显然是不行的,因为数组中只能存放同一种数据类型的数据,整型数组可以存放学号和成绩,但是姓名,性别和地址是不能存放的。
今天要说的就是c语言中用户可以自己建立不同数据类型组成的组合型的数据结构——结构体(struct ),在其他的高级语言里面称为“记录(record)”。
接下来举一个简单的栗子:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
上面的程序设计指定了一个结构体类型 struct student (struct 是声明结构体类型时必须使用的的关键字 ,不能省略)。
注: 此时struct student 就相当于是一个类型名,类似于 int, float。
声明一个结构体的一般形式为:
struct 结构体名 {成员列表};
注意: 结构体类型的名字是由一个关键字struct 和结构体名tag 组合而成(例如:struct student )。结构体名是由用户指定的,又称为“结构体标记(structure tag )”,作用是区别于其他的结构体类型。上例中的student 就是结构体名(结构体标记)。
花括号内包含结构体的所有成员,声明规则为:
类型名 成员名;
“成员列表”(member list)也称为“域表”,每一个成员都是结构体中的一个域。成员名命名规则与变量名相同。
说明: 结构体类型并非是只有一种,而是可以设计出很多种,除了上例的struct student ,还可以设计struct teacher ,struct worker 等等,各自包含各自的成员。
2 如何定义结构体类型的变量
第一节的介绍中,我们只是建立了一个结构体类型,它只是一个模型,并没有定义变量,其中并无具体的数据,系统也不会分配存储单元。
第一种形式:先声明结构体类型,再定义该类型的变量
例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student student1, student2;
int main(){
return 0;
}
这种结构体类型的定义和其他类型定义变量的形式相似(比如:int a; ),上面的 student1,student2为 struct student 类型的变量。
student1的结构:
num | name | sex | age | score | addr |
---|
10001 | xiao mi | M | 19 | 90.5 | Shanghai |
第二种形式:在声明结构体类型的同时定义变量
例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}student1, studnet2;
这种定义的一般形式为:
struct 结构体名
{
成员列表;
} 变量名列表;
这种形式的结构比较直观,在写小程序时会比较直观,清晰,但在写大程序时,往往要求对结构体类型的声明和对变量的定义分别放在不同的位置,以使程序的结构更加清晰,便于维护。
第三种形式:不指定结构体名tag而直接定义结构体类型变量
其一般形式为:
struct
{
成员列表;
} 变量名列表;
说明: 指定了一个无名的结构体类型,它没有名字(不出现结构体名tag )。显然不能再以此类结构体类型去定义其他变量,因为我们往往使用struct demo_tag var1 来定义一个结构体变量var1 ,如果没有标签名(demo_tag )的话就不能用这种形式定义var1 ,所以我们在使用结构体变量的时候只能使用变量名列表的变量,如果要添加其他变量的话,只能提前在变量名列表中添加你需要的变量名。因此这种方式用的不多。
注意: (1)结构体类型与结构体变量是不同的概念,不要混淆。只能对变量进行赋值,存取和运算,而不能对一个类型赋值,存取和运算。在编译时,对类型是不分配空间的,只对变量分配空间。 (2)结构体类型中的成员名可以和程序中的变量名同名,二者互不干扰。 (3)对结构体变量中的成员,即域,可以单独使用,它的作用和地位与普通变量无差。
第四种形式:使用typedef为结构体取一个新名字
c语言中,typedef 的作用是给数据类型取一个新名字,比如:
typedef int ElementData;
这样的话,我们在使用结构体的时候,可以使用自己定义的数据类型,比如:
struct teacher
{
char name[20];
ElementData age;
ElementData num;
};
当然,不一定非得在结构体中才能使用 ElementData ,在程序中其他的地方也是可使用的:
typedef int ElementData;
int main(){
ElementData a = 20;
printf("%d", a);
return 0;
}
typedef 的作用讲明白了,接下来我们可以进入正题:如何在结构体中使用typedef 。 常见两种形式:
typedef struct{
char name;
int age;
}STUDENT;
说明: 这种形式下,并没有定义结构体名 tag ,但是使用了 typedef 给无标签tag 的结构体取了一个新名字 STUDENT ,此后,STUDENT 便是数据类型的名字,并且也不需要使用关键字struct ,以后声明就可以用直接 STUDENT x;
typedef struct NODE{
int data;
struct NODE* next;
}node;
这是创建链表的常见写法,可以拆分两步来看: 第一步:创建了一个struct NODE 类型的结构体,类型名是 struct NODE ,结构体名是NODE 。
struct NODE{
int data;
struct NODE* next;
};
第二步,使用typedef struct NODE node 给这个结构体取了一个新名字node ,此时 node 便是这种结构体的数据类型名。以后便可以使用 node 直接声明变量,比如,node Lnode; 而不必使用struct 关键字。
需要注意的是 :在创建链表的时候,使用的是 struct NODE 创建的指针变量next ,此时是因为,结构体的新命名功能要晚于结构的创建功能,因此在创建 next 指针变量时使用 struct NODE *next 。
不过,在之后的创建、插入、删除、查找函数,以及主函数中,声明指针统一用的是 node* pointer;
3 结构体不同创建形式的比较
形式1:
struct {
char a;
short b;
int c;
} var1;
struct {
char a;
short b;
int c;
} var2;
int main(void)
{
return 0;
}
说明: (1)由于这种形式,没有标签tag,因此不能在程序中使用 struct tag 来定义一个新的结构体变量,只能是在创建结构体的同时就将需要的变量列表写全。 (2)上述方法定义了两个结构体变量var1与var2,两个变量的构造方式相同。但是,这种定义方式有着很大的不便,因为反复重写相同的东西。
对此做一下修改,于是有定义方法2。
形式2:
struct {
char a;
short b;
int c;
} var1,var2;
int main(void)
{
return 0;
}
说明: (1)同形式1,由于没有 tag,因此不能额外声明结构体变量。 (2)这种方式少写了一次结构体,同时还能够实现两个变量的定义。不过,如果定义的结构体变量过多的时候代码就会有可读性以及维护性上的问题。对此改进有两种可选方式,也就是方法3-结构体tag以及方法4-结构体数据类型。
形式3
struct demo_tag {
char a;
short b;
int c;
} var1;
struct demo_tag var2;
int main(void)
{
return 0;
}
说明 :上述代码同样实现了两个结构体变量的定义,但是此结构采用了结构体的tag用以代替了结构体的描述。这种定义方式每次需要写struct 关键字,因为tag 只是代表了结构体的描述信息,即结构体名,struct demo_tag 才是一个类型名。不过,如果出现大量的结构体变量定义需要时,这种方式显然要比前两种方式好得多。
形式4
typedef struct demo_tag {
char a;
short b;
int c;
} demo_t;
demo_t var1,var2;
int main(void)
{
return 0;
}
说明: 代码中的结构体demo_tag 其实是没有用了的,可以去掉。我个人感觉这种方法是最好的一种使用方式。只需要构造一个结构体数据类型,接下来的结构体对象构建起来就简单很多了。而且,当出现大量的结构体数据时,代码需要维护的时候工作量也会小很多。不仅仅在于代码的字符会看着少一些,同时这种方式也比较适合最基本的C语言定义规则。当然,这得建立在你对这种技术有一定的熟知的基础上。
二、使用结构体
1 赋值和初始化
代码示例1:
#include<stdio.h>
#include<iostream>
struct Student
{
int age;
float score;
char sex;
}s={12, 95.5, 'F'};
int main(){
printf("%d %f %c", s.age, a,score, s.sex);
return 0;
}
代码示例2:
#include<stdio.h>
#include<iostream>
struct Student
{
int age;
float score;
char sex;
};
int main()
{
struct Student st = { 80, 66.6, 'F' };
struct Student st2;
st2.age = 10;
st2.score = 88.8;
st2.sex = 'F';
printf("age=%d st.score=%.2f sex=%c\n", st.age, st.score, st.sex);
printf("age=%d st.score=%.2f sex=%c\n", st2.age, st2.score, st2.sex);
system("pause");
return 0;
}
2 如何取出结构体变量中的每一个成员
方式1 结构体变量名.成员名
方式2 指针变量->成员名
代码示例:
#include<stdio.h>
#include<iostream>
struct Student
{
int age;
float score;
char sex;
};
int main()
{
struct Student st = { 80, 66.6, 'F' };
struct Student st2;
struct Student *pst = &st2;
pst->age = 90;
st2.score = 88.8;
pst->sex = 'F';
printf("age=%d st.score=%.2f sex=%c\n", st.age, st.score, st.sex);
printf("age=%d st.score=%.2f sex=%c\n", pst->age, pst->score, pst->sex);
system("pause");
return 0;
}
3 结构体与指针
要求:通过指针和函数对结构体变量的输入和输出
代码示例:
#pragma warning( disable : 4996)
#include<stdio.h>
#include<iostream>
#include<malloc.h>
#include<string.h>
struct Student
{
int age;
char sex;
char name[100];
};
void InputStudent(struct Student * pstu);
void OutputStudent(struct Student * pstu);
int main()
{
struct Student st;
InputStudent(&st);
OutputStudent(&st);
system("pause");
return 0;
}
void InputStudent(struct Student * pstu)
{
pstu->age = 10;
strcpy(pstu->name, "zhangsan");(*pstu).name
pstu->sex = 'F';
}
void OutputStudent(struct Student * pstu)
{
printf("age=%d name=%s sex=%c\n", (*pstu).age, (*pstu).name, (*pstu).sex);
}
未完待续
参考文献
1、c程序设计(第五版)(谭浩强) 2、https://blog.csdn.net/grey_csdn/article/details/68954750 3、https://zhuanlan.zhihu.com/p/87364251 4、https://blog.csdn.net/zaishuiyifangxym/article/details/105565374
|