为什么出现结构体?
为了表示一些复杂的数据,一些基本数据类型无法满足要求,
当要用一个变量描述一个对象的多个属性时,普通的内置数据类型是表示不了的,这个时候就可以用结构体回。结构体和类很相似,唯一不同的是:结构体默认是公有成员,而类默认是私有成员。
什么叫结构体?C语言中的结构体
在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。
结构体定义与声明
结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量。 [1]
struct tag {member-list} variable-list ;
在一般情况下,tag、member-list、variable-list这3部分至少要出现2个。以下为示例:
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct { int a; char b; double c;
} s1;//同上声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE{ int a; char b;double c;
};//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;
//也可以用typedef创建新类型
typedef struct{int a;char b;double c;
} Simple2;
//可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;
注意事项:
在上面的声明中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的,如果令t3=&s1,则是非法的。 [1]
结构体变量不能加减乘除,可以相互赋值
普通结构体变量和指针结构体变量作为函数传参数问题
#include <stdio.h>
#include <string.h>void f(struct Student *pst);
void g(struct Student std);
struct Student {int sid;char name[20];int age;char like[60];}; //此处分号不可省略int main() {struct Student st;f(&st); //传地址给结构体的属性赋值printf("%d %s %d %s\n", st.sid, st.name, st.age, st.like);g(st); //赋值之后,结构体变量的属性值验证while (true){}return 0;
}void f(struct Student *pst) {(*pst).sid = 99;strcpy_s(pst->name, "老王");pst->age = 18;strcpy_s(pst->like, "老王喜欢隔壁住富婆");
}void g(struct Student std) {printf("%d %s %d %s\n", std.sid, std.name, std.age, std.like);
}
都能输出结果
结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
//此结构体的声明包含了其他的结构体
struct COMPLEX{char string[100];struct SIMPLE a;
};
//此结构体的声明包含了指向自己类型的指针
struct NODE{char string[100];struct NODE *next_node;
};
如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明,如下所示:
struct B;
//对结构体B进行不完整声明
//结构体A中包含指向结构体B的指针
struct A{struct B *partner;//other members;
};
//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明
struct B{struct A *partner;//other members;
};
结构体作用:
结构体和其他类型基础数据类型一样,例如int类型、char类型,只不过结构体可以做成你想要的数据类型。以方便日后的使用。 [1]
在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。由于C语言内部程序比较简单,研发人员通常使用结构体创造新的“属性”,其目的是简化运算。 [1]
结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。 [1]
结构体的大小与内存对齐
结构体的大小不是结构体元素单纯相加就行的,因为我们主流的计算机使用的都是32bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。 [1]
规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 [1]
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。 [1]
3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
C++中的结构体
在C语言中,可以定义结构体类型,将多个相关的变量包装成为一个整体使用。在结构体中的变量,可以是相同、部分相同,或完全不同的数据类型。在C语言中,结构体不能包含函数。在面向对象的程序设计中,对象具有状态(属性)和行为,状态保存在成员变量中,行为通过成员方法(函数)来实现。C语言中的结构体只能描述一个对象的状态,不能描述一个对象的行为。在C++中,考虑到C语言到C++语言过渡的连续性,对结构体进行了扩展,C++的结构体可以包含函数,这样,C++的结构体也具有类的功能,与class不同的是,结构体包含的函数默认为public,而不是private。
C++控制台输出例子:
#include<cstdlib>
#include<iostream>
//定义结构体
struct point{//包含两个变量成员int x;int y;
};
using namespace std;
int main(int argc,char * argv[]){point pt;//加上struct的结构体变量定义是C语言的特征,而C++语言不需要这样pt.x=1;pt.y=2;cout<<pt.x<<endl<<pt.y<<endl;return EXIT_SUCCESS;
}
C++中的结构体与类的区别
类与结构体在C++中有三点区别。 [1]
(1)class中默认的成员访问权限是private的,而struct中则是public的。
(2)从class继承默认是private继承,而从struct继承默认是public继承。
(3)C++的结构体声明不必有struct关键字,而C语言的结构体声明必须带有关键字(使用typedef别名定义除外)。
如何使用结构体?两种方式
struct Student st = {1000,"zhangsan",20};
struct Student *std = &st;1,st.sid = 500;2,std->sid=222;
结构体使用代码:
#include <stdio.h>
#include <string.h>struct Student {int sid;char name[20];int age;} st; //此处分号不可省略int main(void) {//第一种方式struct Student st = {1000,"zhangsan",20};printf("%d %s %d\n", st.sid, st.name, st.age);st.sid = 500;// st.name="lisi" //errorstrcpy_s(st.name,"lisi");st.age=20;printf("%d %s %d\n", st.sid, st.name, st.age);//第二种方式struct Student *std;std = &st;std->sid=222; //std->sid 等价于 (*std).sid 所以等价 st.sidprintf("%d %s %d\n", st.sid, st.name, st.age);while(true){}}
结构体简单使用案例效果: