C语言基础之结构体

文章目录

  • 一、结构体
    • 1、结构体概述
    • 2、结构体类型的定义方式
      • (1)先定义结构体类型,再定义结构体变量
      • (2)结构体类型、变量同时定义
      • (3)一次性结构体
    • 3、结构体成员的初始化
      • (1)结构体初始化
      • (2)清空结构体
      • (3)键盘给结构体赋值
    • 4、结构体成员操作
    • 5、相同类型的结构体操作
    • 6、结构体嵌套
    • 7、结构体数组
    • 8、结构体指针变量
    • 9、结构体数组元素的指针
    • 10、结构体的指针指向堆区空间
    • 11、结构体深层拷贝
    • 12、结构体与结构体成员都在堆区
    • 13、结构体对齐
      • (1)结构体自动类型对齐
      • (2)结构体嵌套结构体 自动对齐规则
      • (3)结构体强制对齐
    • 14、位域
  • 二、共用体
  • 三、枚举enum

一、结构体

1、结构体概述

将多种数据结构封装在一起 形成新的结构叫结构体

每种数据结构 都有自己独立的空间

结构体的关键字 struct

2、结构体类型的定义方式

(1)先定义结构体类型,再定义结构体变量

struct str
{
    int num;//结构体成员
    char name;
};
struct str array;//定义结构体变量

(2)结构体类型、变量同时定义

struct str
{
    int num;//结构体成员
    char name;
}array;//定义结构体变量
struct str data;//定义结构体新变量

(3)一次性结构体

struct 
{
     int num;   
}asd;//定义变量

3、结构体成员的初始化

(1)结构体初始化

#include <stdio.h>

struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array = {100,"hello",{200,300}};
    printf("%d %s %d\n",array.num, array.str, array.data[1]);
    return 0;
}

(2)清空结构体

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array;
    memset(&array,0,sizeof(array));
    printf("%d\n",sizeof(array));//260 = 1*4+128+32*4
    return 0;
}

(3)键盘给结构体赋值

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array;
    memset(&array,0,sizeof(array));
    scanf("%d %s",&array.num, array.str);//键盘获取内容
    printf("%d  %s\n",array.num, array.str);
    return 0;
}
#include <stdio.h>
#include <string.h>
struct date
{
    int num;
    char str[128];
};
int main(int argc, char const *argv[])
{
    struct date arr[3];
    memset(arr,0,sizeof(arr));
    int n = sizeof(arr)/sizeof(arr[0]);

    //获取键盘数组
    printf("请输入%d个学生信息num str\n",n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        scanf("%d %s",&arr[i].num,arr[i].str);
    }
    
    for ( i = 0; i < n; i++)
    {
        printf("%d %s\n",arr[i].num,arr[i].str);
    }   
}

4、结构体成员操作

int类型

zxc.num +=100;

char类型

strcpy(zxc.str,"name");

5、相同类型的结构体操作

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
	struct stu array = {100,"hello",200};
    struct stu array2;
    #if 1
    //方式一;成员逐个赋值
        array2.num = array.num;
        *array2.data = *array.data;
        strcpy(array2.str,array.str);
    #elif 0
    //方式二;相同类型的结构体变量,可以直接赋值
        array2 = array;
    #else
    //方式三
    memcpy(&array2,&array,sizeof(array));

    #endif
    printf("%d %s %d\n",array2.num,array2.str, *array2.data);
    return 0;
}

6、结构体嵌套

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
struct date
{
    int year;
    int month;
    int day;
    struct stu ob;
};
int main(int argc, char const *argv[])
{
	struct date lucy = {2023,07,28,{666,"xixi",999}};
    printf("year=%d month=%d day=%d\n",lucy.year,lucy.month,lucy.day);
    printf("str = %s data = %d\n",lucy.ob.str,*lucy.ob.data);
    return 0;
}

结果:

year=2023 month=7 day=28
str = xixi data = 999

