C语言-结构体与位域

简介: C语言-结构体与位域

1. 结构体介绍

C语言里的结构体是可以包含不同数据类型和相同数据类型的一个有序集合,属于构造类型,可以自己任意组合,并且结构体里也可以使用结构体类型作为成员。


结构体在项目开发中使用非常多,无处不在,有了结构体类型就可以设计很多框架,模型,方便数据传输,存储等等。


结构体定义语法

  struct 结构体名称
{
    数据类型1 成员名1;
    数据类型2 成员名2;
    数据类型3 成员名3;
    .....
};
结构体的名称命名规则: 和普通变量命名规则一样—遵循C语言变量命名标准。
                       ‘A’~‘Z’ ‘a’~ ’z’  ‘0’~’9’  _

示例代码:

struct app
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
};
上面这一块代码表示定义(声明)一个新的结构体类型。  数据类型名称:struct app

2. 如何使用结构体定义变量?

结构体定义变量有3种形式:

#include <stdio.h>
//第一种形式:在定义结构体类型的时候同时定义变量
struct app1
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}a1,a2,a3;   //a1 a2 a3就是定义的结构体变量
//第二种形式
struct app2
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
};
//第三种形式: 匿名方式定义结构体
struct
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}c1,c2,c3;  //c1 c2 c3就是定义的结构体变量
int main()
{
    //使用结构体类型定义变量
    struct app2 b1;
    struct app2 b2;
    struct app2 b3;
    return 0;
}

3. 结构体的赋值

结构体变量的赋值语法:

 结构体变量名.成员名=xxx;

结构体初始化赋值说明:

结构体只能在(定义结构体变量的时候)初始化的时候支持整体赋值,之后就只能按照成员单个赋值。

注意:结构体变量之间支持直接赋值。

#include <stdio.h>
#include <string.h>
//第一种形式:在定义结构体类型的时候同时定义变量
struct app1
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}a1={23,"小白",5678},a2,a3={12,"小明",1234};   //a1 a2 a3就是定义的结构体变量
//第二种形式
struct app2
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
};
int main()
{
    //使用结构体类型定义变量
    struct app2 b1={15,"小李",6878};
    struct app2 b2;
    struct app2 b3;
    //单个修改结构体成员变量的值
    b1.age=18;
    //b1.name="555";
    strcpy(b1.name,"小丽");
    printf("b1:%d\n",b1.age);
    printf("b1:%s\n",b1.name);
    printf("a1:%d\n",a1.age);
    printf("a1:%s\n",a1.name);
    //结构体变量之间支持直接赋值 (要保证变量的类型要一致)。
   //int a=100;
   //int b;
   //b=a;
   b2=b1;  //将b1结构体变量赋值给b2结构体变量
   printf("b2:%d\n",b2.age);
   printf("b2:%s\n",b2.name);
    return 0;
}

4. 结构体指针定义与使用

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct app
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}; 
int main()
{
    struct app a1;   //定义一个结构体变量
    struct app *p1;  //定义一个结构体指针
    struct app *p2;  //定义一个结构体指针
    p1=&a1;  //地址赋值  p1指向a1的空间
    //申请堆空间
    p2=malloc(sizeof(struct app));
    //通过指针访问成员
    p1->age=20;
    strcpy(p1->name,"小红");
    p1->number=1234;
    //输出数据
    printf("姓名:%s\n",p1->name);
    printf("学号:%d\n",p1->number);
    printf("年龄:%d\n",p1->age);
     //通过指针访问成员
    p2->age=13;
    strcpy(p2->name,"小李");
    p2->number=5678;
    //输出数据
    printf("姓名:%s\n",p2->name);
    printf("学号:%d\n",p2->number);
    printf("年龄:%d\n",p2->age);
    //释放空间
    free(p2);
    return 0;
}

5. 结构体数组定义与使用

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct app
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}; 
int main()
{
    //定义一个结构体数组
    struct app buff[10];  //一次定义了10个结构体变量
    struct app *p=buff;  //定义一个结构体指针
    //访问成员
    buff[0].age=10;
    strcpy(buff[0].name,"小米");
    buff[0].number=1234;
    //打印数据
    printf("姓名:%s\n",buff[0].name);
    printf("学号:%d\n",buff[0].number);
    printf("年龄:%d\n",buff[0].age);
    printf("姓名:%s\n",p[0].name);
    printf("学号:%d\n",p[0].number);
    printf("年龄:%d\n",p[0].age);
    return 0;
}

6. 结构体当做函数的形参和返回值

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct app
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}; 
struct app *func_stu(struct app *p);
int main()
{
    //定义一个结构体数组
    struct app buff[10];  //一次定义了10个结构体变量
    //调用函数
    func_stu(&buff[0]);
    //打印数据
    printf("姓名:%s\n",buff[0].name);
    printf("学号:%d\n",buff[0].number);
    printf("年龄:%d\n",buff[0].age);
    return 0;
}
//定义函数
struct app *func_stu(struct app *p)
{
   //访问成员
    p->age=10;
    strcpy(p->name,"小米");
    p->number=1234;
    return p;
}

