C语言结构体

1、结构体的概念

前面的教程中咱们讲解了变量和数组(array),变量是一个一个定义的,数组是一组具备相同类型的变量的集合。但在实际的工做和生活中,为了表达一个数据集,须要用不一样数据类型的变量。例如超女基本信息,姓名为字符串,身高和年龄为整数,体重为浮点数,身材和颜值为字符串,由于数据集各要素的数据类型不一样,不能用一个数组来存放。程序员

用咱们以前学过的知识,若是要存放超女信息,能够用多个变量,以下:数组

char name[51];   // 姓名
  int  age;        // 年龄
  int  height;     // 身高,单位:cm
  double weight;     // 体重,单位:kg
  char sc[31];     // 身材,火辣;普通;飞机场
  char yz[31];     // 颜值,漂亮;通常;歪瓜裂枣

这种方式有一个缺陷,若是某数据集有100个要素,就要定义100个变量,对100个变量初始化,把100个变量做为函数的参数传递,实在太麻烦。markdown

在C语言中,使用结构体(struct)来存放一组不一样类型的数据,语法以下:数据结构

struct 结构体名
{
  结构体成员变量一的声明;
  结构体成员变量二的声明;
  结构体成员变量三的声明;
  ......
  结构体成员变量四的声明;
};

结构体是一个集合,是一种构造的数据类型,是程序员为了描述一个数据集本身定义出来的数据类型。结构体的成员(member)能够是任意类型的变量,也能够是结构体变量。以超女为例:ide

struct st_girl
{
  char name[51];   // 姓名
  int  age;        // 年龄
  int  height;     // 身高,单位:cm
  int  weight;     // 体重,单位:kg
  char sc[31];     // 身材,火辣;普通;飞机场
  char yz[31];     // 颜值,漂亮;通常;歪瓜裂枣
};

2、结构体变量

结构体是一种程序员自定义的数据类型,是模板,能够用它来定义变量。例如:函数

struct st_girl queen, princess, waiting, workers;

定义了四个结构体变量,queen王后、princess王妃,waiting宫女和workers侍者。学习

3、占用内存的状况

理论上讲结构体的各个成员在内存中是连续存放的,和数组很是相似,可是,结构体的占用内存的总大小不必定等于所有成员变量占用内存大小之和。在编译器的具体实现中,为了提升内存寻址的效率,各个成员之间可能会存在缝隙。用sizeof能够获得结构体占用内容在总大小,sizeof(结构体名)或sizeof(结构体变量名)均可以。.net

示例(book90.c)3d