7、结构体数组

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char name[128];
};
int main(int argc, char const *argv[])
{
	struct date2 arr[3] = {{100,"qwe"},{232,"asdas"},{7897,"ksjs"}};
    int n = 0;
    n = sizeof(arr)/sizeof(arr[0]);
    
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("%d  %s\n",arr[i].num,arr[i].name);
    } 
    return 0;
}

8、结构体指针变量

结构体指针变量 本质是指针变量 保存的是结构体变量的地址

p->num 根据地址获取num

(*p).num

左边是 地址 使用 ->

左边是 变量 使用 .

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
	struct stu ob = {100,"xixi",200};
    struct stu *p = &ob;
    printf("%d %s %d\n",p->num,p->str,*(*p).data);
    return 0;
}

9、结构体数组元素的指针

#include <stdio.h>
#include <string.h>
struct data
{
    int num;
    char str[128];
};
void input_stu_data(struct data *arr,int n)
{
    printf("请输入%d个学生信息num arr\n",n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("请输入第%d个学生信息:",i+1);
        scanf("%d %s",&(arr+i)->num,arr[i].str);
    }   
    return;
}
void sort_arr_array(struct data *arr ,int n)
{
    int i = 0;
    for ( i = 0; i < n-1; i++)
    {
        int min = i;
        int j = min +1;
        for ( ; j < n; j++)
        {
            if(arr[min].num>arr[j].num)
                min = j;
        }
        if(i != min)
        {
            struct data tmp = arr[min];
            arr[min] = arr[i];
            arr[i] = tmp;
        }
    }
    return;
}
int main(int argc, char const *argv[])
{
    struct data arr[5];
    memset(arr,0,sizeof(arr));

    int n = sizeof(arr)/sizeof(arr[0]);
    //键盘输入
    input_stu_data(arr,n);
    //对结构体数组排序
    sort_arr_array(arr , n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("%d %s\n",arr[i].num,arr[i].str);
    }
    return 0;
}

10、结构体的指针指向堆区空间

当结构体有指针成员时须为其申请指针空间

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char *name;
};
int main(int argc, char const *argv[])
{
    struct stu lucy;
    lucy.num = 100;
    lucy.name = (char *)calloc(1,128);//申请空间
    strcpy(lucy.name, "hellow world");
    printf("%d %s\n",lucy.num,lucy.name);
    printf("%c\n",lucy.name[1]);
    lucy.name[1] = 'D';
    printf("%d %s\n",lucy.num,lucy.name);
    //释放lucy.name指向的堆区空间
    if(lucy.name != NULL)
    {
        free(lucy.name);
        lucy.name = NULL;
    }
    return 0;
}

11、结构体深层拷贝

如果结构体中含有指针成员,尽量使用深拷贝

(如果使用浅拷贝,拷贝完成后需要对lucy、ob申请的空间进行释放,由于指向同一空间,就造成空间重复释放,所以使用深拷贝,为ob重新申请一个空间,使用完成后进行释放)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
    int num;
    char *name;
};


int main(int argc, char const *argv[])
{
    struct stu lucy;
    struct stu ob;
    lucy.num = 100;
    lucy.name = (char *)calloc(1,128);//申请空间
    ob.name = (char *)calloc(1,128);
    
    ob.num = lucy.num;
    strcpy(ob.name,lucy.name);
    strcpy(lucy.name, "hellow world");
    printf("%d %s\n",lucy.num,lucy.name);
    printf("%c\n",lucy.name[1]);
    
    lucy.name[1] = 'D';
    printf("%d %s\n",lucy.num,lucy.name);
    //释放lucy.name指向的堆区空间
    if(lucy.name != NULL)
    {
        free(lucy.name);
        lucy.name = NULL;
    }
    if(ob.name != NULL)
    {
        free(ob.name);
        ob.name = NULL;
    }
    return 0;
}

如果结构体中没有指针成员 赋值 不会出现浅拷贝。

如果结构体中有指针成员 赋值 容易造成浅拷贝

