结构体用于存储不同类型的数据项。
定义结构 必须使用 struct
语句。struct
语句定义了一个包含多个成员的新的数据类型,struct
语句的格式如下:
1 2 3 4 5 6 struct tag { member-list member-list member-list ... } variable-list ;
tag
是结构体标签。member-list
是标准的变量定义,比如 int i
; 或者 float f
,或者其他有效的变量定义。variable-list
结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。下面是声明 Book
结构的方式:
1 2 3 4 5 6 7 struct Books { char title[50 ]; char author[50 ]; char subject[100 ]; int book_id; } book;
在一般情况下,tag
、member-list
、variable-list
这 3 部分至少要出现 2 个。
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 struct { int a; char b; double c; } s1; struct SIMPLE { int a; char b; double c; }; struct SIMPLE t1 , t2 [20], *t3 ; typedef struct { int a; char b; double c; } Simple2; Simple2 u1, u2[20 ], *u3;
在上面的声明中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的,如果令 t3=&s1
,则是非法的。
结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
1 2 3 4 5 6 7 8 9 10 11 12 13 struct COMPLEX { char string [100 ]; struct SIMPLE a ; }; struct NODE { char string [100 ]; struct NODE *next_node ; };
如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct B ; struct A { struct B *partner ; }; struct B { struct A *partner ; };
结构体变量的初始化 和其它类型变量一样,对结构体变量可以在定义时指定初始值。
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> struct Books { char title[50 ]; char author[50 ]; char subject[100 ]; int book_id; } book = {"C 语言" , "RUNOOB" , "编程语言" , 123456 }; int main () { printf ("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n" , book.title, book.author, book.subject, book.book_id); }
执行输出结果为:
1 2 3 4 title : C 语言 author: RUNOOB subject: 编程语言 book_id: 123456
访问结构成员 为了访问结构的成员,我们使用成员访问运算符(.)
。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。也可以使用 struct
关键字来定义结构类型的变量。
下面的实例演示了结构的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <stdio.h> #include <string.h> struct Books { char title[50 ]; char author[50 ]; char subject[100 ]; int book_id; }; int main ( ) { struct Books Book1 ; struct Books Book2 ; strcpy ( Book1.title, "C Programming" ); strcpy ( Book1.author, "Nuha Ali" ); strcpy ( Book1.subject, "C Programming Tutorial" ); Book1.book_id = 6495407 ; strcpy ( Book2.title, "Telecom Billing" ); strcpy ( Book2.author, "Zara Ali" ); strcpy ( Book2.subject, "Telecom Billing Tutorial" ); Book2.book_id = 6495700 ; 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); 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 ; }
结果:
1 2 3 4 5 6 7 8 Book 1 title : C Programming Book 1 author : Nuha Ali Book 1 subject : C Programming Tutorial Book 1 book_id : 6495407 Book 2 title : Telecom Billing Book 2 author : Zara Ali Book 2 subject : Telecom Billing Tutorial Book 2 book_id : 6495700
结构作为函数参数 可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。可以使用上面实例中的方式来访问结构变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <stdio.h> #include <string.h> struct Books { char title[50 ]; char author[50 ]; char subject[100 ]; int book_id; }; void printBook ( struct Books book ) ;int main ( ) { struct Books Book1 ; struct Books Book2 ; strcpy ( Book1.title, "C Programming" ); strcpy ( Book1.author, "Nuha Ali" ); strcpy ( Book1.subject, "C Programming Tutorial" ); Book1.book_id = 6495407 ; strcpy ( Book2.title, "Telecom Billing" ); strcpy ( Book2.author, "Zara Ali" ); strcpy ( Book2.subject, "Telecom Billing Tutorial" ); Book2.book_id = 6495700 ; printBook( Book1 ); 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); }
结果:
1 2 3 4 5 6 7 8 Book title : C Programming Book author : Nuha Ali Book subject : C Programming Tutorial Book book_id : 6495407 Book title : Telecom Billing Book author : Zara Ali Book subject : Telecom Billing Tutorial Book book_id : 6495700
指向结构的指针 可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示:
1 struct Books *struct_pointer ;
在上述定义的指针变量中,存储结构变量的地址,使用 &
运算符获取地址,如下所示:
1 struct_pointer = &Book1;
使用 ->
运算符,访问指向该结构的指针访问结构的成员,如下所示:
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <stdio.h> #include <string.h> struct Books { char title[50 ]; char author[50 ]; char subject[100 ]; int book_id; }; void printBook ( struct Books *book ) ;int main ( ) { struct Books Book1 ; struct Books Book2 ; strcpy ( Book1.title, "C Programming" ); strcpy ( Book1.author, "Nuha Ali" ); strcpy ( Book1.subject, "C Programming Tutorial" ); Book1.book_id = 6495407 ; strcpy ( Book2.title, "Telecom Billing" ); strcpy ( Book2.author, "Zara Ali" ); strcpy ( Book2.subject, "Telecom Billing Tutorial" ); Book2.book_id = 6495700 ; printBook( &Book1 ); 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); }
当上面的代码被编译和执行时,它会产生下列结果:
1 2 3 4 5 6 7 8 Book title : C Programming Book author : Nuha Ali Book subject : C Programming Tutorial Book book_id : 6495407 Book title : Telecom Billing Book author : Zara Ali Book subject : Telecom Billing Tutorial Book book_id : 6495700
结构体内存大小对齐原则
结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding)。即结构体成员的末地址减去结构体首地址(第一个结构体成员的首地址)得到的偏移量都要是对应成员大小的整数倍。
结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在成员末尾加上填充字节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> typedef struct { unsigned char a; unsigned int b; unsigned char c; } debug_size1_t ; typedef struct { unsigned char a; unsigned char b; unsigned int c; } debug_size2_t ; int main (void ) { printf ("debug_size1_t size=%lu,debug_size2_t size=%lu\r\n" , sizeof (debug_size1_t ), sizeof (debug_size2_t )); return 0 ; }
编译执行输出结果:
1 debug_size1_t size=12 ,debug_size2_t size=8
结构体占用存储空间,以32位机为例
debug_size1_t 存储空间分布为 a(1byte)+空闲(3byte)+b(4byte)+c(1byte)+空闲(3byte)=12(byte)。
debug_size2_t 存储空间分布为a(1byte)+b(1byte)+空闲(2byte)+c(4byte)=8(byte)。
动态可变长的结构体 注意:一个结构体中只能有一个可变长的成员,并且该成员必须是最后一个成员。
1 2 3 4 5 typedef struct { int id; char name[0 ]; }stu_t ;
定义该结构体,只占用4字节的内存,name
不占用内存。
1 2 3 4 stu_t *s = NULL ; s = malloc (sizeof (*s) + 100 ); s->id = 1010 ; strcpy (s->name,"hello" );
参考
C 结构体