C语言——自定义类型结构体_学习笔记

这篇具有很好参考价值的文章主要介绍了C语言——自定义类型结构体_学习笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

结构体的基本概念

结构体是一种用户自定义的数据类型,可以包含多个不同类型的变量。通过使用结构体,我们可以将相关联的数据组织在一起,便于管理和使用。

结构体的声明

正常的结构体声明

在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型的一类。
结构体可以包含多个不同类型的数据成员,例如:int、float、char等。

结构体的声明方式如下:

struct 结构体名 {
    类型1 数据成员1;
    类型2 数据成员2;
    ...
    类型n 数据成员n;
};

例如:

struct student {
    int id;
    char name[50];
    int age;
};                  //注意,结构体定义后面的分号不要忘了

以上属于是正常的结构体声明↑↑↑↑↑↑↑↑↑↑↑↑

匿名结构体声明

既然有正常的,那就有特殊的结构体声明了↓↓↓↓↓↓↓↓↓↓↓↓↓↓
在声明结构体的时候,可以不完全的声明。(匿名结构体类型)
如下:

//匿名结构体类型
struct
{
	int a;
	char b;
	float c;
}x;
struct 
{
	int a;
	char b;
	float c;
}*p;
  • p是结构体指针,这里可以看到,上下两个结构体的成员内容都是一模一样的,
  • 能不能实现 p = &x 呢?
  • 答案是不能,编译器会把上面的两个声明当成完全不同的结构体类型,所以p不能放x的地址!!!

上面两个结构体在声明的时候省略掉了结构体标签,这样声明也是可以的,但是!匿名的结构体类型,只能在创建的时候定义结构体变量,如果没有对结构体类型重命名的话,基本上只能使用一次。

typedef 结构体起别名

可以使用typedef关键字为结构体起别名,这样一些名字很长的结构体名字就可以简化,这样当我们需要频繁创建结构体变量的时候就比较方便。
例如:

#include <stdio.h>

struct Chinese_Student {
    char name[50];
    int age;
    float score;
};

typedef struct Chinese_Student Student; // 为结构体起别名Student

int main() {
    Student stu = {"Tom", 20, 88.5}; // 创建并初始化结构体变量,其实就等价于Chinese_Student stu = {"Tom", 20, 88.5};
    printf("Name: %s\n", stu.name); // 访问结构体变量的成员
    printf("Age: %d\n", stu.age);
    printf("Score: %.1f\n", stu.score);
    return 0;
}

结构体的自引用

在结构体中包含一个类型为结构体本身的成员可以吗?
比如下面这段代码:

struct Node
{
	int data;
	struct Node next;
};                      //error报错

这段代码是会报错的,因为结构体中包含同一个类型的结构体作为成员,这样结构体变量的大小就会无穷的大,是不合理的。

正确的结构体自引用方式,使用结构体指针

struct Node
{
	int data;
	struct Node* next;
};  

结构体变量的创建和初始化

对于结构体变量的创建和初始化,用示例代码来进行说明:

#include <stdio.h>

//创建结构体变量前,要先对结构体进行声明↓↓↓↓↓↓
struct student {
    char name[50];  //这里声明一个student类型的结构体,有三个成员
    int age;        //分别是字符类型姓名,整型类型年龄,浮点型类型分数
    float score;
};

int main() {
   
    // 可以在创建结构体变量的时候同时按声明中的结构体成员顺序对结构体变量进行初始化操作↓↓
    struct student stu1 = {"Tom", 20, 88.5}; 
    
    //也可以用成员访问操作符,不按照成员顺序对结构体成员进行初始化操作↓↓↓↓↓
    struct student stu2 = {.age=18, .name="weil", .score=99.9}; 
    
	// 访问结构体变量的成员↓↓↓↓↓↓↓
    printf("Name: %s\n", stu2.name); 
    printf("Age: %d\n", stu2.age);
    printf("Score: %.1f\n", stu2.score);
    return 0;
}

结构体内存对齐

对于结构体的大小,我们可以用sizeof 运算符进行计算
如下:

struct S1
{
	char c1;       //1字节
	int i;         //4字节
	char c2;       //1字节
};
int main()
{
	printf("%zd\n", sizeof(struct S1));
	return 0;
}

运行结果为
C语言——自定义类型结构体_学习笔记,C语言学习笔记,c语言,学习,笔记
上面代码的结构体占的字节数大小为什么会是12个字节呢?

这就涉及到结构体内存对齐的知识点了↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

结构体内存对齐规定

  1. 结构体的第一个成员对齐到相对结构体变量起始位置偏移量为0的地址处
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数=编译器默认的一个对齐数与该成员变量大小的较小值。
    VS中默认的值为8
    Linux中没有默认对齐数,对齐数就是成员自身的大小
  3. 结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