12、结构体与结构体成员都在堆区

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
    int num;
    char *name;
};
int main(int argc, char const *argv[])
{
    //结构体本身在堆区
    struct stu *p = NULL;
    p = (struct stu *)calloc(1,sizeof(struct stu));

    //为结构体指针成员申请空间
    
    p->name = (char *)calloc(1,128);//(*p).name = (char *)calloc(1,128);
    p->num = 100;
    strcpy(p->name,"hello world");
    printf("%d %s\n",p->num,p->name);
    //先释放成员空间
    if(p->name != NULL)
    {
        free(p->name);
        p->name = NULL;
    }
    //在释放结构体空间
    if(p != NULL)
    {
        free(p);
        p = NULL;
    }
} 

13、结构体对齐

(1)结构体自动类型对齐

①确定分配单位(一行分配多少字节)

​ 结构体中最大的基本类型长度决定

②确定成员偏移量

​ 成员偏移量 = 成员本身类型的整数倍

③收尾工作

​ 结构体的总大小 = 分配单位整数倍

#include <stdio.h>
struct array
{
    char str;
    int num;
    char name;
};

int main(int argc, char const *argv[])
{
    struct array A;
    printf("%d\n",sizeof(A));
    printf("%p\n",&A.str);
    printf("%p\n",&A.num);
    printf("%p\n",&A.name);
    return 0;
}

结果:

12
000000000061FDE4
000000000061FDE8
000000000061FDEC

案例1:画出以下结构体的对齐

struct Data
{
    char a;
    short b;
    int c;
    char d;
    short e;
};

在这里插入图片描述

(2)结构体嵌套结构体 自动对齐规则

①确定分配单位(一行分配多少字节)

​ 所有结构体中最大的基本类型长度决定

②确定成员的偏移量

​ 普通成员偏移量 = 成员自身类型的整数倍

​ 结构体成员的偏移量 = 结构体中最大的基本类型整数倍

③收尾工作

​ 结构体成员大小 = 该结构体中最大的基本类型整数倍

​ 结构体的总大小 = 分配单位整倍数

#include <stdio.h>
struct data1
{  
    char str;
    char str2;
    int num;
};
struct data2
{ 
    char str1;
    struct data1 bob;
    short num1;
};

int main(int argc, char const *argv[])
{
    struct data2 bob2;
    printf("%d\n",sizeof(bob2));
    //结构体自动对齐
    printf("%p\n",&bob2.str1);
    printf("%p\n",&bob2.bob.str);
    printf("%p\n",&bob2.bob.str2);
    printf("%p\n",&bob2.bob.num);
    printf("%p\n",&bob2.num1); 
    return 0;
}

结果:

16
000000000061FDE0
000000000061FDE4
000000000061FDE5
000000000061FDE8
000000000061FDEC

(3)结构体强制对齐

​ #prangma pack(value)是指定对齐值

​ valu值为1,2,4,8,16

①确定分配单位(一行分配多少字节)

​ 分配单位 = min(结构体中最大的基本类型,value)

②确定成员的偏移量

​ 成员偏移量 = 成员自身类型的整数倍

③收尾工作

​ 结构体的总大小 = 分配单位整倍数

#include <stdio.h>
#pragma pack(2)
struct array
{
    char str;
    int num;
    char name;
};

int main(int argc, char const *argv[])
{
    struct array A;
    printf("%d\n",sizeof(A));
    printf("%p\n",&A.str);
    printf("%p\n",&A.num);
    printf("%p\n",&A.name);
    return 0;
}

结果:

8
000000000061FDE8
000000000061FDEA
000000000061FDEE

14、位域

在结构体中,以位为单位的成员,称之为位段(位域)

struct A
{
    unsigned int a:2;
    unsigned int b:6;
    unsigned int c:4;
    unsigned int d:3;
    unsigned int e;
}data;

​ a为无符号整型,大小只占2位二进制位

​ 位域可以是unsigned int ,unsigned char

​ 没有非位域隔开的位域 叫相邻位域(a,c)

​ 相邻位域可以压缩

​ 位段的大小不能超过存储单元的大小

​ 不要对位域取地址。

如:a=9 == 1001 ,但a的存储单元只有两位所以只能存储01

​ b=9 == 1001,b的存储单元有6位可以存储1001

#include <stdio.h>

