结构体-----将不一样类型的数据成员组织到统一的名字之下,适用于对关系紧密,逻辑相关、具备相同或不一样类型的数据进行处理html
struct 结构名(也可称做结构标识符) 数组
{函数
类型 变量名;spa
类型 变量名;.net
······指针
};code
struct 结构名 结构变量;htm
或者blog
struct 结构名内存
{
类型 变量名;
类型 变量名;
······
}结构变量;
例:声明结构体类型的同时定义变量名
1 struct student 2 { 3 int num; 4 }teacher;
(声明结构体类型仅仅是声明了一个类型,系统并不为之分配内存,就如同系统不会为类型 int 分配内存同样。只有当使用这个类型定义了变量时,系统才会为变量分配内存。因此在声明结构体类型的时候,不能够对里面的变量进行初始化。)
定义了一个结构名为student的结构体和一个结构变量teacher,若是省略变量名(teacher),就变成了对结构的声明,上述结构体声明也可分开写
1 struct student 2 { 3 int num; 4 }; 5
6 struct student teacher;
与上面效果相同,可理解为struct student相似于int,而咱们用的是teacher相似于变量,若是省略结构名,则称之为无名结构,这种状况经常出如今函数内部,或者说你只须要teacher这一个变量,
后面不须要再使用结构体名定义其余变量,那么在定义时也能够不给出结构体名
1 struct
2 { 3 int num; 4 }teacher;
(在声明结构体时经常与typedef函数配合使用)
访问结构体变量的成员必须使用成员选择运算符(也称圆点运算符),格式为:结构体变量名.成员名
若使用指针对结构体成员进行访问,格式为:指针->成员名 等价于 (*指针).成员名
为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等),
(注意与#define的区别,typedef 是用来定义一种类型的新别名的,它不一样于宏#define,宏是简单的字符串替换)
例:
1 typedef int INTEGER;
为int定义了一个新的名字INTEGER,也就是说INTEGER与int是同义词,也能够为结构体定义一个别名
1 typedef struct student STUDENT;
或者
1 typedef struct student 2 { 3 int num; 4 }STUDENT;
上述两条语句是等价的,两者都是为struct student结构体类型定义了一个新的名字STUDENT,即STUDENT与struct student是同义词,因此下列两条语句等价
1 1 STUDENT stu1,stu2; 2 2 struct student stu1, stu2;
1 typedef struct tagNode 2 { 3 char *pItem; 4 pNode pNext; 5 } *pNode;
上述代码编译阶段会报错,缘由:
在上面的代码中,新结构创建的过程当中遇到了 pNext 声明,其类型是 pNode。这里要特别注意的是,pNode 表示的是该结构体的新别名。
因而问题出现了,在结构体类型自己尚未创建完成的时候,编译器根本就不认识 pNode,由于这个结构体类型的新别名还不存在,因此天然就会报错。
所以,咱们要作一些适当的调整,好比将结构体中的 pNext 声明修改为以下方式:
1 typedef struct tagNode 2 { 3 char *pItem; 4 struct tagNode *pNext; 5 } *pNode;
或者将 struct 与 typedef 分开定义
1 typedef struct tagNode *pNode; 2 struct tagNode 3 { 4 char *pItem; 5 pNode pNext; 6 };
在上面的代码中,咱们一样使用 typedef 给一个还未彻底声明的类型 tagNode 起了一个新别名。不过,虽然 C 语言编译器彻底支持这种作法,但不推荐这样作,建议改成
1 struct tagNode 2 { 3 char *pItem; 4 struct tagNode *pNext; 5 }; 6 typedef struct tagNode *pNode;
#define函数格式:
#define 标识符 字符串,标识符成为宏名,宏替换时不作任何语法检查
1 typedef char* pStr1; 2 #define pStr2 char*
3 pStr1 s1,s2; 4 pStr2 s3,s4;
在上述的变量定义中,s一、s二、s3都被定义为char *,而s4则定义成了char,不是咱们所预期的指针变量,根本缘由就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。
上例中#define语句应该写成 pStr2 s3, *s4;
就是在一个结构体内包含了另外一个结构体做为其成员
1 typedef struct date 2 { 3 int year; 4 int month; 5 int day; 6 }DATE; 7
8 typedef struct student 9 { 10 long studentID; 11 char studentName[10]; 12 char studentSex; 13 DATE birthday; 14 int score[4]; 15 }STUDENT; 16 STUDENT pp;
上面代码中,定义告终构体变量birthday和pp,并给struct date和struct student分别取别名为DATE和STUDENT,
当出现结构体嵌套时,必须以级联方式访问结构体成员,即经过成员选择运算符逐级找到最底层的成员时再引用
1 pp.birthday.day = 10; 2 printf("%d", pp.birthday.day);
上面是使用了typedef的结构体嵌套,也能够不使用,代码以下
1 struct STUDENT 2 { 3 long studentID; 4 char studentName[10]; 5 char studentSex; 6 int score[4]; 7 struct DATE 8 { 9 int year; 10 int month; 11 int day; 12 }birthday; 13 }student;
定义告终构体变量student和birthday,引用成员的的方法和上面相似
1 student.birthday.day = 100; 2 printf("%d", student.birthday.day);
C语言容许对具备相同结构体类型的变量进行总体赋值,注意:对字符数组型结构体成员进行赋值时必定要使用strcpy()
1 strcpy(stu1.studentName, “王刚”);
而不能写成
1 stu2.studentName = stu1.studentName
由于结构体成员studentName是一个字符型数组,studentName是该数组的名字,表明字符型数组的首地址,是一个常量,不能做为赋值表达式的左值,
结构体所占内存的字节数,不是简单的相加, 由于对多数计算机而言,为了提升内存寻址的效率,不少处理器体系结构为特定的数据类型引入了特殊了内存对齐需求,
不一样的系统和编译器,内存对齐的方式有所不一样,为了知足处理器的对其要求,可能会在较小的成员后加入补位,例:
1 Typedef struct sample 2 { 3 Char m1; 4 Int m2; 5 Char m3; 6 }SAMPLE;
字节长度为12而不是1+4+1=6字节长度,即sizeof(struct sample)==12;
1 typedef struct student 2 { 3 long studentID; 4 char studentName[10]; 5 char studentSex; 6 DATE birthday; 7 int score[4]; 8 }STUDENT; 9 STUDENT stu1; 10 STUDENT *pt; 11 pt = &stu1;
或者
1 STUDENT *pt = &stu1;
上面的代码中,定义告终构体变量stu1,和结构体指针变量pt,并将stu1变量的地址赋值给了指针变量pt
假设已声明了STUDENT结构体类型,而且已定义了一个有30个元素的结构体数组stu,则定义结构体指针变量pt并将其指向结构体数组stu的方法为:
1 STUDENT *pt = stu;
等价于
1 STUDENT *pt = &stu[0];
等价于
1 STUDENT *pt; 2 pt = stu;
将结构体传递给函数的方式有以下3种:
1.用结构体的单个成员做为函数参数,向函数传递结构体的单个成员(属于传值调用,不会影响相应的实参结构体的值)
2.用结构体变量作函数参数,向函数传递结构体完整结构(属于传值调用,不会影响相应的实参结构体的值)
3.用结构体指针或结构体数组做函数参数属于模拟按引用调用,会影响相应的实参结构体的值,向函数传递结构体地址,由于仅复制结构体首地址一个值给被调函数,相对于第二种方式,这种传递效率更高
按值调用:将程序将函数调用语句中的实参的一份副本传给函数的形参
模拟按引用调用:指针做为函数的参数,虽然实际上也是传值给被调用函数,可是传给被调用函数的这个值不是变量的值,而是变量的地址,
经过向被调用函数传递某个变量的地址值能够在被调函数中改变主调函数中这个变量的值,至关于模拟C++中的按引用调用所以称为模拟按引用调用
参考连接:
http://www.javashuo.com/article/p-gfvlhpwk-kr.html