/*
 * 程序名:book90.c,此程序用于演示C语言的结构体占用内存的状况
 * 做者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年龄
  int  height;       // 身高,单位:厘米cm
  char sc[30];       // 身材,火辣;普通;飞机场。
  char yz[30];       // 颜值,漂亮;通常;歪瓜裂枣。
};

int main()
{
  struct st_girl queen;
  printf("sizeof(struct st_girl) %d\n",sizeof(struct st_girl));
  printf("sizeof(queen) %d\n",sizeof(queen));
}

运行效果指针

在这里插入图片描述

从上面的示例能够看出,struct st_girl所有成员变量占用的内存是50+4+4+30+30=118,可是结构体占用的内存是120。

注意,C语言提供告终构体成员内存对齐的方法,可使结构体成员变量之间的内存没有空隙,我暂时不介绍。

4、结构体的变量名

和数组不同,结构体变量名不是结构体变量的地址,结构体变量名就是变量名,就象int ii同样,只是不能直接输出,直接输出没有意义。取地址要用&,不用钻牛角尖,不直接输出就好了。

struct st_girl stgirl;
  printf("%d\n",stgirl);   // 没有意义。
  printf("%p\n",stgirl);   // 没有意义,结构体变量名不是结构体变量的地址。
  printf("%p\n",&stgirl);  // 这才是结构体的地址。

5、结构体初始化

采用memset函数初始化结构体,所有成员变量的值清零。

memset(&queen,0,sizeof(struct st_girl));

memset(&queen,0,sizeof(queen));

注意事项,若是把一个结构体的地址传给子函数,子函数用一个结构体指针(如struct st_girl *pst)来存放传入的结构体的地址,那么,在子函数中只能用如下方法来初始化结构体:

memset(pst,0,sizeof(struct st_girl));

不能用如下方法来初始化结构体:

memset(pst,0,sizeof(pst));

由于子函数中用sizeof(pst),获得的不是结构体占用内存的字节数,而是结构体指针变量占用内存的字节数(8字节)。

6、成员的访问(使用)

使用使用圆点.运算符能够访问(使用)结构的成员,结构体成员变量的使用与普通变量的使用相同。

示例(book92.c)

/*
 * 程序名:book92.c,此程序演示结构体的访问(使用)。
 * 做者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年龄
  int  height;       // 身高,单位:厘米cm
  char sc[30];       // 身材,火辣;普通;飞机场。
  char yz[30];       // 颜值,漂亮;通常;歪瓜裂枣。
};

int main()
{
  struct st_girl queen;  // 定义结构体变量

  // 初始化结构体变量
  memset(&queen,0,sizeof(struct st_girl));

  // 对结构体每一个成员赋值
  strcpy(queen.name,"武则天");
  queen.age=28;
  queen.height=168;
  strcpy(queen.sc,"火辣");
  strcpy(queen.yz,"漂亮");

  printf("姓名:%s\n",queen.name);
  printf("年龄:%d\n",queen.age);
  printf("身高:%d\n",queen.height);
  printf("身材:%s\n",queen.sc);
  printf("颜值:%s\n",queen.yz);
}

运行效果

在这里插入图片描述

7、结构体数组

结构体能够被定义成数组变量,本质上与其它类型的数组变量没有区别。

struct st_girl princess[6];
memset(princess,0,sizeof(princess));
strcpy(princess[0].name,"杨玉环");
princess[0].age=18;
strcpy(princess[1].name,"西施");
princess[1].age=28;
……

在实际开发中,咱们不多用结构体数组,C++标准库的vector容器是一个动态的结构体数组,比结构体数组更方便。

8、结构体指针

结构体是一种自定义的数据类型,结构体变量是内存变量,有内存地址,也就有结构体指针。

在指针章节中咱们已经学习过,采用不一样数据类型的指针指向不一样数据类型的变量的地址,这一规则也适用于结构体。以下:

struct st_girl queen;
struct st_girl *pst=& queen;

经过结构体指针可使用结构体成员,通常形式为:

(*pointer).memberName

或者:

pointer->memberName

第一种写法中,圆点.的优先级高于*,(*pointer)两边的括号不能少。若是去掉括号写做*pointer.memberName,那么就等效于*(pointer.memberName),这样意义就彻底不对了。

第二种写法中,-\>是一个新的运算符,习惯称它为“箭头”,有了它,能够经过结构体指针直接使用结构体成员;这也是-\>在C语言中的惟一用途。

上面的两种写法是等效的,程序员一般采用后面的写法,这样更加直观。

示例(book93.c)

/*
 * 程序名:book93.c,此程序演示结构体的指针
 * 做者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年龄
};

int main()
{
  struct st_girl *pst,queen;  // 定义结构体变量

  // 初始化结构体变量
  memset(&queen,0,sizeof(struct st_girl));

  pst=&queen;

  // 对结构体每一个成员赋值
  strcpy(pst->name,"武则天");
  pst->age=28;

  printf("姓名:%s,年龄:%d\n",queen.name,queen.age);
  printf("姓名:%s,年龄:%d\n",pst->name,pst->age);
  printf("姓名:%s,年龄:%d\n",(*pst).name,(*pst).age);
}

运行效果

在这里插入图片描述

9、结构体的复制

在C语言中,结构体的成员若是是基本数据类型(int、char、double)能够用=号赋值,若是是字符串,字符串不是基本数据类型,能够用strcpy函数赋值,若是要把结构体变量的值赋给另外一个结构体变量,有两种方法:1)一种是把结构体变量成员的值逐个赋值给另外一个结构体变量的成员,这种方法太笨,没人使用;2)另外一种方法是内存拷贝,C语言提供了memcpy(memory copy的简写)实现内存拷贝功能。

函数声明:

void *memcpy(void *dest, const void *src, size_t n);

参数说明:

src 源内存变量的起始地址。

dest 目的内存变量的起始地址。

n 须要复制内容的字节数。

函数返回指向dest的地址,函数的返回值意义不大,程序员通常不关心这个返回值。

示例(book94.c)

/*
 * 程序名:book94.c, 此程序演示采用memcpy函数复制结构体
 * 做者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年龄
};

void main()
{
  struct st_girl girl1,girl2;

  strcpy(girl1.name,"西施");  // 对girl1的成员赋值
  girl1.age=18;

  // 把girl1的内容复制到girl2中
  memcpy(&girl2,&girl1,sizeof(struct st_girl));

  printf("girl1.name=%s,girl1.age=%d\n",girl1.name,girl1.age);
  printf("girl2.name=%s,girl2.age=%d\n",girl2.name,girl2.age);
}

运行效果

在这里插入图片描述
你们可能想起了strcpy函数,与memcpy有类似之处,实际上这两个函数从功能和实现原理上完本不一样,甚至不该该放在一块儿比较。

1)复制的内容不一样,strcpy只能复制字符串,而memcpy能够复制任意内容,例如字符数组、整型、结构体、类等。

2)用途不一样,一般在复制字符串时用strcpy,而须要复制其余类型数据时则通常用memcpy。

3)复制的方法不一样,strcpy不须要指定长度,它遇到被复制字符的串结尾符0才结束,memcpy则是根据其第3个参数决定复制的长度。

10、结构体做为函数的参数

结构体是多个变量集合,做为函数参数时就能够传递整个集合,也就是全部成员。若是结构体成员较多,函数参数的初始化和赋值的内存开销会很大,影响程序的运行效率。因此最好的办法就是传递结构体变量的地址。

示例(book95.c)

/*
 * 程序名:book95.c,此程序演示结构体做为函数的参数。
 * 做者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年龄
};

// 对结构体赋值的函数
void setvalue(struct st_girl *pst);

int main()
{
  struct st_girl queen;  // 定义结构体变量

  // 初始化结构体变量
  memset(&queen,0,sizeof(struct st_girl));

  setvalue(&queen);  // 调用函数,传结构体的地址

  printf("姓名:%s,年龄:%d\n",queen.name,queen.age);
}

void setvalue(struct st_girl *pst)
{
  // 对结构体每一个成员赋值
  strcpy(pst->name,"武则天");
  pst->age=28;
}

运行效果

在这里插入图片描述

11、枚举和共同体

C语言还有两种数据结构:枚举和共同体,这两种数据结构的应用太少了,少到我已经记不起它们的定义,二十年来,我从未使用过,也不介绍了。

12、memset和bzero函数

一、memset函数

memset 函数是内存空间赋值函数,用来给某一块内存空间进行赋值的。

包含在\<string.h\>头文件中。

函数的声明以下:

void *memset(void *s, int v, size_t n);

s为内存空间的地址,通常是数组名或结构体的地址。

v为要填充的值,填0就是初始化。

n为要填充的字节数。

在实际开发中,程序员用memset函数对数组或结构体清零,在以前的章节中,咱们已经用过不少次了。

二、bzero函数

bzero函数是内存空间清零。

包含在\<string.h\>头文件中。

函数的声明以下:

void bzero(void *s, size_t n);

s为内存空间的地址,通常是数组名或结构体的地址。

n为要清零的字节数。

若是要对数组或结构体清零,用memset和bzero均可以,没什么差异,看程序员的习惯。

十3、课后做业

编写示例程序,把本章节介绍的知识点所有演示一遍,用程序演示能够加深您的理解和映象。

十4、版权声明

C语言技术网原创文章,转载请说明文章的来源、做者和原文的连接。
来源:C语言技术网(www.freecplus.net)
做者:码农有道

若是这篇文章对您有帮助,请点赞支持,或在您的博客中转发个人文章,谢谢!!!若是文章有错别字,或者内容有错误,或其余的建议和意见,请您留言指正,很是感谢!!!

相关文章
相关标签/搜索