C语言之结构体基础

什么是结构体

在C语言中,结构体是不同数据类型的元素的集合。该结构用于创建用户定义的数据类型。该结构也被称为“ C语言自定义类型”。换句话说,结构体是不同类型数据的集合。这种数据类型的名字是由用户自主定义的。通常结构体用于将不同数据类型的元素组合成一个组。结构体中定义的元素称为结构成员。在前面我们学习过基础的数据类型int float char 等,都只能用来表示基础的数据类型,那么要怎么来表示复杂的数据类型呢?比如下信息:

定义5个数组,然后通过数组下标一致性原则去描述上述表格数据是否可行? 当然没得问题,如下代码:

#include 
#include 
#include 
int main() 
{
  int ids[10] = { 0 };
  char names[10][10] = { 0 };
  char sexs[10][3] = { 0 };
  int ages[10] = { 0 };
  int scores[10] = { 0 };

  ids[0] = 100;
  strcpy(names[0], "欧阳疯");
  strcpy(sexs[0], "男");
  ages[0] = 18;
  scores[0] = 666;

  return 0;
}

看起来还不错,实际上很繁琐,在排序需要交换两者数据的时候极其繁琐,既然学生信息有很多,那么能不能定义一个学生类型呢?如果能,直接通过学生访问该学生的所有信息就很方便了!

C语言结构体创建

为了定义结构体,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

那么对于上面的学生的信息,就可以用如下结构体表示学生结构体类型:

#include 
#include 
#include 
struct Student 
{
    int id;    //学号
    char name[10];  //姓名
    char sex;    //性别
    int age;    //年龄
    int score;    //总分
};
int main() 
{

  return 0;
}

结构体中所有数据成员组成一个整体,形成一个新的数据类型,而不同变量则是零散内存,毫无关联,如下图:

C语言结构体访问

结构体中的数据必须要通过结构体变量访问,访问方式有以下两种:

结构体变量的创建

结构体类型已经声明,如何使用结构体类型定义结构体变量呢?有以下方法(typedef别名创建后续再讲):

如下测试代码:

#include 
#include 
struct MM
{
  char name[20];
  int age;
  double score;
}mm;       
//在声明结构体类型的同时定义变量mm
int main() 
{
  //先声明结构体类型再定义结构体变量
  //struct MM: 类型
  //girl: 变量名
  struct MM girl;
  return 0;
}

结构体变量的初始化

在定义结构体变量的同时通过{}的方式为每一个成员变量进行赋初值,赋初值主要有以下几种方式:

如下测试代码:

#include 
#include 
struct MM
{
  char name[20];
  int age;
  double score;
};       
int main() 
{
  
  //全部初始化,顺序必须一致
  struct MM girl = {"girl",18,99.1};  
  //部分初始化:未初始化部分自动初始化为0
  struct MM mm = { "gril" };
  //全部初始化为0
  struct MM zero = { 0 };
  //初始化指定的成员(可以初始化任意成员,不必遵循定义顺序)
  struct MM beauty = { .age = 18,.name = "beauty" };
  //用另一个结构体变量初始化
  struct MM woman = girl;
  return 0;
}

结构体数组

一个结构体变量可以存放一个学生的一组信息,可是如果有 10 个学生呢?难道要定义 10 个结构体变量吗?难道上面的程序要复制和粘贴 10 次吗?很明显不可能,这时就要使用数组。结构体中也有数组,称为结构体数组。它与前面讲的数值型数组几乎是一模一样的,只不过需要注意的是,结构体数组的每一个元素都是一个结构体类型的变量,都包含结构体中所有的成员项。

struct Student stus[10]; 这就定义了一个结构体数组,共有 10 个元素,每个元素都是一个结构体变量,都包含所有的结构体成员。

示例程序| 从键盘输入 5 个学生的基本信息,如学号、姓名、年龄、性别,将年龄最大的学生的基本信息输出到屏幕

