目录
文章目录
- 目录
- 结构体
- 声明一个结构体类型
- 定义一个结构体类型的变量
- 定义一个结构体类型的指针变量
- 结构体的成员
- 结构体的内存分布
结构体
结构体(Structure)是一种由不同类型的数据成员组成的数据类型。通过定义结构体,我们可以将多个不同的数据类型组合成一个单独的数据类型。
使用结构体,需要先声明类型,然后再定义类型的变量。
声明一个结构体类型
使用 struct 关键字来定义一个结构体类型:
struct tag { membermembermember...
} variable-list ;
- tag:结构体类型名。
- member:结构体所包含的成员,使用标准的变量定义语句,比如:
int i
。 - variable-list(可选):结构体变量,可以一次性指定一个或多个结构体类型的变量。
定义一个结构体类型的变量
- 直接定义:在声明结构体类型的同时定义结构体变量,如果后面不再需要定义其他新的结构体变量,那么我们可以在定义时不给出结构体类型名称。这种方式书写简单,但是因为没有结构体类型名称,所以后面就没法用该结构体类型定义新的变量。
struct {int a;char b;double c;
} s1;
- 间接定义:先声明定义结构体类型,再另外的定义结构体变量。
// 声明
struct SIMPLE
{int a;char b;double c;
};// 定义
struct SIMPLE t1, t2[20], *t3;
注意,在上述的两个示例中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的。
- 别名定义:我们可以同时使用关键字 struct 和 typedef 来声明一个结构体类型,并未其赋予一个 “别名”,后续使用该 “别名” 定义结构体变量时,就可以不重复的书写 struct 关键字了。
typedef struct
{int a;char b;double c;
} Simple2; // NOTE:因为前面有 typedef,此时的 Simple2 是一个别名,而不是变量。// 现在可以用 Simple2 作为类型,定义一个新的结构体变量
Simple2 u1, u2[20], *u3;
NOTE:在实际的编程中,我们经常会使用 *_s 后缀来命名一个结构体类型,而是用 *_t 后缀来命名一个结构体类型的别名(也称之为自定义一个新的数据类型)。e.g.
typedef struct student_s {char *name;int num;int age;char group;float score;
} student_tstudent_t stu1;
sizeof(student_t);
- 初始化结构体类型的变量(整体赋值):仅限于定义结构体变量的时候。
#include <stdio.h>/*** 声明 Books 结构体类型;* 定义 book 结构体变量;* 初始化 book 结构体变量;*/
struct Books {char title[50];char author[50];char subject[100];int id;
} book = {"is book", "fanguiju", "C", 123};int main() {printf("Book's title: %s\nauthor: %s\nsubject: %s\nid: %d\n", book.title, book.author, book.subject, book.id);return 0;
}
- 初始化结构体类型的变量(分别赋值):在使用过程中只能对成员逐一赋值,并使用 ‘.’(结构体成员访问运算符)对结构体的成员进行访问:
#include <stdio.h>
#include <string.h>/* 声明 Books 结构体类型 */
struct Books {char title[50];char author[50];char subject[100];int id;
};int main() {/* 定义 book 结构体变量 */struct Books book1;/* 初始化 book 结构体变量 */strcpy(book1.title, "C Programming"); // book1.title 是字符串类型,需要使用 strcpy() 接口,而不能直接赋值。strcpy(book1.author, "Nuha Ali");strcpy(book1.subject, "C Programming Tutorial");book1.id = 123;/* 访问结构体成员 */printf("Book's title: %s\nauthor: %s\nsubject: %s\nid: %d\n", book1.title, book1.author, book1.subject, book1.id);return 0;
}
定义一个结构体类型的指针变量
- 定义结构体 Books 的指针变量:
struct Books* struct_pointer;
- 将结构体变量的内存地址赋值到指针变量:
struct_pointer = &book1;
- 指针变量使用
->
运算符来访问结构体成员。
struct_pointer->title;
因为结构体指针变量 struct_pointer 本质是一个内存地址,跟结构体变量不同,不可以直接使用成员访问运算符 .
,而是使用 ->
运算符。
#include <stdio.h>
#include <string.h>struct Books {char title[50];char author[50];char subject[100];int id;
};void printBook(struct Books* book) {printf("Book's title: %s\nauthor: %s\nsubject: %s\nid: %d\n", book->title, book->author, book->subject, book->id);
}int main() {struct Books book1;strcpy(book1.title, "C Programming");strcpy(book1.author, "Nuha Ali");strcpy(book1.subject, "C Programming Tutorial");book1.id = 123;printBook(&book1);return 0;
}
结构体的成员
结构体的成员可以是大多数数据类型,包括可以是其他结构体,也可以是指向本身结构体类型的指针,这种指针的应用通常是为了实现一些更高级的数据结构,如:链表、树等。
// 包含其他结构体。
struct COMPLEX {char string[100];struct SIMPLE a;
};// 包含指向本身结构体类型的指针。
struct NODE {char string[100];struct NODE *next_node;
};
如果两个结构体互相包含,则需要对其中一个结构体进行声明,同时还要注意语句的顺序,否则会出现编译错误:
// 声明 B
struct B;// 声明 A
struct A{struct B *partner; // 包含 B//other members;
};struct B {struct A *partner; // 包含 A//other members;
};
结构体的内存分布
理论上讲,结构体的各个成员在内存空间中是连续存储的,和数组非常类似,比如结构体变量 stu1 的内存分布如下图所示,共占用 4 + 4 + 4 + 1 + 4 = 17 个字节。
但是在编译器的具体实现中,各个成员之间可能会存在缝隙,对于 stu1 的成员变量 group 和 score 之间就可能存在 3 个字节的空白填充。这样算来,stu1 其实占用了 17 + 3 = 20 个字节。