参考摘抄学习来自:
- C 结构体
- C语言必学知识点 "结构体"详细解析!
- C 语言之结构体最全面总结
- C typedef
文章目录
- 1 定义
- 2 初始化
- 3 结构体大小的计算
- 4 访问结构成员
- 5 结构作为函数参数
- 6 指向结构的指针
- 7 结构体数组
- 8 动态申请结构体
1 定义
它允许您存储不同类型的数据项。
结构体中的数据成员可以是基本数据类型(如 int、float、char 等),也可以是其他结构体类型、指针类型等。
struct tag {
member-list
member-list
member-list
...
} variable-list ;
tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f;,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。以下为实例:
eg
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct
{
int a;
char b;
double c;
} s1;
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
int a;
char b;
double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;
//也可以用typedef创建新类型
typedef struct
{
int a;
char b;
double c;
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;
结构体嵌套
//此结构体的声明包含了其他的结构体
struct COMPLEX
{
char string[100];
struct SIMPLE a;
};
//此结构体的声明包含了指向自己类型的指针
struct NODE
{
char string[100];
struct NODE *next_node;
};
C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE:
typedef unsigned char BYTE;
在这个类型定义之后,标识符 BYTE 可作为类型 unsigned char 的缩写,例如:
BYTE b1, b2;
按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但您也可以使用小写字母,如下:
typedef unsigned char byte;
您也可以使用 typedef 来为用户自定义的数据类型取一个新的名字。例如,您可以对结构体使用 typedef 来定义一个新的数据类型名字,然后使用这个新的数据类型来直接定义结构变量
2 初始化
#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);
}
output
title : C 语言
author: RUNOOB
subject: 编程语言
book_id: 123456
3 结构体大小的计算
#include <stdio.h>
struct Person {
char name[20];
int age;
float height;
};
int main() {
struct Person person;
printf("name size: %zu\n", sizeof(person.name));
printf("age size: %zu\n", sizeof(person.age));
printf("height size: %zu\n", sizeof(person.height));
printf("结构体 Person 大小为: %zu 字节\n", sizeof(person));
return 0;
}
output
name size: 20
age size: 4
height size: 4
结构体 Person 大小为: 28 字节
再看看下面这个例子
#include <stdio.h>
int main(void)
{
struct A
{
char a;
int b;
char c;
} a = {'a', 10, 'o'};
printf("size of a = %d\n", sizeof(a.a));
printf("size of b = %d\n", sizeof(a.b));
printf("size of c = %d\n", sizeof(a.c));
printf("size of a = %d\n", sizeof(a));
return 0;
}
output
size of a = 1
size of b = 4
size of c = 1
size of a = 12
#include <stdio.h>
int main(void)
{
struct A
{
char a;
char c;
int b;
} a = {'a', 'o', 10};
printf("size of a = %d\n", sizeof(a.a));
printf("size of c = %d\n", sizeof(a.c));
printf("size of b = %d\n", sizeof(a.b));
printf("size of a = %d\n", sizeof(a));
return 0;
}
output
size of a = 1
size of c = 1
size of b = 4
size of a = 8
存在内存对齐现象
在C语言中,内存对齐(Memory Alignment)是一个重要的概念,它指的是数据在内存中按照一定的规则进行排列,以提高内存的访问效率。不同的硬件平台对内存访问有不同的要求,如果数据没有按照这些要求来对齐,可能会导致性能下降,甚至在某些平台上引发硬件异常。
为什么要内存对齐?
- 性能优化:现代计算机体系结构通常通过内存对齐来提高内存访问速度。这是因为硬件可能设计为以特定的字节边界(如4字节、8字节等)来高效地访问内存。
- 平台兼容性:不同的硬件平台对内存对齐的要求可能不同。遵循内存对齐的规则可以确保程序在不同平台上的兼容性。
内存对齐的规则
- 自然对齐:数据的存储起始地址是数据本身大小的整数倍。例如,int类型(假设为4字节)的变量应该存储在4的倍数地址上。
- 结构体对齐:结构体中的成员变量和整个结构体本身都会受到对齐规则的影响。结构体成员的对齐通常遵循其自然对齐规则,而结构体本身的对齐则可能由编译器或编译器的特定选项决定。
- 编译器指令:大多数编译器提供了控制对齐的指令或选项,如GCC的
__attribute__((aligned(n)))
和MSVC的#pragma pack(n)
。
4 访问结构成员
成员访问运算符(.)
#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; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* 输出 Book1 信息 */
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);
/* 输出 Book2 信息 */
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;
}
output
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
#include <stdio.h>
#include <string.h>
struct Person {
int age;
float height;
};
struct Birthday{
char name[20];
struct Person person;
};
int main() {
struct Birthday birthday;
strcpy(birthday.name, "Bryant");
birthday.person.age = 18;
birthday.person.height = 171;
printf("name:%s, age:%d, height:%f\n", birthday.name, birthday.person.age, birthday.person.height);
return 0;
}
output
name:Bryant, age:18, height:171.000000
5 结构作为函数参数
#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; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* 输出 Book1 信息 */
printBook( Book1 );
/* 输出 Book2 信息 */
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);
}
output
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
#include <stdio.h>
struct Student{
int age;
};
void test(struct Student stu){
printf("test 修改前的值:%d\n", stu.age);
stu.age = 10;
printf("test 修改后的值:%d\n", stu.age);
}
int main()
{
struct Student student;
student.age = 30;
printf("main 修改前的值:%d\n", student.age);
test(student);
printf("main 修改后的值:%d\n", student.age);
return 0;
}
output
main 修改前的值:30
test 修改前的值:30
test 修改后的值:10
main 修改后的值:30
可以看到仅改变了形参,实际值没有改变,传结构体指针就没问题(见下节)
#include <stdio.h>
struct Student{
int age;
};
void test(struct Student* stu){
printf("test 修改前的值:%d\n", stu->age);
stu->age = 10;
printf("test 修改后的值:%d\n", stu->age);
}
int main()
{
struct Student student;
student.age = 30;
printf("main 修改前的值:%d\n", student.age);
test(&student);
printf("main 修改后的值:%d\n", student.age);
return 0;
}
output
main 修改前的值:30
test 修改前的值:30
test 修改后的值:10
main 修改后的值:10
6 指向结构的指针
#include <stdio.h>
#include <string.h>
struct Student{
char name[20];
int age;
};
int main()
{
struct Student student;
student.age = 20;
strcpy(student.name, "Bryant");
printf("name: %s, age: %d\n", student.name, student.age);
struct Student *p = &student;
printf("name: %s, age: %d\n", p->name, p->age);
printf("name: %s, age: %d\n", (*p).name, (*p).age);
return 0;
}
output
name: Bryant, age: 20
name: Bryant, age: 20
name: Bryant, age: 20
#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; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* 通过传 Book1 的地址来输出 Book1 信息 */
printBook( &Book1 );
/* 通过传 Book2 的地址来输出 Book2 信息 */
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);
}
output
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
7 结构体数组
#include <stdio.h>
#include <string.h>
struct Person {
char name[20];
int age;
float height;
}person[3]={{"Bryant", 19, 178}, {"Chole", 18, 167}};
int main() {
for(int i=0; i<2; i++)
printf("name:%s, age:%d, height:%f\n", person[i].name,
person[i].age, person[i].height);
return 0;
}
output
name:Bryant, age:19, height:178.000000
name:Chole, age:18, height:167.000000
8 动态申请结构体
结构体也可以在堆里面动态申请
#include <stdio.h>
...
int main(void)
{
struct Info *i1;
struct Info *i2;
i1 = (struct Info *)malloc(sizeof(struct Info));
i2 = (struct Info *)malloc(sizeof(struct Info));
if (i1 == NULL || i2 == NULL)
{
printf("内存分配失败!\n");
exit(1);
}
printf("请录入第一个同学的信息...\n");
getInput(i1);
putchar('\n');
printf("请录入第二个学生的信息...\n");
getInput(i2);
printf("\n录入完毕,现在开始打印...\n\n");
printf("打印第一个学生的信息...\n");
printInfo(i1);
putchar('\n');
printf("打印第二个学生的信息...\n");
printInfo(i2);
free(i1);
free(i2);
return 0;
}