c语言在结构体之前定义变量,C语言结构体史上最详细的讲解

struct结构体数据类型

前言

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

int

float

long

double

string(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

outputstruct.c:8:1: 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 : %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);   /* print Book2 info */

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;

}

编译并执行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 : %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);

}

编译运行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 : %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);

}

编译运行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 : %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);

}

编译运行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("%d\n", (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("%d\n", (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("%d\n", (int) sizeof(struct packed_struct));    return 0;

}

作者:shellhub

链接:https://www.jianshu.com/p/d2c666527954

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值