为什么存在内存对齐

大部分的参考资料都是这样说的:

1.平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

假设一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法。

举例解释

struct S1
{
    char c1;
    char c2;
    int i;
};
struct S2
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%zd\n", sizeof(struct S1));
	printf("%zd\n", sizeof(struct S2));
	return 0;
}

以上代码运行结果(VS 2022):
C语言——自定义类型结构体_学习笔记,C语言学习笔记,c语言,学习,笔记
结构体中的成员类型相同,不同的排列顺序也会影响结构体变量的大小,这就是结构体内存对齐的奥妙,接下来画内存布局图来进行解释:
C语言——自定义类型结构体_学习笔记,C语言学习笔记,c语言,学习,笔记

那在设计结构体的时候,我们既要满足对齐,又要节省空间,就要让占用空间小的成员尽量集中在一起

结构体数组

↓↓↓↓↓↓↓↓↓↓↓↓↓创建结构体数组 & 遍历访问结构体数组↓↓↓↓↓↓↓↓↓↓↓↓↓
代码示例如下:

#include <stdio.h>

// 定义一个结构体类型
struct Student {
    char name[20];
    int age;
    float score;
};

int main() {
    // 创建结构体数组并初始化
    struct Student students[] = {
        {"Tom", 20, 88.5},
        {"Jack", 21, 92.0},
        {"Alice", 19, 95.5}
    };

    // 遍历访问打印结构体数组中的所有内容
    int len = sizeof(students) / sizeof(struct Student);  // 计算数组长度
    for (int i = 0; i < len; i++) {
        printf("Name: %s\n", students[i].name);
        printf("Age: %d\n", students[i].age);
        printf("Score: %.1f\n", students[i].score);
    }

    return 0;
}

在这个示例中,我们首先定义了一个名为Student的结构体类型,包含三个成员变量:name、age和score。然后,我们在main函数中创建了一个Student类型的结构体数组students,并初始化其中的元素。接着,我们使用一个for循环遍历访问数组中的每个元素,并使用printf函数打印出每个学生的姓名、年龄和分数。

在访问结构体数组元素时,我们使用了结构体变量名加上索引的方式来访问,例如students[i].name表示访问第i个元素的name成员变量。

结构体指针

↓↓↓↓↓↓↓↓↓↓↓↓↓结构体指针的创建 & 初始化 & 成员访问↓↓↓↓↓↓↓↓↓↓↓↓↓

#include <stdio.h>

// 定义一个结构体类型
struct Student {
    char name[20];
    int age;
    float score;
};

int main() {
    // 创建结构体变量并初始化
    struct Student stu1 = {"Tom", 20, 88.5};
    struct Student stu2 = {"Jack", 21, 92.0};
    struct Student stu3 = {"Alice", 19, 95.5};

    // 创建结构体指针变量
    struct Student *stuPtr;

    // 将结构体变量的地址赋给结构体指针变量
    stuPtr = &stu1;

    // 遍历打印结构体指针中的内容
    printf("Name: %s\n", stuPtr->name);
    printf("Age: %d\n", stuPtr->age);
    printf("Score: %.1f\n", stuPtr->score);

    // 将结构体指针变量指向下一个结构体变量
    stuPtr = &stu2;

    // 遍历打印结构体指针中的内容
    printf("Name: %s\n", stuPtr->name);
    printf("Age: %d\n", stuPtr->age);
    printf("Score: %.1f\n", stuPtr->score);

    // 将结构体指针变量指向下一个结构体变量
    stuPtr = &stu3;

    // 遍历打印结构体指针中的内容
    printf("Name: %s\n", stuPtr->name);
    printf("Age: %d\n", stuPtr->age);
    printf("Score: %.1f\n", stuPtr->score);

    return 0;
}

在这个示例中,我们首先定义了一个Student结构体类型,包含了学生的姓名、年龄和分数。在main函数中,我们创建了三个Student类型的结构体变量,并分别初始化它们。

然后,我们创建了一个Student类型的指针变量stuPtr,用于指向这些结构体变量。我们将第一个结构体变量的地址赋给了stuPtr,并使用->运算符通过指针访问结构体中的数据,并打印出学生的信息。接着,我们将指针变量指向下一个结构体变量,重复上述操作,直到遍历完所有的结构体变量。文章来源地址https://www.toymoban.com/news/detail-726525.html

