【C】Structure

news2025/2/25 0:36:16

在这里插入图片描述

参考摘抄学习来自:

  • C 结构体
  • C语言必学知识点 "结构体"详细解析!
  • C 语言之结构体最全面总结
  • C typedef

文章目录

  • 1 定义
  • 2 初始化
  • 3 结构体大小的计算
  • 4 访问结构成员
  • 5 结构作为函数参数
  • 6 指向结构的指针
  • 7 结构体数组
  • 8 动态申请结构体

1 定义

它允许您存储不同类型的数据项。

结构体中的数据成员可以是基本数据类型(如 int、float、char 等),也可以是其他结构体类型、指针类型等。

struct tag { 
    member-list
    member-list 
    member-list  
    ...
} variable-list ;

tag 是结构体标签

member-list 是标准的变量定义,比如 int i; 或者 float f;,或者其他有效的变量定义。

variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。

在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。以下为实例:

eg

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct 
{
    int a;
    char b;
    double c;
} s1;

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;

//也可以用typedef创建新类型
typedef struct
{
    int a;
    char b;
    double c; 
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;

结构体嵌套

//此结构体的声明包含了其他的结构体
struct COMPLEX
{
    char string[100];
    struct SIMPLE a;
};

//此结构体的声明包含了指向自己类型的指针
struct NODE
{
    char string[100];
    struct NODE *next_node;
};

C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE:

typedef unsigned char BYTE;

在这个类型定义之后,标识符 BYTE 可作为类型 unsigned char 的缩写,例如:

BYTE  b1, b2;

按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但您也可以使用小写字母,如下:

typedef unsigned char byte;

您也可以使用 typedef 来为用户自定义的数据类型取一个新的名字。例如,您可以对结构体使用 typedef 来定义一个新的数据类型名字,然后使用这个新的数据类型来直接定义结构变量

2 初始化

#include <stdio.h>

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book = {"C 语言", "RUNOOB", "编程语言", 123456};

int main()
{
    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
}

output

title : C 语言
author: RUNOOB
subject: 编程语言
book_id: 123456

3 结构体大小的计算

#include <stdio.h>

struct Person {
    char name[20];
    int age;
    float height;
};

int main() {
    struct Person person;
    printf("name size: %zu\n", sizeof(person.name));
    printf("age size: %zu\n", sizeof(person.age));
    printf("height size: %zu\n", sizeof(person.height));
    printf("结构体 Person 大小为: %zu 字节\n", sizeof(person));
    return 0;
}

output

name size: 20
age size: 4
height size: 4
结构体 Person 大小为: 28 字节

再看看下面这个例子

#include <stdio.h>

int main(void)
{
    struct A
    {
        char a;
        int b;
        char c;

    } a = {'a', 10, 'o'};
    
    printf("size of a = %d\n", sizeof(a.a));
    printf("size of b = %d\n", sizeof(a.b));
    printf("size of c = %d\n", sizeof(a.c));
    printf("size of a = %d\n", sizeof(a));
    
    return 0;
}

output

size of a = 1
size of b = 4
size of c = 1
size of a = 12

#include <stdio.h>

int main(void)
{
    struct A
    {
        char a;
        char c;
        int b;
    } a = {'a', 'o', 10};
    
    printf("size of a = %d\n", sizeof(a.a));
    printf("size of c = %d\n", sizeof(a.c));
    printf("size of b = %d\n", sizeof(a.b));
    printf("size of a = %d\n", sizeof(a));
    
    return 0;
}

output

size of a = 1
size of c = 1
size of b = 4
size of a = 8

存在内存对齐现象

在C语言中,内存对齐(Memory Alignment)是一个重要的概念,它指的是数据在内存中按照一定的规则进行排列,以提高内存的访问效率。不同的硬件平台对内存访问有不同的要求,如果数据没有按照这些要求来对齐,可能会导致性能下降,甚至在某些平台上引发硬件异常。

为什么要内存对齐?

  • 性能优化:现代计算机体系结构通常通过内存对齐来提高内存访问速度。这是因为硬件可能设计为以特定的字节边界(如4字节、8字节等)来高效地访问内存。
  • 平台兼容性:不同的硬件平台对内存对齐的要求可能不同。遵循内存对齐的规则可以确保程序在不同平台上的兼容性。

内存对齐的规则

  • 自然对齐:数据的存储起始地址是数据本身大小的整数倍。例如,int类型(假设为4字节)的变量应该存储在4的倍数地址上。
  • 结构体对齐:结构体中的成员变量和整个结构体本身都会受到对齐规则的影响。结构体成员的对齐通常遵循其自然对齐规则,而结构体本身的对齐则可能由编译器或编译器的特定选项决定。
  • 编译器指令:大多数编译器提供了控制对齐的指令或选项,如GCC的__attribute__((aligned(n)))和MSVC的#pragma pack(n)

4 访问结构成员

成员访问运算符(.)

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */
   struct Books Book2;        /* 声明 Book2,类型为 Books */
 
   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* Book2 详述 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* 输出 Book1 信息 */
   printf( "Book 1 title : %s\n", Book1.title);
   printf( "Book 1 author : %s\n", Book1.author);
   printf( "Book 1 subject : %s\n", Book1.subject);
   printf( "Book 1 book_id : %d\n", Book1.book_id);

   /* 输出 Book2 信息 */
   printf( "Book 2 title : %s\n", Book2.title);
   printf( "Book 2 author : %s\n", Book2.author);
   printf( "Book 2 subject : %s\n", Book2.subject);
   printf( "Book 2 book_id : %d\n", Book2.book_id);

   return 0;
}

