结构体类型
在一个组合中包含若干个类型不同的数据项。相当于其他高级语言中的记录。
声明
- 一般形式:
struct 结构名
{
数据类型 成员名 1;
数据类型 成员名 2;
:
数据类型 成员名 n;
};- 结构体类型名作为结构体类型的标志。
- 声明一个结构体类型时必须对各个成员进行类型声明:类型名 成员名;
- 每一个成员也成为结构体中一个域,所以成员表又称为域表。
- 结构体的成员可以是数据,又可以是函数。
- 声明结构体并不实际分配内存单元。
struct Student //声明一个结构体类型
{
int num;
char name[20];
char sex;
int age;
};
- 注意:
- 结构变量的存储类型概念、它的寿命、可见性及使用范围与普通变量完全一致。
- 结构变量说明在结构类型声明之后,二者也可同时进行。
- 结构变量占内存大小可用 sizeof 运算求出: sizeof(运算量)
结构体类型变量的定义方法与初始化
- 定义结构体类型变量的2中方法:
-
先声明结构体类型再定义变量
Student student1,student2;//student1,student2是两个结构体类型Student的变量
-
声明结构体类型的同时定义变量
一般形式:
struct 结构体类型名{
成员名;
} 变量名表;struct Student { int num; char name[20]; char sex; int age; }student1,student2;//student1,student2是两个结构体类型Student的变量
-
当多文件引用同一个结构体变量时,采用第一种方法;否则可采用第二种。
定义了结构体变量之后,系统会给它分配内存空间。
- 初始化
-
可以在声明结构体并定义变量时初始化
struct Student { int num; char name[20]; char sex; int age; }student1={201313232,“yejing”,‘f’,18};
-
结构体声明与定义分开的情况,在定义变量时初始化。
Student student1={201313232,“yejing”,‘f’,18};
-
引用结构体变量
- 可以将一个结构体变量的值赋给另一个具有相同结构的结构体变量。
student1=student2;
- 可以引用一个结构体变量中的一个成员的值。
引用形式:
结构体变量名.成员名;
" . " 成员运算符
#include <iostream>
using namespace std;
struct Student
{
int num;
char name[20];
char sex;
int age;
}student1,student2;
int main() {
student1 = { 123,"yejing",'f',18 };
student2 = student1;
cout << student1.num << " " << student2.num; // 123 123
cout << student1.name << " " << student2.name; // yejing yejing
}
结构体数组
每个数组元素都是一个结构体类型的数据,它们分别都包含各自的成员项。
#include <iostream>
using namespace std;
struct Student
{
char name[20];
int count;
};
int main() {
Student s[3] = {"Tom",0,"Rain",0,"Sun",0};
char na[20];
for (int i = 0; i < 10; i++) {
cin >> na;
//以下对分支if可以使用for+if改写
if (strcmp(na, s[0].name)==0)//对字符数组的比较需要使用特殊函数
s[0].count++;
else if (strcmp(na, s[1].name)==0)
s[1].count++;
else if (strcmp(na, s[2].name)==0)
s[2].count++;
}
for (int i = 0; i < 3; i++)
cout << s[i].name << ":" << s[i].count<<endl;
}
结果:
指向结构体变量的指针
一个结构体变量的指针就是该变量所占据的内存段的起始地址。
指针变量也可以指向结构体数组中的元素。
-
通过指向结构体变量的指针引用结构体变量的成员
以下3种方式等价:- 结构体变量 . 成员名
- (* 指针名 ). 成员名
- 指针名->成员名
#include <iostream> #include <string> using namespace std; struct Student { string name; char sex; int age; }; int main() { Student s; Student *p = &s; s.name = "yj"; s.age = 19; s.sex = 'm'; p->sex = 'f';//通过指针操作结构体类型变量的成员值 cout << s.name << " " << s.age<<" "<<s.sex<<endl; //yj 19 f cout << (*p).name << " " << (*p).age << " " << (*p).sex; //yj 19 f 注意*p两边的()不可以省去,因为成员运算符‘.’优先级高于‘*’优先级。此外p->name等价于(*p).name。 return 0; }
-
用结构体变量和指向结构体变量的指针构成链表
链表:- 链表是一种重要的数据结构。
- 链表有一个头指针,它存放一个地址。该地址指向一个元素。
- 链表中的每一个元素称为节点。每个节点都应该包括两部分:用户需要用的实际数据和下一个节点的地址。最后一个元素不在指向其他元素,它的地址部分放一个“NULL”表示空地址。链表到此结束。
- 链表中各元素的地址可以是不连续的,要找某个元素,可以通过上一个元素提供的地址找到它。
- 链表数据结构必须使用指针和结构体变量才能实现。可以声明一个结构体类型,包含两种数据成员:一种是用户需要用的实际数据,另一种是用来存放下一个节点地址的指针变量。
#include <iostream>
#include <string>
using namespace std;
struct Student {
int sno;
string name;
Student *next;
};
int main() {
Student a, b, c;
a.sno = 11; a.name = "Tom";
b.sno = 22; b.name = "Sun";
c.sno = 33; c.name = "Cloud";
Student *head;
Student *p;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
do {
cout << p->sno << " " << p->name << " " <<endl; //输出p指向的节点的数据
p=p->next; //使p指向下一个节点;相当于p=(*p).next;(*)p.next相当于a.next;
} while (p!=NULL); //输出节点c数据后,p指针为null;
return 0;
}
输出: 11 Tom
22 Sun
33 Cloud
结构体类型数据作为函数参数
- 结构体变量名作为作参数
- 用指向结构体变量的指针作形参,结构体变量的地址作为实参
- 用结构体变量的引用作为函数形参,它成为实参的别名。
#include <iostream>
#include <string>
using namespace std;
struct Student {
int sno;
string name;
};
int main() {
Student a, b, c;
a.sno = 11; a.name = "Tom";
b.sno = 22; b.name = "Sun";
c.sno = 33; c.name = "Cloud";
void print(Student s);
void print(Student *p);
void print1(Student &ss);
print(a); //Tom 11
print(&b); //Sun 22
print1(c); //Cloud 33
return 0;
}
//1. 结构体变量名作为作参数
void print(Student s) {
cout << s.name << " " << s.sno << endl;
}
//2. 用指向结构体变量的指针作形参,结构体变量的地址作为实参
void print(Student *p) {
cout << p->name << " " << p->sno;
}
//3. 用结构体变量的引用作为函数形参,它成为实参的别名。
void print1(Student &s) {
cout << s.name << " " << s.sno << endl;
}
动态空间分配与释放
c语言中,使用库函数malloc和free来分配和撤销内存空间。
c++提供运算符new和delete来取代malloc和free函数。
-
new 和delete是运算符,而不是函数,执行效率高。
-
一般形式:
new 类型 [初值];- 用new分配数组空间时不可以指定初值。
- 若因为内存原因而导致不能正常分配空间,new会返回一个空指针。
new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针); new int(100);//开辟一个存放整数的存储空间,并且初值为100,返回一个指向该存储空间的地址(即指针); new char[10];//开辟一个存放字符数组的空间,返回一个指向字符数组首元素的地址(即指针); new int[4][3];//开辟一个存放二维整型数组的空间,返回一个指向该数组首元素的地址(即指针); float *p = new float(3.14);//开辟一个存放单精度数的空间,并指定初值为3.14,将返回的该空间的地址赋给指针变量p
delete 指针变量------- --对变量
delete [] 指针变量 -------对数组char *p1=new char[10];//开辟一个存放字符数组的空间,返回一个指向字符数组首元素的地址(即指针); delete[] p1; //释放开辟的空间 int **p2 =new int[4][3]; //错误(活动) E0144 "int (*)[3]" 类型的值不能用于初始化 "int **" 类型的实体, C2440 “初始化” : 无法从“int(*)[3]”转换为“int **” delete[] p2; float *p = new float(float(3.14));//开辟一个存放单精度数的空间,并指定初值为3.14,将返回的该空间的地址赋给指针变量p delete p;//释放开辟的空间
枚举类型–enum
- 只要将需要的变量值一一列举出来,便构成了一个枚举类型。
- 枚举类型的声明形式如下:
enum 枚举类型名 {变量值列表};
• 例如:
enum Weekday
{SUN, MON, TUE, WED, THU, FRI, SAT};
- 枚举类型应用说明:
- 对枚举元素按常量处理,不能对它们赋值。例如,不能写: SUN = 0;
- 枚举元素具有默认值,它们依次为:0,1,2,…。
- 也可以在声明时另行指定枚举元素的值,如:
enum Weekday {SUN=7,MON=1,TUE,WED,THU,FRI,SAT}; - 枚举值可以进行关系运算。
- 整数值不能直接赋给枚举变量,如需要将整数赋值给枚举变量,应进行强制类型转换
设某次体育比赛的结果有四种可能:胜(WIN)、负(LOSE)、平局(TIE)、比赛取(CANCEL),编写程序顺序输出这四种情况。
typedef语句
-
为一个已有的数据类型另外命名
-
语法形式
typedef 已有类型名 新类型名表;• 例如
typedef double Area;
Area a; -
不推荐使用,降低可读性
联合体
- 声明形式:
union 联合名
{
数据类型 成员名 1;
数据类型 成员名 2;
:
数据类型 成员名 n;
}; - 联合体类型变量说明的语法形式
联合名 联合变量名; - 引用形式:
联合名.成员名
例如:
union uarea
{ char c_data;
short s_data;
long l_data;
}
- 无名联合
• 无名联合没有标记名,只是声明一个成员项的集合,这些成员项具有相同的内存地址,可以由成员项的名字直接访问。
例:
union
{ int i;
float f;
}
在程序中可以这样使用:
i=10;
f=2.2;