声明一个结构体类型的一般形式为:
struct 结构体名{j结构体所包含的成员变量}
struct stu{
char name[20];//姓名
int num;//学号
int age;//年龄
char grop;、、所在学习小组
}
stu 为结构体名,它包含了5个成员,分别是 name,num,age,group,score
定义结构体类型变量:
struct stu s1,s2;
struct stu{
char name[20];//姓名
int num;//学号
int age;//年龄
char group;//所在学习小组
float score;//成绩
}s1,s2;
struct {
char name[20];
int num;
int age;
char group;
float score;
}s1,s2;
结构体变量赋值与使用
struct stu stu1 = {"Tom", 12,18,'A',136.5};
struct stu stu1 = {.name="Tom”,.num= 12, .age=18,.group='A',.score=136.5};
struct stu {
char *name;
int num;
int age;
char group;
float score;
}s1 = {"Tom",12,18,'A',136.5};
访问结构体成员变量使用点号操作符·
stu1.name= "Tom";
stu1.num=12;
stu1.age=18;
stu1.group='A';
stu1.score=136.5;
结构体内存对齐模式:
内存对齐初步
数据项只能存储在地址是数据项大小的整数倍的内存位置上
例如int类型占用4个字节,地址只能在0,4,8等位置上。
操作系统的默认对齐系数
每个操作系统都有自己的默认内存对齐系统,如果是新版本的操作系统,默认对齐系统一般都是8,因为操作系统定义的最大类型存储单元就是8个字节,例如long long,不存在超过8个字节的类型(例如int是4,char是1,long在32为编译时是4,64位编译时是8)。当操作系统的默认对齐系数与内存对齐理论产生冲突时,以操作系统的对齐系数为基准。
例如:
假设操作系统的默认对齐系数是4,那么对与long long这个类型的变量就不满足第一节所说的,也就是说long long这种结构,可以存储在被4整除的位置上,也可以存储在被8整除的位置上。
可以通过#pragmatic pack()语句修改操作系统的默认对齐系数,编写程序的时候不建议修改默认对齐系数。
内存对齐产生的影响
内存对齐是操作系统为了快速访问内存而采取的一种策略,简单来说,就是为了放置变量的二次访问。操作系统在访问内存时,每次读取一定的长度(这个长度就是操作系统的默认对齐系数,或者是默认对齐系数的整数倍)。如果没有内存对齐时,为了读取一个变量是,会产生总线的二次访问。
例如假设没有内存对齐(默认对齐系数是8),结构体xx的变量位置会出现如下情况:
structxx{
char b; //oxffbff5e8
int a; //oxffbff5e9
int c;//oxffbff5ed
char d;//oxffbff5f1
};
操作系统先读取oxffbff5e8-oxffbff5ef的内存,然后在读取oxffbff5fo-oxffbff5f8的内存,为了获得值c,就需要将两组内存合并,进行整合,这样严重降低了内存的访问效率。(这就涉及到了老生常谈的问题,空间和效率那个更重要?)。
这样大家就能理解为什么结构体的第一变量,不管类型如何,都是能被8整除的吧(因为访问内存是从8的整数倍开始的,为了增加读取的效率)!
define 宏函数
#define SUM(a,b) ((a)+(b))
#define MIN(a,b) ((a)<(b)?(a):(b)
条件编译ifdef #ifndef...#else...#endif
#ifndef标识符
程序段1
#else
程序段2
#endif
与上一种形式的区别是ifdef改为ifndef。它的功能是:如果标识符未被#define命令定义过,则对程序段1进行编译;否则对程序2进行编译。这与第一种形式的功能正好相反
static 修饰局部变量
在局部静态变量前面加上关键字static,该局部变量便成了静态局部变量。静态局部变量有以下特点:
(1)该变量在全局数据区分配内存
(2)如果不显示初始化,那么将被隐式初始化为0
(3)它始终驻留在全局数据区,直到程序运行结束
(4)其作用域为局部作用域,当定义它的函数块语句块结束时,其作用域随之结束。
static修饰全局变量
在全局变量前面加上关键字static,该全局变量变成了全局静态变量。
全局静态变量有以下特点:
(1)在全局数据区分配内存
(2)如果没有初始化,其默认值为0
(3)该变量在本文件内从定义开始到文件结束可见,即只能在本文件内使用
const修饰一般变量
一般变量是指简单类型的只读变量。这种只读变量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。例如:
int const i=2;或const int i=2;
定义或说明一个只读数组可采用如下格式:
int const a[5]={1,2,3,4,5};或 const int a[5]={1,2,3,4,5}
const int *p; //p可变,p指向的对象不可变
int const * p; //p可变,p指向的对象不可变
int * const p;// p不可变,p指向的对象可变
int *const p; //p不可变,p指向的对象可变
const int * const p; //指针p和p指向的对象都不可变
这里给出一个记忆和理解的方法:
先忽略类型名(编译器解析的时候也是忽略类型名),我们看const离哪个近,“近水楼台先得月”,离谁近就修饰谁。
const (int) *p //const 修饰*p,p是指针,*p是指针指向的对象,不可变