#include 
struct Student
{
    int id;
    char name[10];
    int age;
    char sex;
};
int main()
{
    struct Student stus[10];
    printf("input stu>:
");
    for (int i = 0; i < 5; i++)
    {    
        scanf("%d %s %d %c", &stus[i].id, stus[i].name, &stus[i].age, &stus[i].sex);
    }
    struct Student maxStu = stus[0];
    for (int i = 0; i < 5; i++)
    {
        if (maxStu.age < stus[i].age)
        {
            maxStu = stus[i];
        }
    }
    printf("-------------Max---------------
");
    printf("%d %s %d %c
", maxStu.id, maxStu.name, maxStu.age, maxStu.sex);
    return 0;
}

程序测试结果如下:

当然对于这种表格数据操作有很多,例如排序,查找,文件保存等。详细参见结构体数组写管理系统。

结构体指针

当一个指针变量指向结构体时,我们就称它为结构体指针。C语言结构体指针的定义形式一般为:struct 结构体名 *变量名;

如下测试代码:

#include 
#include 
#include 
struct MM
{
  char name[20];
  int age;
  double score;
};       
int main() 
{
  struct MM girl = {"girl",18,99.1};  
  struct MM* pMM = NULL;
  //结构体指针指向结构体变量
  pMM = &girl;
  //指针用->访问
  printf("%s	%d	%.1lf
", pMM->name, pMM->age, pMM->score);
  //*pMM等效girl
  printf("%s	%d	%.1lf
", (*pMM).name, (*pMM).age, (*pMM).score);
  //结构体指针动态内存申请
  struct MM* pArray = (struct MM*)malloc(sizeof(struct MM)*3);
  assert(pArray);
  for (int i = 0; i < 3; i++) 
  {
    pArray[i] =(struct MM){ "张三",18,99.9 };
    printf("%s	%d	%.1lf
", pArray[i].name, pArray[i].age, pArray[i].score);
  }
  return 0;
}

程序测试结果如下:

基本上普通指针能做的,结构体指针一样的。只是在访问数据的时候需要剥洋葱(通过->访问每个数据)。当然也可以当做函数参数和返回值。

C语言位段

C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为位段。利用位段能够用较少的位数存储数据。基本语法如下:

struct 结构体名
{
      类型 位段名1 : 位段大小;
      类型 位段名2 : 位段大小;
      类型 位段名3 : 位段大小;
      类型 位段名4 : 位段大小;
      ...
};

C语言标准规定,只有有限的几种数据类型可以用于位段。

如下测试代码:

#include 
#include 
#include 
struct BitField
{
    unsigned char a : 1;
    unsigned char b : 4;
    unsigned char c : 3;
};
int main()
{
    //初始化
    struct BitField bit = { 1,2,3 };
    //输出
    printf("first:%d %d %d
", bit.a, bit.b, bit.c);
    //赋值
    //10    1位有效去掉最高位
    bit.a = 2;  
    //10100 4位有效去掉最高位
    bit.b = 20;  
    //1000  3位有效去掉最高位
    bit.c = 8;   
    //再次输出
    printf("last:%d %d %d
", bit.a, bit.b, bit.c);
}

程序测试结果如下:

位段注意项:

C语言结构体嵌套

在一个结构体内包含另一个结构体作为其成员,当然一般嵌套可以理解为一类数据的封装。访问的话逐步剥洋葱即可,定义方式有两种写法。

示例程序以结构体变量当做数据成员方式嵌套 | 给学生增加一个出生日期,包含年月日

#include 
#include 
#include 
struct Date
{
    short year;
    short month;
    short day;
};
struct Student
{
    int id;
    char name[10];
    struct Date birth;  //出生日期
};
int main()
{
    //数据完整的情况,{}可有可无
    struct Student baby = { 1001,"baby",{2008,3,17} };
    printf("%d	%s	%d-%d-%d
", baby.id, baby.name, 
        baby.birth.year, baby.birth.month, baby.birth.day);
    return 0;
}

示例程序直接把结构体定义在另一个结构体内| 给学生增加一个出生日期,包含年月日

#include 
#include 
#include 
struct Student
{
    int id;
    char name[10];
    struct Date
    {
        short year;
        short month;
        short day;
    }birth;//出生日期
};
int main()
{
    //数据完整的情况,{}可有可无
    struct Student baby = { 1001,"baby",{2008,3,17} };
    printf("%d	%s	%d-%d-%d
", baby.id, baby.name, 
        baby.birth.year, baby.birth.month, baby.birth.day);
    return 0;
}

C语言结构体内存对齐

什么是内存对齐

从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这就是内存对齐。通俗点讲就是厕所建坑位需要合理排布对齐,不然可能会存在只有半个坑的情况。

为什么要内存对齐

当然我们会不会算内存对齐其实并不重要,因为对于一个结构体占用内存一个sizeof即可搞定,重要的是大家要知道如何设计代码可以让内存更小,毕竟在特殊开发场景,内存占用是非常值得关注的。例如,网络传输,嵌入式等。

内存对齐规则

C语言标准并没有规定内存对齐的细节,而是交给具体的编译器去实现,但是对齐的基本原则是一样的。

如下测试代码:

#include 
#include 
//会不会算出结果不重要,重要是学会怎么写可以少内存即可
//按照从小到大即可 字符和整形写一块
struct Data1
{
  double score;    //8
  char name[3];       //补一位和int组成8位
  int age;
};
struct Data2
{
  char name[3];     //补 5位
  double score;     //8位
  int age;          //补4位
};

struct Data3
{
  char name[9];   //8+1  +3
  int num;        //4
  double score;   //8
  int age;        //4+3 5
  char tel[3];
};
struct Data4
{
  int age;
  char name[3];
  int num;
};
struct Data5
{
  char name[5];
  char num;
};
struct Data6
{
  char name[5];
  int* p;         //32位按照4个字节对齐,64位按照8位对齐
};
struct Data7
{
  struct Data4 data;   //12
  //char name[3];     //3+1
  double score;        //8
  int age;             //8
};
union Data8
{
  char name[20];
  double score;
};
int main()
{
  struct Data1* p = (struct Data1*)malloc(sizeof(struct Data1));
  printf("%zd
", sizeof(struct Data1));   //16
  printf("%zd
", sizeof(struct Data2));   //24
  //8 1w  8w 
  printf("%zd
", sizeof(struct Data3));   //32
  printf("%zd
", sizeof(struct Data4));   //12
  printf("%zd
", sizeof(struct Data5));   //6
  printf("%zd
", sizeof(struct Data6));   //16
  //C语言不允许空的结构体
  printf("%zd
", sizeof(struct Data7));   //32
  printf("%zd
", sizeof(union Data8));   //24
  return 0;
}

相关

如果阁下正好在学习C/C++,看文章比较无聊,不妨关注下关注下小编的视频教程,通俗易懂,深入浅出,一个视频只讲一个知识点。视频不深奥,不需要钻研,在公交、在地铁、在厕所都可以观看,随时随地涨姿势。

展开阅读全文

页面更新:2024-03-12

标签:语言   结构   初始化   变量   数据类型   定义   内存   成员   类型   基础   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top