【C】Structure

在这里插入图片描述

参考摘抄学习来自:

  • 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.mfbz.cn/a/774368.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT-4o还没完全开放,Moshi就提前开源了

GPT-4o已经发布有段时间了&#xff0c;但大众迟迟没有等到成型的产品出来&#xff0c;这会的功夫&#xff0c;法国创业团队抢先OpenAI发布端到端实时音频模型——Moshi。单从响应时效上&#xff0c;体验下来应该比GPT-4o还要快&#xff0c;但是音色及语言多样性的支持上&#x…

从资金管理的角度 谈谈伦敦金投资技巧

刚进入伦敦金市场的时候&#xff0c;笔者认为技术分析是很重要的&#xff0c;所以将学习伦敦金投资技巧的精力全部投入到技术分析的学习中。经过一系列交易的亏损&#xff0c;笔者才发现&#xff0c;其实交易管理才是最重要的。如果管理得好&#xff0c;30%的胜率&#xff0c;投…

mysql修改字符集为UTF-8

启动 mysql 服务 systemctl start mysqld 登录 mysql mysql -uroot -p 查询 mysql 字符集 ## 在 mysql 命令行下查询 mysql 状态 mysql>status; 退出 mysql 并关闭 mysql ## 退出 mysql mysql>exit; ## 关闭 mysql systemctl stop mysqld 编辑 my.cnf 配置文…

数学建模----滑翔伞伞翼面积的设计及运动状态描述

摘要 滑翔伞作为一项融合了挑战、冒险和刺激于一体的运动&#xff0c;近年来在全球范围内受到了广泛的关注。滑翔伞在救援、探险、体育、娱乐、环保和交通等领域的应用展现了其重要价值。然而&#xff0c;中国在滑翔伞领域尚未取得突破&#xff0c;缺乏全球影响力和竞争力。因此…

[C++]——继承 深继承

一、继承概念 (1)、定义 继承(inheritance)机制是面向对象程序设计使代码复用最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能。继承呈现了面向对象程序设计的层次结构&#xff0c;体现了由简单到复杂的认知过程&#xff0c;是类…

qq六七年前的聊天记录怎么找?80%的人是这么做的

在使用QQ的过程中&#xff0c;六七年前的聊天记录可能承载了许多珍贵的回忆和重要的信息。然而&#xff0c;随着时间的推移&#xff0c;这些记录可能变得难以寻找甚至被遗忘。那么&#xff0c;qq六七年前的聊天记录怎么找呢&#xff1f;事实上&#xff0c;有80%的人通过以下三种…

PySide6 实现资源的加载:深入解析与实战案例

目录 1. 引言 2. 加载内置资源 3. 使用自定义资源文件&#xff08;.qrc&#xff09; 创建.qrc文件 编译.qrc文件 加载资源 4. 动态加载UI文件 使用Qt Designer设计UI 加载UI文件 5. 注意事项与最佳实践 6. 结论 在开发基于PySide6的桌面应用程序时&…

2024-07-05 base SAS programming学习笔记9(variables)

1.在数据集增加累加变量值&#xff08;SUM&#xff09; 求和语句(SUM STATEMENT)&#xff1a;variableexpression variable是累积求和的变量名&#xff0c;为数值型&#xff0c;默认初始值为0&#xff1b;该variable值则会保留到一个观测 当expression有缺失值&#xff0c;在求…

事件分发机制:demo复现自定义ViewGroup点击事件不起作用

几年前遇到的一个bug&#xff0c;不弄清楚心里就是不舒服&#xff01; 平时应用开发中&#xff0c;经常遇到的UI需求&#xff0c;例如抖音的设置界面&#xff0c;如下图所示&#xff1a; 很容易想到&#xff0c;自定义一个Layout&#xff0c;左边一个图标&#xff0c;中间文…

CentOS 离线安装部署 MySQL 8详细教程

1、简介 MySQL是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它基于SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;进行操作。MySQL最初由瑞典的MySQL AB公司开发&#xff0c;后来被Sun Microsystems公司…

