0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言结构体史上最详细的讲解【软件干货】

哈哈hfgfdf 来源:嵌入式学习资料 作者:嵌入式学习资料 2024-03-28 17:52 次阅读

struct结构体数据类型

前言

我们知道,在C语言中有一些基本的数据类型,如charintfloatlongdoublestring(c99)

等等数据类型,他们可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型明显就无法满足需求了,这时候C提供了一种自定义数据类型,他可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct,可以使用struct关键词声明结构体

结构体的声明

结构体的声明语法如下

struct [structure tag] /*结构体的标签*/{

   member definition; /*零个或多个成员变量的定义*/
   member definition;
   ...
   member definition;
} [one or more structure variables];  /*一个或多个结构体变量的定义*/

结构体标签(structure tag)是可选的,但是推荐还是写上,这样使得代码更加规范清晰,成员变量的定义一般为基本数据类型,如int age;char name[10]等,成员变量之间使用;隔开,最后一个成员变量后面的;可选, 如下面定义一个图书信息的结构体变量

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

如下所示

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id
} book;

我省略了最后一个成员变量后面的分号;代码可以正常运行,但是当我使用gcc编译的时候,出现了下面信息

gcc struct.c
```
 output
``` shell
struct.c1: warning: no semicolon at end of struct or union
 } book;
 ^

这是警告提示,提示我们需要在struct和union数据类型定义的后面加上分号;,这样的好处就是当我们需要再添加一个成员变量的时候,只需写上该成员变量的定义,而无需先敲;,我太机智了,手动滑稽...

没有成员变量的结构体

我们也可以定义一个空的结构体,有时候我们需要某一个结构体数据类型,但是暂时又不知道如何填充里面的成员变量,我们可以有如下定义

struct Books {
  //TODO
} book;

访问结构体成员

定义完结构体积后接下来就是去访问它并给他赋值,为了访问一个结构体成员变量,我们可以使用成员操作符(.)成员访问运算符被编码为结构变量名称和我们希望访问的结构成员之间的句点(.)如下所示的完整代码

struct.c

#include 
#include 

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */

   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;

   /* print Book1 info */
   printf( "Book 1 title : %sn", Book1.title);
   printf( "Book 1 author : %sn", Book1.author);
   printf( "Book 1 subject : %sn", Book1.subject);
   printf( "Book 1 book_id : %dn", Book1.book_id);

   /* print Book2 info */
   printf( "Book 2 title : %sn", Book2.title);
   printf( "Book 2 author : %sn", Book2.author);
   printf( "Book 2 subject : %sn", Book2.subject);
   printf( "Book 2 book_id : %dn", Book2.book_id);

   return 0;
}

编译并执行

gcc struct.c && ./a.out

输出

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 
#include 

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* function declaration */
void printBook( struct Books book );

int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */

   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;

   /* print Book1 info */
   printBook( Book1 );

   /* Print Book2 info */
   printBook( Book2 );

   return 0;
}

void printBook( struct Books book ) {

   printf( "Book title : %sn", book.title);
   printf( "Book author : %sn", book.author);
   printf( "Book subject : %sn", book.subject);
   printf( "Book book_id : %dn", book.book_id);
}

编译运行

gcc struct.c && ./a.out

输出

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

结构体的指针

我们也可以定义结构体指针,像这样

struct Books *struct_pointer;

现在你可以存放结构体变量的地址在结构体变量指针中.和基本数据类型的变量一样,我们使用&操作符取一个变量的地址

struct_pointer = &Book1;

接下来就是使用结构体指针去访问成员变量了,访问的操作符我们由原来的.变为->,没错,这个是不是很形象呢?完整代码如下

#include 
#include 

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* function declaration */
void printBook( struct Books *book );
int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */

   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;

   /* print Book1 info by passing address of Book1 */
   printBook( &Book1 );

   /* print Book2 info by passing address of Book2 */
   printBook( &Book2 );

   return 0;
}

void printBook( struct Books *book ) {

   printf( "Book title : %sn", book->title);
   printf( "Book author : %sn", book->author);
   printf( "Book subject : %sn", book->subject);
   printf( "Book book_id : %dn", book->book_id);
}

编译运行

gcc struct.c && ./a.out

输出

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 
#include 

struct Books {
    char  title[50];
    char  author[50];
    char  subject[100];
    int   book_id;
};

/* function declaration */
void printBook( struct Books *book );
int main( ) {

    struct Books books[2];

    /* book 1 specification */
    strcpy( books[0].title, "C Programming");
    strcpy( books[0].author, "Nuha Ali");
    strcpy( books[0].subject, "C Programming Tutorial");
    books[0].book_id = 6495407;

    /* book 2 specification */
    strcpy( books[1].title, "Telecom Billing");
    strcpy( books[1].author, "Zara Ali");
    strcpy( books[1].subject, "Telecom Billing Tutorial");
    books[1].book_id = 6495700;

    /* print Book1 info by passing address of Book1 */
    printBook( &books[0] );

    /* print Book2 info by passing address of Book2 */
    printBook( &books[1] );

    return 0;
}