struct A
{
    unsigned int a:2;
    unsigned int b:6;
    unsigned int c:4;
    unsigned char :8;
    unsigned int d:3;
    unsigned int e;
}data;
int main(int argc, char const *argv[])
{
    printf("sizeof(struct A)=%lu\n",sizeof(struct A));
    return 0;
}

无意义位段

#include <stdio.h>
struct A
{
    unsigned char a : 2;
    unsigned char :2;  //两位无意义位段
    unsigned char b : 2;
    unsigned char c : 2;
    //int num;
};

int main(int argc, char const *argv[])
{
    printf("sizeof(struct A)=%lu\n",sizeof(struct A));
}

在这里插入图片描述

#include <stdio.h>
struct B
{
    unsigned char addr : 2;
    unsigned char : 1;
    unsigned char opt :2;
    unsigned char : 1;
    unsigned char data : 2;
};
int main(int argc, char const *argv[])
{
    struct B reg;
    reg.addr = 2;
    reg.opt = 1;
    reg.data = 1;
}

二、共用体

共用体:所有成员共享同一块空间

结构体:所有成员拥有独立空间

union C
{
    int a;
    short b;
    char c;
};

成员a b c共享同一块空间。空间大小 由最大的成员空间决定,即c

union C ob;
ob.a = 10;//空间内容为10
ob.b = 20;//空间内容为20
ob.c = 30;//空间内容为30
ob.a + ob.b + ob.c = 90;

三、枚举enum

枚举:将枚举变量要赋的值一一列举出来

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

enum ha{data1,data2,data3=14,data4};
int main(int argc, char const *argv[])
{
    enum ha num = data2;
    printf("%d\n",num);
}

枚举默认从0开始依次递增即,data1 = 0 ; data2 = 1 ; data3 = 14 ; data4 = 15 ;

四、如有错误欢迎指正
如要转发请告知

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

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

相关文章

pytorch升级打怪(三)

数据集合数据加载器 简介加载数据集迭代和可视化数据集为您的文件创建自定义数据集__init____len____getitem__ 准备您的数据以使用DataLoaders进行训练通过DataLoader进行遍载 简介 处理数据样本的代码可能会变得混乱且难以维护&#xff1b;理想情况下&#xff0c;我们希望我…

软考高级:企业应用集成概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

内网渗透之路:常用命令助力信息深度探索

1、查询网络配置信息 ipconfig /all 2、查询操作系统及软件信息 &#xff08;1&#xff09;查询操作系统和版本信息 英文操作系统 systeminfo | findstr /B /C:"OS Name" /C:"OS Version" 中文操作系统 systeminfo | findstr /B /C:"OS 名称&q…

论文阅读:FCB-SwinV2 Transformer for Polyp Segmentation

这是对FCBFormer的改进&#xff0c;我的关于FCBFormer的论文阅读笔记&#xff1a;论文阅读FCN-Transformer Feature Fusion for PolypSegmentation-CSDN博客 1&#xff0c;整体结构 依然是一个双分支结构&#xff0c;总体结构如下&#xff1a; 其中一个是全卷积分支&#xff…

【Flutter 面试题】什么是Widget,Stateful Widget和Stateless Widget之间的区别?

【Flutter 面试题】什么是Widget&#xff0c;Stateful Widget和Stateless Widget之间的区别&#xff1f; 文章目录 写在前面解答补充说明StatelessWidget 示例StatefulWidget 示例 写在前面 &#x1f64b; 关于我 &#xff0c;小雨青年 &#x1f449; CSDN博客专家&#xff0c…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:TextArea)

多行文本输入框组件&#xff0c;当输入的文本内容超过组件宽度时会自动换行显示。 高度未设置时&#xff0c;组件无默认高度&#xff0c;自适应内容高度。宽度未设置时&#xff0c;默认撑满最大宽度。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&…

会员项目定价卡css3特效

会员项目定价卡css3特效&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 下载地址 会员项目定价卡css3特效代码

WIFI 7技术的应用前景