output

Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

#include <stdio.h>
#include <string.h>

struct Person {
    int age;
    float height;
};

struct Birthday{
    char name[20];
    struct Person person;
};

int main() {
    struct Birthday birthday;
    strcpy(birthday.name, "Bryant");
    birthday.person.age = 18;
    birthday.person.height = 171;
    printf("name:%s, age:%d, height:%f\n", birthday.name, birthday.person.age, birthday.person.height);
  
    return 0;
}

output

name:Bryant, age:18, height:171.000000

5 结构作为函数参数

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* 函数声明 */
void printBook( struct Books book );
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */
   struct Books Book2;        /* 声明 Book2,类型为 Books */
 
   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* Book2 详述 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* 输出 Book1 信息 */
   printBook( Book1 );

   /* 输出 Book2 信息 */
   printBook( Book2 );

   return 0;
}
void printBook( struct Books book )
{
   printf( "Book title : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", book.book_id);
}

output

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

#include <stdio.h>

struct Student{
    int age;
};

void test(struct Student stu){
    printf("test 修改前的值:%d\n", stu.age);
    stu.age = 10;
    printf("test 修改后的值:%d\n", stu.age);
}

int main()
{
    struct Student student;
    student.age = 30;
    printf("main 修改前的值:%d\n", student.age);
    test(student);
    printf("main 修改后的值:%d\n", student.age);
    return 0;
}

output

main 修改前的值:30
test 修改前的值:30
test 修改后的值:10
main 修改后的值:30

可以看到仅改变了形参,实际值没有改变,传结构体指针就没问题(见下节)

#include <stdio.h>

struct Student{
    int age;
};

void test(struct Student* stu){
    printf("test 修改前的值:%d\n", stu->age);
    stu->age = 10;
    printf("test 修改后的值:%d\n", stu->age);
}

int main()
{
    struct Student student;
    student.age = 30;
    printf("main 修改前的值:%d\n", student.age);
    test(&student);
    printf("main 修改后的值:%d\n", student.age);
    return 0;
}

output

main 修改前的值:30
test 修改前的值:30
test 修改后的值:10
main 修改后的值:10

6 指向结构的指针

#include <stdio.h>
#include <string.h>

struct Student{
    char name[20];
    int age;
};


int main()
{
    struct Student student;
    
    student.age = 20;
    strcpy(student.name, "Bryant");
    
    printf("name: %s, age: %d\n", student.name, student.age);

    struct Student *p = &student;
    printf("name: %s, age: %d\n", p->name, p->age);
    printf("name: %s, age: %d\n", (*p).name, (*p).age);
   
    return 0;
}

output

name: Bryant, age: 20
name: Bryant, age: 20
name: Bryant, age: 20

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* 函数声明 */
void printBook( struct Books *book );
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */
   struct Books Book2;        /* 声明 Book2,类型为 Books */
 
   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* Book2 详述 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* 通过传 Book1 的地址来输出 Book1 信息 */
   printBook( &Book1 );

   /* 通过传 Book2 的地址来输出 Book2 信息 */
   printBook( &Book2 );

   return 0;
}
void printBook( struct Books *book )
{
   printf( "Book title : %s\n", book->title);
   printf( "Book author : %s\n", book->author);
   printf( "Book subject : %s\n", book->subject);
   printf( "Book book_id : %d\n", book->book_id);
}

output

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

7 结构体数组

#include <stdio.h>
#include <string.h>

