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

目录
相关文章
|
8月前
|
存储 人工智能 搜索推荐
一种专为AI代理设计的内存层,能够在交互过程中记忆、学习和进化
Mem0 是专为 AI 代理设计的内存层,支持记忆、学习与进化。提供多种记忆类型,可快速集成,适用于开源与托管场景,助力 AI 代理高效交互与成长。
793 123
一种专为AI代理设计的内存层,能够在交互过程中记忆、学习和进化
|
10月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
349 26
|
10月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
452 15
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
792 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
1248 14
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
831 10
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
594 6
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
629 1
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
871 23
|
8月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
1468 0