到了这里,关于C语言——自定义类型结构体_学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构(c++语言版) 邓俊辉 第五章:二叉树学习笔记

    5.1二叉树及其表示         树是由节点和边组成的。 1.有根树         树是由顶点(vertex)和边(edge)组成。树的每个顶点也叫节点(node)。 2.深度与层次         由树的连通性,每一节点与根都有一条路径相连:根据树的无环性,由根通往每个节点的路径必然唯一。  

    2024年02月13日
    浏览(46)
  • C语言学习:8、深入数据类型

    C语言中,如果需要用的整数大于int类型的最大值了怎么办? 我们知道int能表示的最大数是2147483647,最小的数是-2147483648,为什么? 因为字32位系统中,寄存器是32位的,寄存器中最高位表示符号位,0表示整数,1表示负数; 所以32位系统中int的最大值可以表示为0111 1111 1111

    2024年02月09日
    浏览(37)
  • 《综合与Design_Compiler》学习笔记——第一章综合综述 第二章verilog语言结构到门级的映射 第三章 使用DC进行综合

    2023.6.25 2023.6.27 和之前学的芯动力mooc中很多内容相似,这篇整理的逻辑更好些 将RTL代码转换到基于工艺库的门级网表。一般分为如下三个步骤。 (1)逻辑级综合 设计被描述成 布尔等式 的形式,触发器、锁存器这样的基本单元采用元件例化(instantiate)的方式表达出来,下面是

    2024年02月12日
    浏览(56)
  • C语言入门教程,C语言学习教程(第三部分:C语言变量和数据类型)二

    前面我们多次提到了字符串,字符串是多个字符的集合,它们由 \\\" \\\" 包围,例如 \\\"http://c.biancheng.net\\\" 、 \\\"C语言中文网\\\" 。字符串中的字符在内存中按照次序、紧挨着排列,整个字符串占用一块连续的内存。 当然,字符串也可以只包含一个字符,例如 \\\"A\\\" 、 \\\"6\\\" ;不过为了操作方

    2024年01月17日
    浏览(51)
  • 【JAVA】数据类型与变量(主要学习与c语言不同之处)

    ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:橘橙黄又青-CSDN博客 目标: 1. 字面常量 2. 数据类型 3. 变量 在上节课 HelloWorld 程序中, System.Out.println(\\\"Hello World\\\") ; 语句,不论程序何时运行,输出的都是 Hello World,其实 \\\"Hello Wo

    2024年03月28日
    浏览(48)
  • 【go语言学习笔记】05 Go 语言实战

    在做项目开发的时候,要善于借助已经有的轮子,让自己的开发更有效率,也更容易实现。 1. RESTful API 定义 RESTful API 是一套规范,它可以规范如何对服务器上的资源进行操作。和 RESTful API 和密不可分的是 HTTP Method。 1.1 HTTP Method HTTP Method最常见的就是POST和GET,其实最早在

    2024年02月13日
    浏览(45)
  • Go语言学习笔记

    注:安装教程 注:上一篇笔记 注:下一篇笔记 2.6、流程控制 2.6.1、条件语句 2.6.2、选择语句 2.6.3、循环语句 2.6.4、跳转语句 goto语句跳转到本函数内的某个标签 2.7、函数 2.7.1、函数定义 函数构成代码执行的逻辑结构。函数的基本组成为:func、函数名、参数列表、返回值

    2024年02月06日
    浏览(48)
  • 6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理

    1、Go版本 2、汇编基础 推荐阅读:GO汇编语言简介 推荐阅读:A Quick Guide to Go\\\'s Assembler - The Go Programming Language 精简指令集 数据传输: MOV/LEA 跳转指令: CMP/TEST/JMP/JCC 栈指令: PUSH/POP 函数调用指令: CALL/RET 算术指令: ADD/SUB/MUL/DIV 逻辑指令: AND/OR/XOR/NOT 移位指令: SHL/SHR JCC有条件跳转: JE

    2024年02月04日
    浏览(41)
  • go语言学习笔记1

    ​ GoLang是一种静态强类型、编译型、并发型,并具有 垃圾回收 功能的编程语言;它可以在不损失应用程序性能的情况下极大的降低代码的复杂性,还可以发挥多核处理器同步多工的优点,并可解决面向对象程序设计的麻烦,并帮助程序设计师处理琐碎但重要的内存管理问题

    2024年02月12日
    浏览(50)
  • Go语言学习笔记(二)

    以下是一些推荐的Go语言学习资源的链接: Go语言教程:https://golang.org/doc/ Go by Example:Go by Example Golang Tutorials:https://golangtutorials.com/ Go语言第一课(慕课网):PHP模糊查询技术案例视频教程-慕课网 Go语言进阶教程(实验楼):极客企业版 Go语言高级编程(GitBook):谁是凶手

    2024年01月20日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包