struct Person {
    char name[20];
    int age;
    float height;
}person[3]={{"Bryant", 19, 178}, {"Chole", 18, 167}};


int main() {
    for(int i=0; i<2; i++)
        printf("name:%s, age:%d, height:%f\n", person[i].name, 
        person[i].age, person[i].height);
    return 0;
}

output

name:Bryant, age:19, height:178.000000
name:Chole, age:18, height:167.000000

8 动态申请结构体

结构体也可以在堆里面动态申请

#include <stdio.h>
...
int main(void)
{
    struct Info *i1;
    struct Info *i2;
    
    i1 = (struct Info *)malloc(sizeof(struct Info));
    i2 = (struct Info *)malloc(sizeof(struct Info));
    if (i1 == NULL || i2 == NULL)
    {
        printf("内存分配失败!\n");
        exit(1);
    }
    
    printf("请录入第一个同学的信息...\n");
    getInput(i1);
    putchar('\n');
    printf("请录入第二个学生的信息...\n");
    getInput(i2);

    printf("\n录入完毕,现在开始打印...\n\n");
    printf("打印第一个学生的信息...\n");
    printInfo(i1);
    putchar('\n');
    printf("打印第二个学生的信息...\n");
    printInfo(i2);
    
    free(i1);
    free(i2);
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1919166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

构造函数的初始化列表,static成员,友元,内部类【类和对象(下)】

P. S.&#xff1a;以下代码均在VS2022环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;LiUEEEEE                        …

【C++:默认成员函数】

构造函数 特点 没有返回值支持函数重载对象实例化时&#xff0c;编译器自动调用作用不是构造&#xff0c;而是初始化函数名与类名相同无参函数和全缺省的函数&#xff0c;不用传参就能调用的函数叫做默认构造函数 构造函数是一个特殊的成员函数 注&#xff1a;无参构造函数在实…

一场夏测杀出个“双冠王”,极越01成为纯电SUV标杆

文 | AUTO芯球 作者 | 雷慢 万万没想到&#xff0c;懂车帝夏测运动会杀出一匹最大的黑马&#xff0c;竟然是极越01。 当前正在进行的懂车帝夏测运动会&#xff0c;在“纯电SUV/MPV续航达成率”赛事中&#xff0c;极越01以85.8%的续航达成率获得第一名。并且由于赛制规则限制…

Go泛型详解

官网文档&#xff1a;https://go.dev/blog/intro-generics 泛型为该语言添加了三个新的重要功能&#xff1a; 函数和类型的类型参数。将接口类型定义为类型集&#xff0c;包括没有方法的类型。类型推断&#xff0c;在许多情况下允许在调用函数时省略类型参数。 类型参数&…

Java高级重点知识点-22-缓冲流、转换流、序列化流、打印流

文章目录 缓冲流字节缓冲流字符缓冲流 转换流InputStreamReader类OutputStreamWriter类 序列化ObjectOutputStream类ObjectInputStream类 打印流 缓冲流 缓冲流,也叫高效流&#xff0c;是对4个基本的 FileXxx 流的增强&#xff0c;所以也是4个流 基本原理&#xff1a; 缓冲流的…

SpringBoot集成Sentinel 实现QPS限流

Spring Cloud Alibaba 的 Sentinel 组件提供了丰富的“流量控制“规则&#xff0c; 单体SpringBoot应用中也可以集成 Sentinel 来实现流量控制&#xff0c;本文主要讲 QPS流量控制。 SpringBoot集成Sentinel有两种方式&#xff1a; 一种是 dashboard控制面板的方式&#xff0…

virturalBox+K8S部署jaeger-all-in-one

pod的yaml如下&#xff1a;这里使用的是主机host模式 apiVersion: apps/v1 kind: Deployment metadata:name: jaegerlabels:app: jaeger spec:replicas: 1selector:matchLabels:app: jaegertemplate:metadata:labels:app: jaegerspec:hostNetwork: truecontainers:- name: jae…

【js面试题】深入理解浏览器对象模型(BOM)

面试题&#xff1a;请你说说对bom的理解&#xff0c;常见的bom对象你了解哪些 引言&#xff1a; 浏览器对象模型&#xff08;BOM&#xff09;是JavaScript中用于与浏览器窗口及其内容进行交互的一组对象和方法。 BOM的核心是window对象&#xff0c;它代表了浏览器窗口本身&…

tableau人口金字塔,漏斗图,箱线图绘制 - 13

人口金字塔&#xff0c;漏斗图&#xff0c;箱线图 1. 金字塔1.1 定义1.2 金字塔创建1.2.1 数据导入1.2.2 数据异常排查1.2.3 创建度量字段1.2.4 转换属性1.2.5 创建数据桶1.2.6 选择相关属性1.2.7 年龄排序1.2.8 创建计算字段1.2.9 选择相关字段1.2.10 设置轴排序1.2.11 设置颜…

Python编程学习笔记(4)--- 字典

目录 1 什么是字典 2 使用字典 2.1 访问字典中的值 2.2 添加键值对 2.3 创建空字典 2.4 修改字典中的值 2.5 删除键值对 2.6 类似键值对组成的字典 2.7 使用get&#xff08;&#xff09;来访问值 3 遍历字典 3.1 遍历所有键值对 3.2 遍历字典中的所有键 3.3 按照特…

【C语言 】C语言 学生选修课程系统(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

【限免】HFM雷达信号及模糊函数MATLAB代码

微信公众号&#xff1a;EW Frontier QQ交流群&#xff1a;949444104 HFM信号 HFM 信号表达式: 式中:T 为脉冲宽度,b -k / f1 f2 为信号的调频参数,k B / T 为对应的线性调频斜率,B 为信号带宽,f0 为波形中心频率,f1 f0 -B / 2 为下限频率,f2 f0 B / 2 为上限频率。 仿真结…

【系统架构设计】计算机组成与体系结构(三)

计算机组成与体系结构&#xff08;三&#xff09; 计算机系统组成存储器系统主存储器辅助存储器Cache存储器Cache 基本原理映射机制直接映射全相联映射组相联映射 替换算法写操作 流水线&#xff08;计算&#xff09;流水线周期流水线执行时间流水线的吞吐率流水线的加速比 计算…

【unity笔记】九、Unity添加串口通信

unity仿真使用虚拟串口调试。下面为简单流程。 常用串口调试软件在这里下载。 1.虚拟串口 添加虚拟串口&#xff0c;这里使用com1 com2 2. 串口调试 在这里为虚拟串口发送消息。 3. unity配置 3.1 设置 在文件->生成设置->玩家设置->玩家->其他设置 中找到…

C++|智能指针

目录 引入 一、智能指针的使用及原理 1.1RAII 1.2智能指针原理 1.3智能指针发展 1.3.1std::auto_ptr 1.3.2std::unique_ptr 1.3.3std::shared_ptr 二、循环引用问题及解决方法 2.1循环引用 2.2解决方法 三、删除器 四、C11和boost中智能指针的关系 引入 回顾上…

接口测试框架基于模板自动生成测试用例!

引言 在接口自动化测试中&#xff0c;生成高质量、易维护的测试用例是一个重要挑战。基于模板自动生成测试用例&#xff0c;可以有效减少手工编写测试用例的工作量&#xff0c;提高测试的效率和准确性。 自动生成测试用例的原理 为了实现测试用例数据和测试用例代码的解耦&a…

企事业网站需要做软件测试吗?包括哪些测试内容和好处?

在这个数字化时代&#xff0c;企事业网站已经成为宣传和交流的重要平台&#xff0c;它的稳定性、安全性和用户体验对于企业形象和业务发展至关重要。因此&#xff0c;为了确保企事业网站的良好运行&#xff0c;对其进行软件测试是至关重要的。那么网站测试具体有哪些好处?又包…

从 ArcMap 迁移到 ArcGIS Pro

许多 ArcMap 用户正在因 ArcGIS Pro 所具有的现代 GIS 桌面工作流优势而向其迁移。 ArcGIS Pro 与其余 ArcGIS 平台紧密集成&#xff0c;使您可以更有效地共享和使用内容。 它还将 2D 和 3D 组合到一个应用程序中&#xff0c;使您可以在同一工程中使用多个地图和多个布局。 Arc…

redis源码分析之底层数据结构(一)-动态字符串sds

1.绪论 我们知道redis是由c语言实现的&#xff0c;c语言中是自带字符串的&#xff0c;但是为什么redis还要再实现自己的动态字符串呢&#xff0c;这种动态字符串的底层数据结构是怎样的呢?接下来我们带着这些问题来看一看redis中的动态字符串sds。 2.sds的组成 struct __at…

Python模块ConfigParser读取应用程序的配置文件简单示例

一、模块说明&#xff1a; 系统管理员通常通过文本编辑器编辑这些配置文件&#xff0c;以设置应用程序的默认值&#xff0c;然后应用程序将读取并解析这些配置文件&#xff0c;并根据其中的内容执行对应操作。ConfigParser模块具有read()方法&#xff0c;用于读取配置文件。 …