【C语言】结构体 -- 结构体的声明 -- 定义和初始化 -- 成员的访问 -- 结构体传参

简介: 【C语言】结构体 -- 结构体的声明 -- 定义和初始化 -- 成员的访问 -- 结构体传参

1、结构体的声明

1.1 结构的基础知识

结构是一些值得集合,这些值成为成员变量。结构的每个成员可以是不同类型的变量。

1.2 结构的声明

struct tag//tag结构体名,struct是结构体关键字
{
    member-list;
}variable-list;//这里的分号不可缺少

我们以书来举例:

#include <stdio.h>
struct BOOK
{
  char name[20];
  float price;
}b3,b4,b5;
int main()
{
  struct BOOK b1;
  struct BOOK b2;
  return 0;
}

分析:

这里我们创建了一个结构体类型,struct BOOK 类型。

这里每次定义结构体变量的时候类型太长,我们可以对它进行重命名。

重命名

这里用到一个关键字typedef,我们就对上面的代码进行改写:

#include <stdio.h>
typedef struct BOOK
{
  char name[20];
  float price;
}BOOK;
int main()
{
  BOOK b1;
  BOOK b2;
  return 0;
}

分析:



1.3 结构成员的类型

结构的成员可以是标量、数组、指针,甚至是其他结构体。

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

有了结构体类型,那如何定义变量,其实很简单。

1.4.1 结构体变量的定义

我们来看下面的代码:

struct BOOK
{
  char name[20];
  float price;
}b3;//全局变量
struct BOOK b4;//全局变量
int main()
{
  struct BOOK b1;//局部变量
  struct BOOK b2;//局部变量
  return 0;
}

这里的 b1, b2 是局部变量,b3,b4 是全局变量,全局变量可以在创建结构体的时候就创建。

1.4.2 结构体变量的初始化

我们来看代码:

struct S
{
  char sex[6];
  char name[20];
  int age;
};
int main()
{
  struct S s1 = { "male", "zhangsan", 20 };
  return 0;
}

上面代码是按照结构体成员的顺序来初始化的。我们也可以不按照顺序来初始化。

我们来看代码:

struct S
{
  char sex[6];
  char name[20];
  int age;
};
int main()
{
  struct S s1 = { "male", "zhangsan", 20 };
  struct S s2 = { .name = "wangwu", .sex = "male", .age = 20 };
  printf("%s %s %d\n", s1.sex, s1.name, s1.age);
  printf("%s %s %d\n", s2.sex, s2.name, s2.age);
  return 0;
}

效果展示:


我们不按照顺序初始化的时候是用 .成员名 来赋值的,这样也是可以的。

2、 结构体成员的访问

2.1 结构体变量访问成员

结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。

语法: 结构体变量 . 结构体成员

我们就以上面的代码来看:

struct S
{
  char sex[6];
  char name[20];
  int age;
};
int main()
{
  struct S s1 = { "male", "zhangsan", 20 };
  struct S s2 = { .name = "wangwu", .sex = "male", .age = 20 };
  //结构体变量.结构体成员
  printf("%s %s %d\n", s1.sex, s1.name, s1.age);
  printf("%s %s %d\n", s2.sex, s2.name, s2.age);
  return 0;
}



2.2 结构体指针访问指向变量的成员

有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。

那么如何访问成员。

语法:结构体指针->结构体成员

如下:

struct S
{
  char sex[6];
  char name[20];
  int age;
};
void Print(struct S* p1)
{
  //结构体指针->结构体成员
  printf("%s %s %d\", p1->sex, p1->name, p1->age);
}
int main()
{
  struct S s1 = { "male", "zhangsan", 20 };
  struct S s2 = { .name = "wangwu", .sex = "male", .age = 20 };
  //结构体变量.结构体成员
  printf("%s %s %d\n", s1.sex, s1.name, s1.age);
  printf("%s %s %d\n", s2.sex, s2.name, s2.age);
  Print(&s1);//结构体地址传参
  return 0;
}

3、结构体传参

struct S
{
  int arr[100];
  int n;
};
void Print1(struct S ss)
{
  int i = 0;
  for (i = 0; i < 5; i++)
  {
    printf("%d ", ss.arr[i]);
  }
  printf("\n%d\n", ss.n);
}
int main()
{
  struct S s = { {1,2,3,4,5}, 100 };
  Print1(s);
  return 0;
}

效果展示:

性能分析:


这里的结构体 s 的成员arr的字节是400,结构体整体是大于400的,再加上形参再创建一份,这样浪费空间很严重。因此我们直接将 s 交给Print1 来打印,这样就不会浪费空间的。

因此,我们来实现的第二种方法:

struct S
{
  int arr[100];
  int n;
};
void Print2(struct S* ps)
{
  int i = 0;
  for (i = 0; i < 5; i++)
  {
    printf("%d ", ps->arr[i]);
  }
  printf("\n%d\n", ps->n);
}
int main()
{
  struct S s = { {1,2,3,4,5}, 100 };
  Print2(&s);
  return 0;
}

效果展示:

这里两次的打印结果是一样的,传参传的是指针,最多就 8 个字节(x32平台是 4 字节,x64平台是 8 字节),这样就不会额外开辟空间。


Q:在实现打印的时候,上面的 Print1 和 Print2 函数选择哪个好些?


答案是:首选 Print2 函数。


函数传参的时候,参数是需要压栈的。


如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。


结论:结构体传参的时候,要穿结构体的地址。


目录
打赏
0
0
0
0
9
分享
相关文章
C语言结合AWTK开发HTTP接口访问界面
这样,我们就实现了在C语言中使用libcurl和AWTK来访问HTTP接口并在界面上显示结果。这只是一个基础的示例,你可以根据需要添加更多的功能和优化。例如,你可以添加错误处理机制、支持更多HTTP方法(如POST、PUT等)、优化用户界面等。
274 82
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
515 14
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
378 10
|
7月前
|
【C语言】全局搜索变量却找不到定义?原来是因为宏!
使用条件编译和 `extern` 来管理全局变量的定义和声明是一种有效的技术,但应谨慎使用。在可能的情况下,应该优先考虑使用局部变量、函数参数和返回值、静态变量或者更高级的封装技术(如结构体和类)来减少全局变量的使用。
98 5
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
185 6
|
7月前
|
【C语言】宏定义在 a.c 中定义,如何在 b.c 中使用?
通过将宏定义放在头文件 `macros.h` 中,并在多个源文件中包含该头文件,我们能够在多个文件中共享宏定义。这种方法不仅提高了代码的重用性和一致性,还简化了维护和管理工作。本文通过具体示例展示了如何定义和使用宏定义,帮助读者更好地理解和应用宏定义的机制。
269 2
C语言在实现高效算法方面的特点与优势,包括高效性、灵活性、可移植性和底层访问能力
本文探讨了C语言在实现高效算法方面的特点与优势,包括高效性、灵活性、可移植性和底层访问能力。文章还分析了数据结构的选择与优化、算法设计的优化策略、内存管理和代码优化技巧,并通过实际案例展示了C语言在排序和图遍历算法中的高效实现。
203 2
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
305 23
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
97 1
一文彻底搞清楚C语言的函数
|
6月前
|
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
264 15
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问