随着WIFI 7技术的不断成熟和普及&#xff08;如果对WIFI 7技术不太了解的&#xff0c;可以点击链接去查看一下这篇文章WIFI7&#xff1a;开启无线通信新纪元 &#xff09;&#xff0c;我们正迎来一个数字连接的全新时代。WIFI 7作为新一代无线网络标准&#xff0c;将极大的改变…

【矩阵】48. 旋转图像【中等】

旋转图像 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《适应分布式资源渗透率提高的配电网网元规划方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

springboot276基于JS的个人云盘管理系统的设计与实现

个人云盘管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装个人云盘管理系统软件来发挥其…

了解常用测试模型 -- V模型、W模型

目录 V模型 测试流程 特点 优、缺点 w模型/双v模型 测试流程 特点 优、缺点 V模型 测试流程 用户需求&#xff1a;产品经理将用户需求转变为软件需求 需求分析与系统设计&#xff1a;验证需求是否正确&#xff0c;确定编程语言和框架 概要设计&#xff1a;项目结构设…

大语言模型系列-中文开源大模型

文章目录 前言一、主流开源大模型二、中文开源大模型排行榜 前言 近期&#xff0c;OpenAI 的主要竞争者 Anthropic 推出了他们的新一代大型语言模型 Claude 3&#xff0c;该系列涵盖了三个不同规模的模型&#xff1a;Opus、Sonnet 和 Haiku。 Claude 3声称已经全面超越GPT-4。…

Antd组件Input在暗黑模式下,autoComplete导致的背景色问题

Antd的组件暗黑模式&#xff0c;默认Input的背景色是暗黑的&#xff0c;但是浏览器支持自动填充功能的话&#xff0c;就会变成这样&#xff0c;看着就难受 两种解决方法&#xff1a; 一、关闭自动填充功能 <Input autoComplete"off" /> 二、添加样式&#x…

使用 ZipArchiveInputStream 读取压缩包内文件总数

读取压缩包内文件总数 简介 ZipArchiveInputStream 是 Apache Commons Compress 库中的一个类&#xff0c;用于读取 ZIP 格式的压缩文件。在处理 ZIP 文件时&#xff0c;编码格式是一个重要的问题&#xff0c;因为它决定了如何解释文件中的字符数据。通常情况下&#xff0c;Z…

[.NET项目实战] Elsa开源工作流组件应用(一): Elsa工作流简介

Elsa工作流简介 工作流是什么&#xff1f; 引用维基百科中对工作流的解释&#xff1a; 是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。工作流建模&#xff0c;即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算…

考研模拟面试-答案【攻略】

考研模拟面试-答案【攻略】 前言版权推荐考研模拟面试-答案前面的问题通用问题专业题数据结构计算机网络操作系统数据库网络安全 手写题数据结构操作系统计算机网络 代码题基础代码题其他代码题 后面的问题补充题目 基础代码题答案链栈循环队列1循环队列2哈希表 最后 前言 202…

软件测试 —— 案例系统缺陷报告

知识&#xff1a; 1、缺陷等级&#xff1a; 1-Urgent(致命错误)&#xff1a;影响全局的死机、通信中断、重要业务不能完成 2-Very High(严重错误)&#xff1a;规定的功能没有实现或不完整或产生错误结果&#xff1b;使系统不稳定、或破坏数据等 3-High(一般错误)&#xff1a;…

如何成为一名优秀的硬件工程师

求知若饥&#xff0c;大智如愚&#xff0c;这是乔布斯说的&#xff0c;很多工程师把这句话作为工程师的最基本的职业素养。 “工程师是科学家&#xff1b;工程师是艺术家&#xff1b;工程师也是思想家。”实际上&#xff0c;工程师是利用自然科学来创造工程的人。工程既是物质…

DirectShowPlayerService::doSetUrlSource: Unresolved error code 0x800c000d

报出这个问题&#xff0c;应该是对给的url解析不正确&#xff0c;我给的是rtsp的视频流地址&#xff0c;应该是对该格式解析异常。 所以参考两篇文&#xff1a; QT无法播放视频&#xff1a;报错&#xff1a;DirectShowPlayerService::doRender: Unresolved error code 0x8004…