7. typedef关键字在结构体里使用方法

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct app
{
    int age; //年龄
    char name[100]; //姓名
    int number; //学号
}STU;  //STU叫结构体类型,相当于struct app的别名。  struct app == STU
STU *func_stu(STU *p);
int main()
{
    //定义一个结构体数组
    STU buff[10];  //一次定义了10个结构体变量
    //调用函数
    func_stu(&buff[0]);
    //打印数据
    printf("姓名:%s\n",buff[0].name);
    printf("学号:%d\n",buff[0].number);
    printf("年龄:%d\n",buff[0].age);
    return 0;
}
//定义函数
STU *func_stu(STU *p)
{
   //访问成员
    p->age=10;
    strcpy(p->name,"小米");
    p->number=1234;
    return p;
}

8. 结构体位域

位域用的不多,但是也有地方使用,主要是节省空间。

#include <stdio.h>
struct app
{
    unsigned int a:12;  //定义位域,指定位宽   12的单位是位
    unsigned int b:16;
    unsigned char c:1; //定义空间存储1位的数据。  1和0
    unsigned int :5;   //位域的名称可以省略掉,为了空间内存对齐而存在的
};
/*
1. 位域的大小不能超出本来数据类型大小。
2. 位域的名称可以省略掉,为了空间内存对齐而存在的
3. 位域的成员无法取地址操作
*/
int main()
{
    struct app data;
    //data.c=2;  错误 超出范围   只能存放0~1
    //data.b=65535;   错误 超出范围   只能存放0~65535
    // data.a=4096; 错误 超出范围   只能存放0~65535
    //printf("%d\n",data.c);
   // printf("%d\n",data.b);
    //printf("%d\n",data.a);
    //printf("%d\n",&data.a);   //错误 位域的成员无法取地址操作
    data.c=1;
    data.b=555; //只能存放0~65535
    data.a=888; //只能存放0~65535
    printf("%d\n",data.c);
    printf("%d\n",data.b);
    printf("%d\n",data.a);
    return 0;
}

9. 结构体的内存对齐

9.1 示例1: 计算结构体内存对齐

#include <stdio.h>
struct app
{
   int a1;
   char a2;
   char a3;
   char a4;
   char a5;
   char a6;
   char a7;
};
/*
目前32位系统里,使用的是gcc编译器。
开空间的对齐原理:以结构体里出现的最大数据类型的倍数开空间,最大是4个字节。
*/
int main()
{
    struct app data;
    printf("空间大小:%d 字节\n",sizeof(struct app)); //8
    return 0;
}
//func("1",1123,45,"45",123.45,'A');
void func(char *p,...)
{
}

9.2 示例2: 计算结构体内存对齐

#include <stdio.h>
#if 0
struct app
{
   char a1;  //1
   short a2; //2
};
最终占用空间大小4个字节
#endif
#if 0
struct app
{
   int a1[10];   //4*10=40
   char a2[10];  //12
   int a3;      //4
   float a4;   //4
   char a5;   //4
};
//最终占用空间大小64个字节
#endif
#if 1
struct app
{
   int a1;
   double a2;
};
//最终占用空间大小64个字节
#endif
/*
目前32位系统里,使用的是gcc编译器。
开空间的对齐原理:以结构体里出现的最大数据类型的倍数开空间,最大是4个字节。
*/
int main()
{
    struct app data;
    printf("空间大小:%d 字节\n",sizeof(struct app)); //8
    return 0;
}
//func("1",1123,45,"45",123.45,'A');
void func(char *p,...)
{
}

9.3 输出结构体变量成员的地址,查看空间对齐情况

#include <stdio.h>
struct app
{
   int a1[10];   //4*10=40
   char a2[10];  //12
   int a3;      //4
   float a4;   //4
   char a5;   //4
};
//最终占用空间大小64个字节
int main()
{
    struct app data;
    //输出地址   查看空间对齐原理
    printf("%#x\n",data.a1);
    printf("%#x\n",data.a2);
    printf("%#x\n",&data.a3);
    printf("%#x\n",&data.a4);
    printf("%#x\n",&data.a5);
    return 0;
}

9.4 对齐结构体进行强制对齐

#include <stdio.h>
#pragma pack(1)  //1 2 4 8
struct app
{
   int a1[10];   //4*10=40
   char a2[10];  //1*10=10
   int a3;      //4
   float a4;   //4
   char a5;   //1
};
int main()
{
    struct app data;
    //输出地址   查看空间对齐原理
    printf("%#x\n",data.a1);
    printf("%#x\n",data.a2);
    printf("%#x\n",&data.a3);
    printf("%#x\n",&data.a4);
    printf("%#x\n",&data.a5);
    printf("%d\n",sizeof(struct app));
    return 0;
}
目录
相关文章
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
1322 14
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
876 10
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
2089 13
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
671 12
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
454 4
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
723 10
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
1116 1
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。