【C语言进阶篇】看完这篇结构体文章,我向数据结构又进了一大步!(结构体进阶详解)(下)

简介: 【C语言进阶篇】看完这篇结构体文章,我向数据结构又进了一大步!(结构体进阶详解)(下)

3.结构体变量的定义和初始化

3.1 用标签名定义和初始化

这样的话我们可以直接在结构体后面直接定义变量,或者在需要定义的地方使用标签名定义结构体变量。

  • 在声明结构体是创建的结构体变量是 全局变量
  • 在大括号里面创建的结构体是 局部变量

📚 代码演示:

struct Point
{
  int x;
  int y;
}p1; //声明类型的同时定义变量p1
//全局变量
int main()
{
  struct Point p2;//直接使用标签名定义
  //局部变量
  return 0;
}

而初始化的话也非常简单和数组是差不多的每个成员赋值用大括号扩起来,单引号隔开就好了!

  • 大括号括起来,后面加引号
  • 每个成员逗号隔开

📚 代码演示:

struct Point
{
  int x;
  int y;
}p1 = { 2, 1 };//创建时直接赋值
int main()
{
  struct Point p2 = {12,13};//直接使用标签名定义
              //然后进行赋值     
  return 0;
}

3.1.1 如何不按顺序初始化

有人说,那么我不想按结构体成员顺序赋值怎么办呢?

  • 其实只需要用 点操作符 (.) 找到成员然后再赋值就可以了
#include <stdio.h>
struct Stu
{
  char name[20];//姓名
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
}p1 = { .id="20202356",.age = 18, .name = "lisi",.sex = "nan"};
int main()
{
  printf("姓名\t年龄\t性别\t学号\n");
  printf("%s\t %d\t%s\t%s\t", 
                p1.name,
                p1.age, 
                p1.sex, 
                p1.id);
  return 0;
}

📑 代码结果:

3.2 typedef 的定义和初始化

typedef重命名的结构体类型,只是定义与前面不一样,其他部分都是一样的!

  • 但是重命名了,在声明后面就不能再创建我们的结构体变量了
  • 因为typedef 的定义结构体后面默认跟的是重命名的类型名。

📚 代码演示:

#include <stdio.h>
typedef struct Stu
{
  char name[20];//姓名
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
}Stu;
//全局变量
Stu p1 = { .id = "20202356",.age = 18, .name = "lisi",.sex = "nan" };
int main()
{
  printf("姓名\t年龄\t性别\t学号\n");
  //局部变量
  Stu p2 = { .id = "202329",.age = 20, .name = "zhangsan",.sex = "nan" };
  printf("%-10s\t %d\t %s\t %s\n", p1.name, p1.age, p1.sex, p1.id);
  printf("%-10s\t %d\t %s\t %s\t", p2.name, p2.age, p2.sex, p2.id);
  return 0;
}

📑 代码结果:

3.结构体嵌套的定义和初始化

结构体包含结构体的初始化,既然我们知道结构体是如何初始化的,那么结构体包含也就很明确了。

  • 既然你也是结构体那么我,用大括号在包含一下
  • 给你赋值不就完了,大括号套大括号
#include <stdio.h>
struct Stu
{
  char a;
  int num;  
};
struct S
{
  int arr[10];
  struct Stu sn;
  double d;
};
int main()
{
  struct S s = {{1,2,3,4,5,6,7,8,9,10},
        {"l",99},
        3.14};
  return 0;
}

3.1 自引用的定义和初始化

前面结构体包含结构体的的初始化我们都知道了,那么自引用和它基本一样,自引用引用的是相同类型的地址所以我们可以先赋值为 NULL 空指针就好!

📚 代码演示:

#include <stdio.h>
struct Point
{
  int x;
  int y;
};
struct Node
{
  int data;
  struct Point p;
  struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
int main()
{
  struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化
  printf("%d\t%d\t%d\t0x%p", 
          n2.data, 
          n2.p.x, 
          n2.p.y, 
          n2.next);
  return 0;
}

📑 代码结果:

4. 结构体该如何传参

struct S
{
 int data[1000];
 int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
 printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
 printf("%d\n", ps->num);
}
int main()
{
 print1(s);  //传结构体
 print2(&s); //传地址
 return 0;
}

上面的 print1 和 print2 函数哪个好些?答案是:首选print2函数。因为:

  • 函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
  • 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
  • 所以结构体传参的时候一定要传地址!

🔥 由于函数在传递参数时,如果我们传的是实参,那么形参将是实参的一份临时拷贝。如果我们传过去的结构体很大,那么形参也要开辟相同大小的空间就会照成空间的浪费!

4.1 错误的结构体传参

我们来看一下下面这个例子大家就明白了,这里我们在 main() 主函数里面创建了结构体变量想通过 test() 函数进行赋值。

  • 但是我们是 传值调用 ,所以改变形参并不会改变实参。
  • 形参只是实参的一份临时拷贝
#include <stdio.h>
typedef struct Point
{
  int x;
  int y;
}Pt;
void test(Pt pf)
{
  pf.x = 2;
  pf.y = 3;
}
int main()
{
  Pt p2 = {0};
  test(p2);
  printf("%d %d", p2.x, p2.y);
  return 0;
}

📑 代码结果:

4.2 正确的结构体传参

所以我们在结构体传参的时候一定要使用 传址调用 ,这样才能改变我们的结构体!

  • 如果只想使用里面的值,而不想改变结构体变量
  • 只许需要加上const修饰一下指针,让指针所指向的值不能发生改变这样就可以了!

📚 代码演示:

#include <stdio.h>
typedef struct Point
{
  int x;
  int y;
}Pt;
void test(Pt* x)
{
  x->x = 10;
  x->y = 5;
}
void test1(const Pt* x)
{
  printf("%d %d", ps.x, ps.y);
}
int main()
{
  Pt ps = { 0 };
  test(&ps);
  test1(&ps);
  printf("%d %d", ps.x, ps.y);
  return 0;
}

📑 代码结果:

📝全篇总结

✅ 归纳:

好了以上就是关于结构体进阶篇的全部内容了,希望各位铁铁们看完也都会了呢!

  结构体的自引用

  自引用的例子链表

  结构体嵌套如何定义

  结构体传参的注意事项

☁️ 把本章的内容全部掌握,铁汁们就又向下一部分知识数据结构前进了一大步呢!

看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖

拜托拜托这个真的很重要!

你们的点赞就是博主更新最大的动力!

有问题可以评论或者私信呢秒回哦。


目录
相关文章
|
11月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
412 1
|
11月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
146 4
|
11月前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
122 4
|
11月前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
114 4
|
11月前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
142 4
|
8月前
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
9月前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
10月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
703 14
|
10月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
470 10
|
11月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
886 13