结构体
一、结构体应用情景
C语言中的结构体(struct)是一种复合数据类型,也可以理解为自定义的一种数据类型,可以将不同类型的数据组合成一个单一的实体。
结构体在C语言中通常用于以下情景:
- 封装相关数据:当需要将多个相关的数据项组合成一个单一的逻辑单元时,结构体非常有用。例如,如果你想存储一个学生的信息,包括学号、姓名和年龄,这些数据项虽然类型不同,但都描述了学生的属性,因此可以封装在一个结构体中。
- 数据库替代:由于C语言本身不支持数据库操作,结构体可以用来在内存中存储和操作大量数据,作为数据库的一种替代方法。
- 高级数据结构实现:结构体可以包含指向自己类型的指针,这使得它们可以用于实现链表、树等更高级的数据结构。
- 嵌入式开发:嵌入式开发过程中很多时候需要接受判断同一模块的多个参数,已经控制多个动作的是实现,使用结构体非常有利于操作
- 函数参数和返回值:结构体可以作为函数的参数和返回值传递,这样可以在函数之间传递复杂的数据结构。
二、结构体的定义、访问、赋值
1. 定义
结构体通过struct关键字来定义。它的一般形式如下:
注意:每一个数据类型的定义用分号结尾,整个结构体的定义后也有一个分号。类似普通数据类型定义语句。
struct 结构体名称
{
数据类型 成员1;
数据类型 成员2;
...
};
例如,定义一个表示书籍的结构体:
struct Book
{
char title[50];
char author[50];
char rate;
int pages;
float price;
};
在这个例子中,Book是结构体的名称,而title、author、pages和price是结构体的成员。
一旦定义了结构体类型,就可以创建该类型的变量,声明结构体变量的方法合声明普通数据类型的方法相同。
struct Book MyBook;
struct Book HisBook,HerBook;
其实也可以在定义的同时就声明结构体变量。
struct Book
{
char title[50];
char author[50];
char category;
int pages;
float price;
}MyBook;
2. 访问结构体成员
可以使用点运算符(.)来访问结构体的成员, 如果成员是字符串,可以借助字符串函数strcpy()
strcpy(myBook.title, "C语言程序设计");
myBook.pages = 300;
myBook.price = 29.99;
3. 赋值
1. 在声明的同时赋值
赋值顺序和结构体内变量定义顺序需要一致。
struct Book Mybook =
{
"C Programming",
"Nikita",
‘A',
300,
500.00
};
2. 对结构体内对象逐个赋值
对整形,浮点型和字符型可以用运算符 ‘=’ 赋值,而字符串即字符数组需要借助strcpy() 赋值
strcpy(Mybook.title, "C Programming");
strcpy(Mybook.author, "Nikita");
Mybook.category = 'A';
Mybook.pages = 300;
Mybook.price = 500.00;
整个程序示例
#include <stdio.h>
#include <string.h>
int main()
{
struct Book
{
char title[50];
char author[50];
char category;
int pages;
float price;
};
/*声明的同时整体赋值,此种形式需要按顺序
struct Book Mybook =
{
"C Programming",
"Nikita",
'A',
300,
500.00
};
*/
struct Book Mybook;
// 使用 strcpy() 将字符串字面量赋给字符数组
strcpy(Mybook.title, "C Programming");
strcpy(Mybook.author, "Nikita");
Mybook.category = 'A';
Mybook.pages = 300;
Mybook.price = 500.00;
printf("Book title: %s\n", Mybook.title);
printf("Book author: %c\n", Mybook.category);
printf("Book pages: %d\n", Mybook.pages);
return 0;
}
三、结构体数组
也可以创建结构体的数组来存储多个结构体变量,例如
#include <stdio.h>
struct book
{
char title[50];
char author[50];
float value;
};
int main()
{
struct book library[100];
printf("Please enter the book title.\n");
gets(library[0].title);
printf("Please enter the author.\n");
gets(library[0].author);
printf("Please enter the value.\n");
scanf("%f", &library[0].value);
printf("The book title is %s.\n", library[0].title);
printf("The author is %s.\n", library[0].author);
printf("The value is %f.\n", library[0].value);
return 0;
}
以上代码把library声明为一个内含100个元素的数组。数组的每个元素都是一个book类型的数组。数组名library本身不是结构名,它是一个数组名,该数组中的每个元素都是struct book类型的结构变量。因此,library[0]是第1个book类型的结构变量,library [1]是第2个book类型的结构变量,以此类推。如图所示。
标识结构数组的成员
为了标识结构数组中的成员,可以采用访问单独结构的规则:在结构名后面加一个点运算符,再在点运算符后面写上成员名。如下所示:
library[0].value; //第1个数组元素与value相关联
library[4].title; //第5个数组元素与title.相关联
注意,数组下标紧跟在library后面,不是成员名后面:
library.value[2]; //错误
library [2].value; //正确
那么下面的表达式代表什么意思呢?
library[2].title[4];
这是library数组第3个结构变量(library[2]部分)中书名的第5个字符(title [4]部分)。
以最后,总结一下:
library; //一个 book 结构的数组
library[2]; //一个数组元素,该元素是book结构
library[2].title; //一个char数组(library[2]的title成员)
library[2].title [4] //数组中library[2]元素的title成员的一个字符
四、结构体指针
可以使用指针来访问结构体变量,这在函数参数传递中特别有用:
struct Book *ptr;
ptr = &myBook;
printf("书名: %s\n", ptr->title);
在C语言中使用结构体指针是一种高效的方式来访问和操作结构体变量。下面是如何在结构体中使用指针的步骤:
1. 定义结构体指针
首先,定义一个结构体和它的指针类型。例如:
struct Point
{
int x;
int y;
};
2. 创建结构体指针
声明一个指向结构体的指针:
struct Point *ptr;
3. 初始化结构体指针
指针需要指向一个结构体实例:
struct Point point = {10, 20};
ptr = &point;
4. 通过指针访问结构体成员
- 使用箭头运算符(->)来访问结构体成员:
//pointer->memberName
printf("X coordinate: %d\n", ptr->x);
printf("Y coordinate: %d\n", ptr->y);
使用(*)和(.)来访问结构体成员:
//(*pointer).memberName
printf("X coordinate: %d\n", (*ptr).x);
printf("Y coordinate: %d\n", (*ptr).y);
注意:. 的优先级高于*,(pointer)两边的括号不能少。如果去掉括号写作pointer.memberName,那么就等效于*(pointer.memberName),这样意义就完全不对了。
箭头运算符(->)
在C语言中,箭头运算符(->)用于通过结构体指针访问结构体的成员。当你有一个指向结构体的指针时,可以使用箭头运算符来访问该结构体的任何成员。这个运算符是由减号(-)和大于号(>)组合而成的。
下面是箭头运算符的详细讲解。
箭头运算符的使用: 假设你有一个结构体Point和一个指向Point的指针ptr:
struct Point
{
int x;
int y;
};
struct Point *ptr;
如果你想通过指针ptr来访问Point结构体中的x和y成员,你应该这样做:
ptr->x = 10;
ptr->y = 20;
这里,ptr->x和ptr->y分别访问了指针ptr所指向的结构体中的x和y成员。
箭头运算符与点运算符的区别:
• 点运算符(.)用于直接通过结构体变量访问其成员。
• 箭头运算符(->)用于通过指向结构体的指针访问结构体的成员。
例如,如果你有一个结构体变量point和一个指向结构体的指针ptr:
struct Point point;
struct Point *ptr = &point;
你可以使用点运算符来访问point的成员:
point.x = 10;
point.y = 20;
相对地,你可以使用箭头运算符来通过ptr访问相同的成员:
ptr->x = 10;
ptr->y = 20;
箭头运算符的优先级: 箭头运算符的优先级非常高,仅次于点运算符。这意味着在表达式中,箭头运算符会在大多数其他运算符之前被计算。
5. 结构体指针与函数
结构体指针可以作为函数参数传递,这样可以避免复制整个结构体:
void printPoint(struct Point *p)
{
printf("X coordinate: %d\n", p->x);
printf("Y coordinate: %d\n", p->y);
}
6. 动态分配结构体
使用malloc为结构体动态分配内存,并使用指针来访问:
ptr = (struct Point *)malloc(sizeof(struct Point));
if (ptr != NULL)
{
ptr->x = 10;
ptr->y = 20;
}
内存分配部分会在内存那节详细讲解,记得使用free来释放动态分配的内存。
五、结构体嵌套
在C语言中,结构体可以嵌套其他结构体,这是通过在一个结构体中定义另一个结构体类型的成员来实现的。这种方式可以帮助你创建更复杂的数据结构,例如,表示一个公司的员工和部门的关系。下面是一个如何在结构体中嵌套其他结构体的例子:
首先,定义一个表示日期的结构体:
struct Date
{
int year;
int month;
int day;
};
然后,定义一个表示个人信息的结构体,其中包含Date结构体作为成员:
struct Person
{
char name[50];
struct Date birthday; // 嵌套结构体
float height;
float weight;
};
在这个例子中,Person结构体有一个名为birthday的成员,它的类型是之前定义的Date结构体。
初始化嵌套结构体: 当创建一个Person类型的变量时,可以这样初始化嵌套的Date结构体:
struct Person person1 = {
"张三",
{1990, 1, 1}, // 初始化嵌套的Date结构体
170.5,
65.2
};
访问嵌套结构体成员:
要访问嵌套结构体的成员,可以使用两个点运算符:
printf("出生日期: %d-%d-%d\n", person1.birthday.year, person1.birthday.month, person1.birthday.day);
参考资料:C语言中文网
C primer plus(第六版)