void printBook( struct Books *book ) {

    printf( "Book title : %sn", book->title);
    printf( "Book author : %sn", book->author);
    printf( "Book subject : %sn", book->subject);
    printf( "Book book_id : %dn", book->book_id);
}

编译运行

gcc struct.c && ./a.out

输出

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 
#include 

struct Books {
};

int main( ) {
    printf("%dn", (int) sizeof(struct Books)); /*0*/
    return 0;
}
#include 
#include 

struct Books {
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
};

int main() {
    printf("%dn", (int) sizeof(struct Books)); /*204*/
    return 0;
}

位域

有时候我们内存紧张的时候,我们可以使用位域定义结构体成员变量,比如当我们需要定义一个表示true或false的时候,如果想这样定义

int isOpen;

明显很浪费空间,因为一个真假值只需要一个字位表示,所以我们可以这样定义

unsigned int isOpen:1;

但是如果你直接写在函数中是会报错的,我们应该写在结构体中

int main() {
    unsigned int isOpen:1; /*编译无法通过*/
    return 0;
}

正确姿势

struct packed_struct {
   unsigned int f1:1;
   unsigned int f2:1;
   unsigned int f3:1;
   unsigned int f4:1;
   unsigned int type:4;
   unsigned int my_int:9;
} pack;

C尽可能紧凑地自动打包上述位字段,前提是字段的最大长度小于或等于计算机的整数字长。如果不是这种情况,那么一些编译器可能允许字段存储器重叠,而其他编译器会将下一个字段存储在下一个字中。

#include 
#include 

struct packed_struct {
    unsigned int f1:1;
    unsigned int f2:1;
    unsigned int f3:1;
    unsigned int f4:1;
    unsigned int type:4;
    unsigned int my_int:9;
} pack;
int main() {
    printf("%dn", (int) sizeof(struct packed_struct));
    return 0;
}

输出结果 8

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7530

    浏览量

    128658
  • 结构体
    +关注

    关注

    1

    文章

    125

    浏览量

    10750
收藏 人收藏

    评论

    相关推荐

    关于学习stm32 C语言编程结构的使用

    大家好,本人最近学在学习stm32,但是发现大量的使用结构;之前玩51单片机的时候,基本不怎么用到过结构,突然间要用到这么多,有点措手不及,现在想补习一下
    发表于 08-08 23:58

    详细讲解c语言enum枚举类型

    详细讲解C语言enum枚举类型在实际应用中,有的变量只有几种可能取值。如人的性别只有两种可能取值,星期只有七种可能取值。在 C
    发表于 12-21 23:22

    C语言-结构对齐详解

    `C语言-结构对齐详解朱有鹏1、结构为何要对齐访问访问
    发表于 07-12 16:41

    嵌入式Linux 及C语言高级开发

    本帖最后由 慧心的眼眸 于 2018-4-3 13:54 编辑 [tr=transparent]本课程将在学员C语言基础知识之上,通过大量编程实例重点讲解C
    发表于 04-03 13:38

    漫谈C语言结构

      相信大家对于结构都不陌生。在此,分享出本人对c语言结构的学习心得。如果你发现这个总结中有
    发表于 11-15 15:59

    干货c语言基础语法——结构

    1、关于C语言结构的引入在实际问题中有时候我们需要几种数据类型一起来修饰某个变量。例如一个学生的信息就需要学号(字符串),姓名(字符串),年龄(整形)等等。这些数据类型都不同但是他们
    发表于 06-03 17:10

    如何利用C语言结构成员变量的地址?

    C语言,如何取结构成员变量的地址?发个列程好吗?我好研究一下
    发表于 11-04 03:31

    单片机C语言 -- 基于结构的面向对象编程技巧

    1、Keil4 C51工程网址:2、需要一定的C语言基础,才看得懂此文。一、面向对象单片机C语言的面向对象编程,是利用
    发表于 02-04 21:48

    C语言结构对函数指针封装示例

    C语言结构对函数指针封装示例示例:#include int i, j;struct DATE{ int year; char month; char data; char hour;
    发表于 07-15 06:18

    结构与共用的区别

    转载重点:共用的所有成员占用同一段内存,修改一个成员会影响其余所有成员。图形分析影响过程通过前面的讲解,我们知道结构(Struct)是一种构造类型或复杂类型,它可以包含多个类型不同
    发表于 07-20 06:57

    C语言结构在单片机中的应用有哪些?

    C语言的好处是什么?C语言结构在单片机中的应用有哪些?
    发表于 10-14 06:18

    单片机C语言串口传输结构是什么?

    单片机C语言串口传输结构是什么?
    发表于 10-14 06:44

    如何写单片机的C语言结构

    摘要:听说还有好多学单片机的小伙伴不会用结构?指针和结构是学单片机必须要掌握的,如果你C语言
    发表于 12-03 07:11

    结构的相关资料下载

    击上方“果果小师弟”,选择“置顶/星标公众号”干货福利,第一时间送达!摘要:听说还有好多学单片机的小伙伴不会用结构?指针和结构是学单片机
    发表于 01-07 08:25

    怎样去使用C语言结构和共用

    C语言结构和共用分别有何特点呢?怎样去使用C语言
    发表于 01-17 07:51