QT学习(8)——QT绘图学习之绘图设备,QPixmap显示优化,QImage对像素修改,QPicture绘图的记录和重现

目录 引出绘图设备QPixmap使用初体验修改填充颜色 QImage 绘图设备对像素进行修改 QPicture 绘图设备&#xff0c;记录和重现绘图的重绘 总结绘图学习新建一个项目使用初体验画笔颜色、宽度设置画笔类型设置画刷的使用代码 高级设置抗锯齿画家移动状态保存和还原 画家画图片插曲…

Ubuntu 22.04.4 LTS 安装 php apache LAMP 环境nginx

1 安装php-fpm apt update apt-get install php-fpm #配置php-fpm服务启动 systemctl enable php8.1-fpm systemctl start php8.1-fpm #查看服务 systemctl status php8.1-fpm #查看版本 rootiZbp1g7fmjea77vsqc5hmmZ:~# php -v PHP 8.1.2-1ubuntu2.18 (cli) (built: J…

蓝牙信标和蓝牙标签我们如何区分,区分方法有哪些?

蓝牙信标和蓝牙标签其实是两种不同的技术&#xff0c;很多人可能会把蓝牙信标和蓝牙标签搞混&#xff0c;因为区分不开来&#xff0c;但实际上&#xff0c;区分这两种技术也很简单&#xff0c;因为它们各自都有不一样的特性&#xff0c;通过这些特性&#xff0c;我们也能正常区…

20.【C语言】初识结构体(重要)

定义&#xff1a;由一批数据组合而成的结构型数据 作用&#xff1a;描述复杂对象&#xff0c;创建新的类型 格式&#xff1a; struct 对象 { …… } 介绍. 用法&#xff1a;结构体变量.成员变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct hotal…

三、docker配置阿里云镜像仓库并配置docker代理

一、配置阿里云镜像仓库 1. 登录阿里云官网&#xff0c;并登录 https://www.aliyun.com/ 2. 点击产品 - 容器 - 容器与镜像服务ACR - 管理控制台 - 镜像工具 - 镜像加速器 二、配置docker代理 #1. 创建docker相关的systemd文件 mkdir -p /etc/systemd/system/docker.servic…

云服务器在 Web 应用程序中作用

云服务器在Web应用程序中扮演着至关重要的角色&#xff0c;它不仅是现代Web应用程序的基石&#xff0c;还是推动业务发展和提升用户体验的关键技术之一。下面将详细探讨云服务器在Web应用程序中的重要作用及其优势。 首先&#xff0c;云服务器为Web应用程序提供了高度可扩展的…

Linux平台x86_64|aarch64架构如何实现轻量级RTSP服务

技术背景 我们在做Linux平台x86_64架构或aarch64架构的推送模块的时候&#xff0c;有公司提出这样的技术需求&#xff0c;希望在Linux平台&#xff0c;实现轻量级RTSP服务&#xff0c;实现对摄像头或屏幕对外RTSP拉流&#xff0c;同步到大屏上去。 技术实现 废话不多说&…

gen_region_line 生成直线

gen_region_line (Operator) Name 名称 gen_region_line — Store input lines as regions.将输入行存储为region。 生成直线&#xff0c;直线区域 Signature 签名 gen_region_line( : RegionLines : BeginRow, BeginCol, EndRow, EndCol : ) Description 描述 运算符ge…

JavaScript基础知识5(对象)

JavaScript基础知识5&#xff08;对象&#xff09; 对象创建对象使用对象字面量使用 new Object() 访问和修改属性点表示法方括号表示法 动态添加和删除属性添加属性删除属性 对象方法对象的遍历常用属性和方法数学常量数学函数三角函数 使用示例生成随机整数计算圆的面积求最大…

yolov8-seg分割模型TensorRt部署,去掉torch

已完成的yolov8-seg分割模型TensorRt部署 准备下载yolov8-seg模型转化为onnx和trt推理写好的推理接口 准备 https://github.com/songjiahao-wq/yolov8_seg_trtinference.git下载代码 安装TensorRt8.6版本&#xff0c;以及pip install -r requirements.txt 下载yolov8-seg模型…