C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)一

简介: C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)一

简单介绍

结构体是一些值的集合,结构的每个成员可以是不同的类型。

例如描述书是比较复杂的,包括书名、作者、出版社、定价、书号等。

我们可以创建一个书的类型,用来描述书,存储书的各项数据。将这若干项数据集合起来就是一个结构体


声明与定义

声明后定义

注:在声明结构体类型时,最后的分号不能漏掉

声明时定义

特殊的声明

不完全声明

对匿名结构体类型进行探讨:

struct//匿名结构体类型
{
    char c;
    int i;
    char ch;
    double d;
}n;
struct
{
    char c;
    int i;
    char ch;
    double d;
}*p;
int main()
{
    p = &n; //error
    return 0;
}

以上两个匿名结构体类型虽然里面的成员是完全相同的,但是编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。


注:匿名结构体只能使用一次,不能再用于创建结构体变量。


结构自引用

创建一个情景:我们创建一个存储图书馆各项数据的结构体类型,其中包括图书、内饰等等。而图书中又存储着有关图书的各项数据,这时就可以用到结构的自引用了。例如:

struct book //图书
{
    char type[10];
    char name[20];
    int price;
    char number[30];
};
struct upholstery //内饰
{
    char WallColor[10];
    char CeilingMolding[30];
    int LampSwitch;
};
struct library
{
    struct book b;
    struct upholstery u;
    double d;
};

对结构自引用进行探讨

struct Node
{
    int n;
    struct Node n;
};

当我们用struct Node来创建变量时,会发现这个变量的大小是无法计算的,进入了一个死递归的状态。

因此,这种写法是非法的。

正确的写法

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

正确的写法

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

不可以包含同类型的变量,可以包含同类型的指针变量。

与链表有关,在数据结构中会学到。链表的结点包罗两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

另一种错误写法,将匿名结构体与自引用结合起来

struct
{
    int n;
    struct* next;
 
};

很显然,这种写法是非法的。那么此时想尝试用typedef修改一下,可不可行呢?

typedef struct
{
    int n;
    Node* next;
 
}Node;

来将这段代码捋一捋:将匿名结构体自定义为Node,那么先要让匿名结构体定义。而匿名结构体定义时要建立指针变量Node* next之后才算完成;但此时自定义还没有把struct定义为Node,故而以Node为类型的next变量不能成功建立。从而我们得知这段代码也是错误的,正确写法应该先自定义完成再定义结构体:

typedef struct Node
{
    int n;
    Node* next;
 
}Node;

结构体的初始化

struct A
{
    int i;
    char c;
}a;
struct B
{
    int n;
    char e;
    struct A a;
}b;
int main()
{
    struct A a = { 32,'a' };//直接初始化
    printf("%d\n%c\n", a.i, a.c);
    b.n = 64;
    b.e = 'b';
    //利用操作符“.”初始化
    b.a.i = 128;
    b.a.c = 'c';
    //结构自引用(结构嵌套)的初始化
    printf("%d  %c  %d  %c", b.n, b.e, b.a.i,b.a.c);
    return 0;
}


利用操作符“->”进行初始化

struct book
{
    int price;
    char name[20];
}b1,*p;
int main()
{
    p = &b1;
    p->price = 64;
    printf("%d\n", p->price);
    return 0;
}



C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)二:https://developer.aliyun.com/article/1530420

目录
相关文章
|
1月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
54 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
1月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
155 14
|
1月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
184 10
|
2月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
63 6
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
194 13
|
2月前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
73 1
|
2月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
4天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
39 23