C++中,除了基本的数据类型(如char、int、float、double等),还有结构体类型(structure)、共用体类型(union)、枚举类型(enumeration)、类类型(class )等,供用户灵活使用。但是在面试时,和C语言有关的知识点涉及的比较多,其中结构体经常会出现,最常见的就是问题就是这个结构占多少个字节。
1、结构体被编译后实际占用内存的大小
struct
StudentType
//声明一个结构体类型StudentType
{
int
num; //int型变量num,占4个字节
char
name[20]; //char型数组name,占20个字节
char
sex; //char型变量sex,占1个字节
int
age; /int型变量age,占4个字节
float
score; //float型变量,占4个字节
char
addr[30]; //char型数组name,占30个字节
};//注意:最后有一个分号
struct
StudentType student1, student2;
以上定义了student1和student2为StudentType的变量,即它们具有StudentType类型的结构。在定义了结构体变量后,系统就会为之分配内存单元。
在理论上,student1和student2在内存中各占63个字节
:
4+20+1+4+4+30=63。
但是这里需要注意:根据不同编译器,内存存储会有所不同,存储该结构体会按照内存对齐进行相关处理,系统默认对齐系数为4(即按int类型对齐,粗略认识可以认为每相邻两个数据成员存储是大小是4的整数倍。具体计算如下:
struct
StudentType
//声明一个结构体类型StudentType
{
int
num; //int型变量num,理论上占4个字节,根据内存对齐
后
占4个字节
char
name[20]; //char型数组name,理论上占20个字节,根据内存对齐
后
占20个字节
char
sex; //char型变量sex,理论上占1个字节,根据内存对齐
后
占4个字节
int
age; /int型变量age,理论上占4个字节,根据内存对齐
后
占4个字节
float
score; //float型变量,理论上占4个字节,根据内存对齐
后
占4个字节
char
addr[30]; //char型数组name,理论上30个字节,根据内存对齐
后
占32个字节
};
因此,
实际上student1和student2占用内存为:4+20+4+4+4+32=68个字节
。
不清楚那些面试官为什么喜欢考和编译器有关的知识。
2、指向结构体变量的指针引用结构体变量中的成员
#include
<iostream>
#include
<string>
using
namespace std;
int
main( )
{
struct
Student
//声明结构体类型student
{
int
num;
char
sex;
float
score;
};
Student stu;
//定义Student类型的变量stu
Student *p=&stu;
//定义p为指向Student类型数据的指针变量并指向stu
stu.num=1000;
//对string变量可以直接赋值
stu.sex=15;
stu.score=99.5;
cout<<stu. num<<″ ″<<″ ″<<stu.sex<<″ ″<<
stu.score<<endl;
cout<<p -> num<<″ ″<<″ ″<<(*p).sex<<″ ″<<
(*p).score<<endl;
return
0;
}
程序运行结果如下:
1000 15 99.5 (通过结构体变量名引用成员)
1000 15 99.5 (通过指针引用结构体变量中的成员)
3、用结构体变量和指向结构体变量的指针构成链表
链表是一种常见的重要的数据结构。
链表有一个“头指针”变量,以head表示,它存放一个地址。该地址指向一个元素。
链表中的每一个元素称为“结点”,每个结点都应包括两个部分:
一是用户需要用的实际数据;
二是下一个结点的地址。
可以看到链表中各元素在内存中的存储单元可以是不连续的。要找某一元素,可以先找到上一个元素,根据它提供的下一元素地址找到下一个元素。
这种链表的数据结构,必须利用结构体变量和指针才能实现。
可以先声明一个结构体类型,包含两种成员,一种是用户需要用的实际数据,另一种是用来存放下一结点地址的指针变量。
例如,可以设计这样一个结构体类型:
struct
Student
{
int
num;
float
score;
Student *next;
//next指向Student结构体变量
};
其中成员num和score是用户需要用到的数据。next是指针类型的成员,它指向Student类型数据,就是next所在的结构体类型。用这种方法就可以建立链表。
每一个结点都属于Student类型,在它的成员next中存放下一个结点的地址,程序设计者不必知道各结点的具体地址,只要保证能将下一个结点的地址放到前一结点的成员next中即可。
下面通过一个例子来说明如何建立和输出一个简单链表。
建立一个简单链表,它由3个学生数据的结点组成。输出各结点中的数据。
#define
NULL 0
#include
<iostream>
struct
Student
{
long
num;
float
score;
struct
Student *next;
};
int
main( )
{
Student a,b,c,*head,*p;
a. num=31001;
a.score=89.5;
//对结点a的num和score成员赋值
b. num=31003;
b.score=90;
//对结点b的num和score成员赋值
c. num=31007;
c.score=85;
//对结点c的num和score成员赋值
head=&a;
//将结点a的起始地址赋给头指针head
a.next=&b;
//将结点b的起始地址赋给a结点的next成员
b.next=&c;
//将结点c的起始地址赋给b结点的next成员
c.next=NULL;
//结点的next成员不存放其他结点地址
p=head;
//使p指针指向a结点
do
{
cout<<p->num<<″ ″<<p->score<<endl;
//输出p指向的结点的数据
p=p->next;
//使p指向下一个结点
} while (p!=NULL);
//输出完c结点后p的值为NULL
return
0;
}
4、
将一个结构体
变量
中的数据传递给另一个函数
1)、
用结构体
变量
作函数参数
#include
<iostream>
#include
<string>
using
namespace std;
struct
Student
//声明结构体类型Student
{
int
num;
float
score[3];
};
void
print(Student *p);
//函数声明
int
main( )
{
Student stu;
//定义结构体变量
stu.num=12345;
stu.score[0]=67.5;
stu.score[1]=89;
stu.score[2]=78.5;
print(stu);
//调用print函数,输出stu各成员的值
return
0;
}
void
print(Student st)
{
cout<<st.num<<″ ″<<″ ″<<st.score[0]
<<″ ″ <<st.score[1]<<″ ″<<st.score[2]<<endl;
}
运行结果为:
12345 67.5 89 78.5
2)、用指向结构体
变量
的指针作实参
#include
<iostream>
#include
<string>
using
namespace std;
struct
Student
//声明结构体类型Student
{
int
num;
float
score[3];
}stu={12345,″Li Fung″,67.5,89,78.5};//定义结构体student
变量
stu并赋初值
void
print(Student *st);
//函数声明
int
main( )
{
print(stu);
//调用print函数,输出stu各成员的值
return
0;
}
void
print(Student *p)
{
cout<<p->
num<<″ ″<<″ ″<<p->
score[0] <<″ ″ <<p->
score[1]<<″ ″<<p->
score[2]<<endl;
}
