1、结构体的定义与声明
结构体的定义如下所示,struct
为结构体关键字,tag
为结构体的标志,member-list
为结构体成员列表,其必须列出其所有成员;variable-list
为此结构体声明的变量。
struct tag {member-list} variable-list ;
在一般情况下,tag
、member-list
、variable-list
这3部分至少要出现2个。
例如,
1)匿名结构体
#include <iostream>
using namespace std;
int main() {
// 匿名结构体,直接声明变量 s1
struct {
int a;
char b;
double c;
} s1;
// 初始化并访问匿名结构体的成员
s1.a = 10;
s1.b = 'X';
s1.c = 3.14;
cout << "s1: a=" << s1.a << ", b=" << s1.b << ", c=" << s1.c << endl;
return 0;
}
2)使用带标签的结构体
#include <iostream>
using namespace std;
int main() {
// 使用带标签的结构体 SIMPLE 声明的变量 t1
struct SIMPLE {
int a;
char b;
double c;
};
struct SIMPLE t1; // 定义结构体变量 t1
// 在 C++ 中使用 SIMPLE 标签可以省略 struct 关键字
//SIMPLE t1; // 直接使用 SIMPLE 标签
t1.a = 20;
t1.b = 'Y';
t1.c = 6.28;
cout << "t1: a=" << t1.a << ", b="
<< t1.b << ", c=" << t1.c << endl;
// 使用带标签的结构体 SIMPLE 声明数组和指针
struct SIMPLE t2[20]; // 声明结构体数组
struct SIMPLE* t3; // 声明结构体指针
t2[0].a = 30;
t2[0].b = 'Z';
t2[0].c = 9.42;
t3 = &t2[0]; // 指针指向数组中的第一个元素
cout << "t3: a=" << t3->a << ", b="
<< t3->b << ", c=" << t3->c << endl;
return 0;
}
3)使用 typedef 定义的新类型
#include <iostream>
using namespace std;
int main() {
// 使用 typedef 定义的新类型 Simple2
typedef struct {
int a;
char b;
double c;
} Simple2;
Simple2 u1; // 单个结构体变量
Simple2 u2[20]; // 结构体数组
Simple2* u3; // 结构体指针
u1.a = 40;
u1.b = 'A';
u1.c = 12.56;
cout << "u1: a=" << u1.a << ", b="
<< u1.b << ", c=" << u1.c << endl;
u2[0].a = 50;
u2[0].b = 'B';
u2[0].c = 15.78;
u3 = &u2[0]; // 指针指向数组中的第一个元素
cout << "u3: a=" << u3->a << ", b="
<< u3->b << ", c=" << u3->c << endl;
return 0;
}
注意:如上面示例中,即使他们的成员列表是一样的,它们也是不同的类型。以上语法与C语言中基本相同,C++中声明结构体变量时可以省略struct
。
2、嵌套结构体
结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
例如,
#include <iostream>
using namespace std;
struct Point {
int x;
int y;
};
struct Rectangle {
Point topLeft; // 左上角坐标
Point bottomRight; // 右下角坐标
};
int main() {
// 初始化嵌套结构体
Rectangle rect = {{0, 10}, {10, 0}};
std::cout << "Top-Left: ("
<< rect.topLeft.x << ", "
<< rect.topLeft.y << ")" << std::endl;
std::cout << "Bottom-Right: ("
<< rect.bottomRight.x << ", "
<< rect.bottomRight.y << ")" << std::endl;
return 0;
}
如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明。
例如,
#include <iostream>
#include <string>
// 前向声明 B
struct B;
// 定义结构体 A
struct A {
B* partner; // 指向 B 的指针
std::string name; // A 的其他成员
void display();
};
// 定义结构体 B
struct B {
A* partner; // 指向 A 的指针
std::string name; // B 的其他成员
void display();
};
// 定义结构体 A 的成员函数
void A::display() {
std::cout << "A's name: " << name;
if (partner) {
std::cout << ", Partner B's name: "
<< partner->name << std::endl;
} else {
std::cout << ", No partner assigned."
<< std::endl;
}
}
// 定义结构体 B 的成员函数
void B::display() {
std::cout << "B's name: " << name;
if (partner) {
std::cout << ", Partner A's name: "
<< partner->name << std::endl;
} else {
std::cout << ", No partner assigned."
<< std::endl;
}
}
int main() {
A aInstance;
B bInstance;
// 初始化结构体 A 和 B 的成员
aInstance.name = "Alice";
bInstance.name = "Bob";
// 设置互相引用
aInstance.partner = &bInstance;
bInstance.partner = &aInstance;
// 显示结构体信息
aInstance.display();
bInstance.display();
return 0;
}
3、没有成员变量的结构体
也可以定义一个空的结构体,有时候我们需要某一个结构体数据类型,但是暂时又不知道如何填充里面的成员变量,定义一个没有成员变量的结构体,它可以用于特定场景,例如作为标志、占位符、标识类型等。这种结构体的大小通常为 1 字节,主要是因为 C++ 要保证每个对象有唯一的地址。可以有如下定义:
struct EmptyStruct {};
使用示例:
#include <iostream>
struct Placeholder {}; // 空结构体
void doSomething(Placeholder) {
std::cout << "This function is called with a placeholder!" << std::endl;
}
int main() {
Placeholder p; // 创建空结构体的实例
doSomething(p);
return 0;
}
4、访问结构体成员
访问一个结构体成员变量,可以使用成员操作符(.
) ,
例如,
#include <iostream>
using namespace std;
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* book 2 specification */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* print Book1 info */
printf( "Book 1 title : %s\n", Book1.title);
printf( "Book 1 author : %s\n", Book1.author);
printf( "Book 1 subject : %s\n", Book1.subject);
printf( "Book 1 book_id : %d\n", Book1.book_id);
/* print Book2 info */
printf( "Book 2 title : %s\n", Book2.title);
printf( "Book 2 author : %s\n", Book2.author);
printf( "Book 2 subject : %s\n", Book2.subject);
printf( "Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
5、结构体作用
结构体和其他类型基础数据类型一样,例如,int
类型、char
类型,只不过结构体可以做成你想要的数据类型。以方便日后的使用。
在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。研发人员通常使用结构体创造新的“属性”,其目的是简化运算。
结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。
6、结构作为函数参数
可以像基本数据类型一样,把结构体作为函数的参数。
例如,
#include <iostream>
using namespace std;
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* function declaration */
void printBook( struct Books book );
int main( ) {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* book 2 specification */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* print Book1 info */
printBook( Book1 );
/* Print Book2 info */
printBook( Book2 );
return 0;
}
void printBook( struct Books book ) {
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
}
7、结构体的指针
定义声明结构体指针格式如下,
struct tag *struct_pointer;
例如,
#include <iostream>
using namespace std;
#include <stdlib.h>
/*
1.使用->引用结构体成员
*/
int main ()
{
struct Student
{
char cName[20];
int iNumber;
char cSex;
int iGrade;
}student={"Girl",2017,'w',2};
struct Student *pStruct;
pStruct = &student; //指向student结构体变量
printf("-----------the sudent's information----------\n");
printf("Name:%s\n",(*pStruct).cName);
printf("Number:%d\n",(*pStruct).iNumber);
printf("Sex:%c\n",(*pStruct).cSex);
printf("Grade:%d\n",(*pStruct).iGrade);
printf("============使用->符号引用结构体成员==============\n");
printf("Name:%s\n",pStruct->cName);
printf("Number:%d\n",pStruct->iNumber);
printf("Sex:%c\n",pStruct->cSex);
printf("iGrade:%d\n",pStruct->iGrade);
return 0;
}
8、结构体数组
元素为结构体类型的数组称为结构体数组,在实际的应用过程中,经常使用结构体数组来表示具有相同数据结构的一个群体。
例如,
#include <iostream>
using namespace std;
#include<stdlib.h>
//结构体中声明中尽量使用字符指针进行字符串操作,在初始化的时候会方便
//如果使用的是字符数组,那么会就要使用strcpy进行拷贝初始化
struct address{
char *country;
char *city;
};
struct teacher{
char *name;
int age;
struct address addr;
};
void out_teacher(struct teacher tea);
void out_all_teachers(struct teacher [],int num);
int main(int argc,char *argv[]){
//先定义结构体变量,再进行定义结构体数组
struct teacher teacher_one = {"zhangsan",20,{"china","shanghai"}};
struct teacher teacher_two = {"lisi",25,{"china","hefei"}};
struct teacher teachers_one [] = {teacher_one,teacher_two};
out_all_teachers(teachers_one,2);
printf("-----------------------------\n");
//在定义结构体数组的时候,直接进行结构体数组的初始化工作
struct teacher teachers_two [] = {{"wangwu",30,{"china","tianjin"}},{"zhaoliu",40,{"china","jiaozuo"}},{"tianqi",50,{"china","shenzhen"}}};
out_all_teachers(teachers_two,3);
return 0;
}
void out_teacher(struct teacher tea){
printf("name:%s",tea.name);
printf("age:%d\n",tea.age);
printf("country:%s\n",tea.addr.country);
printf("city:%s\n",tea.addr.city);
}
void out_all_teachers(struct teacher teachers[],int num){
int i = 0;
for(i = 0; i < num ; i++){
out_teacher(teachers[i]);
cout << "======================\n";
}
}
9、结构体占用内存空间
结构体变量的所占用内存空间的大小为各成员变量所占空间之和,使用sizeof
查看占用内存空间大小。
例如,
1)查看空结体占用空间
#include <iostream>
using namespace std;
#include <string.h>
struct Books {
};
int main( ) {
cout << (int) sizeof(struct Books) << endl; /*0*/
return 0;
}
2)查看结构体占用空间
#include <iostream>
using namespace std;
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main() {
cout << (int) sizeof(struct Books) << endl; /*204*/
return 0;
}