六、结构体

6.1 结构体概念

  • 结构体(struct):是由一系列具有相同类型或不同类型的数据构成的数据集合。
  • “结构”是一种构造类型,它是由若干“成员”组成的。
  • 每一个成员可以是一个基本数据类型或者又是一个构造类型。
  • 结构即是一种“构造”而成的数据类型, 那么在说明和使用之前必须先定义它,也就是构造它。

6.2 C++语言中的结构体

6.2.1 结构体的声明和定义

  • 声明一个结构体类型的一般形式为:

    • struct 结构体名{
          成员列表;
      };
    • eg:
      struct Stu{//Stu是声明的一个结构体类型名
          int score;//整型成员变量
          int math;//整型成员变量
          char name[10];//字符型成员变量
      };
    • struct为结构体关键字,上面只是声明了一个结构构造类型Stu
    • int,float类似,Stu是一个类型名,可以定义结构体变量
    • 类型声明只是告诉系统此类型的构造形式,并不会实际分配内存
    • 注意:结构体的声明和定义必须以分号结束。
  • 定义结构后,便可以创建这种类型的变量了:
    Stu a;//定义一个结构体变量a
    Stu hat;//定义一个结构体变量hat
  • (2) 示例代码
    1. 此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c,但没有标明其标签,声明了结构体变量s1

      struct {
          int a;
          char b;
          double c;
      } s1;//s1是结构体变量
    2. 此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c,结构体的类型名被命名为Stu,另外定义了变量t1, t2[20], *t3
      struct Stu{
          int a;
          char b;
          double c;
      };
      Stu t1, t2[20], *t3; 
    3. 可以用typedef创建新类型,此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c,结构体的标签被命名为Simple2,用Simple2作为类型声明新的结构体变量u1, u2[20], *u3
      typedef struct Simple{//Simple是结构体类型名
          int a;
          char b;
          double c;
      } Simple2;//注意:Simple2也是结构体类型名,相当于Simple的别名
      Simple2 u1, u2[20], *u3;//若去掉typedef则编译报错,error C2371: “Simple2”: 重定义;不同的基类型
    4. 同类型的结构体可以直接赋值。
      struct Stu{
          int score;
          int math;
          char name[10];
      };
      Stu a,b={100,50,"Tom"};
      a=b;//正确,a,b是同为Stu类型的结构题变量

6.3 结构体内存分配机制

  • 结构体和其他的数据类型是一样的,在定义一个结构体的时候,系统并不会真正的分配内存空间,只有在定义变量的时候,才会分配。
  • 结构体对于成员变量的内存分配有以下要求:
  1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除
  2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
  3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节
  4. 例如:
    • struct Stu {
        char a;
        int b;
        char c;
      };
      1. Stu中,最宽数据类型为int,在32位系统中为4Byte);
      2. 参照第二条,第一个数据是char,存储一个char1 Byte ,要保证下一个int的存储起始地址是4的整数倍,所以要在char后面填充 3 Byte,然后再存储int 变量 b
      3. 最后一个也是char 类型,他就占1 Byte ,肯定是他存储位置的整数倍
      4. 最后参照第三条,结构体的总大小为最宽数据类型的整数倍,所以会在第二个char 之后再填充3 Byte
      5. 这样的话,总共占据的空间是1+3+4+1+3 = 12(红色为填充字节)
    • 但是,调换一下结构中数据成员的顺序:
      struct s1 {
        int b;
        char a;
        char c;
      };
      • 同样地分析4+1+1+2 = 8
      • 相比之下,存储空间的效率提高33%。
      • 提示:在竞赛阶段,为了节约内存,在组织数据结构的数据成员的时候,可以将相同类型的成员放在一起,这样就减少了编译器为了对齐而添加的填充字符。

6.4 结构体初始化

  1. 定义时初始化
struct Stu{
    int Num;
    bool Sex;
    char Name[20];
};
//定义时初始化
Stu a={0};//初始化所有成员为0
Stu b={15,1,"Tom"};//依次为成员赋值
  1. 构造函数初始化
方法一:
struct Stu{
    int Num;
    bool Sex;
    char Name[20];
    //构造函数初始化
    Stu(){
        Num=0;
        Sex=false;
        memset(Name,0,sizeof(Name));
    }
};
方法二:
struct Stu{
    int Num;
    bool Sex;
    char Name[20];
    //构造函数初始化
    Stu(){
        memset(this->Name,0,sizeof(Name));
    }
};
  1. 结构体成员的访问可以使用成员运算符:"."
struct Stu{
    int Num;
    bool Sex;
    char Name[20];
    //构造函数初始化
    Stu(){
        memset(this,0,sizeof(Name));
    }
};
Stu a;
//访问结构体a的成员函数
a.Num=10;
a.Sex=1;
a.Name="Tom";

6.5 结构体重载运算符重载

6.5.1 运算符重载

  • 基本概念

    1. 重载的运算符是具有特殊名字的函数
    2. 由关键字 \(operator\) 和要重载的运算符号共同组成。\(eg: operator +()\)
    3. 重载运算符也包含返回类型、参数列表以及函数体
    4. 重载运算符函数的参数数量与该运算符作用的运算对象数量一样多。(一元运算符有一个参数,二元有两个参数)
    5. 如果运算符函数是成员函数,则它的第一个运算对象绑定到隐式的 \(this\) 指针上,因此显式的参数比实际参数少一个
    6. 只能重载已有的运算符,无权发明新的运算符
    7. 可以重载绝大多数运算符。(不能重载 ::..* ,?: )
    8. 通常情况下,不应重载逗号、取地址、逻辑与、逻辑或运算符

6.5.2 结构体重载运算符重载

  • 结构体是构造类型,是无法直接进行逻辑运算、四则运算等,如果需要,我们可以对相应的运算符进行重载

    • 结构体重载小于号 "<"
    • struct Stu{
          int score;//总分
          int math;//数学
          char Id[maxn];//学号
          //方式一:作为成员函数重载,二元运算符,省略第一个参数,第一个const表示形参为只读,第二个const表示
          //不允许修改成员变量,固定格式。
          bool operator <(const Stu &a)const{
              if(score==a.score){//如果总分相等按数学进行比较
                  //如果总分、数学都相等按学号进行比较
                  if(math==a.math)return (strcmp(Id,a.Id)<0);
                  //如果总分相等,数学不等,数学进行比较
                  return math>a.math;
              }
              //如果总分不等,按总分进行比较
              return score>a.score;
          }
      };
      //方法二:全局重载
      bool operator <(const Stu &a,const Stu &b){
           if(a.score==b.score){//如果总分相等按数学进行比较
               //如果总分、数学都相等按学号进行比较
               if(a.math==b.math)return (strcmp(a.Id,b.Id)<0);
               //如果总分相等,数学不等,数学进行比较
               return a.math>b.math;
           }
              //如果总分不等,按总分进行比较
           return a.score>b.score;
      }
    • 结构体重载小于号 "+"
      struct Stu{
          int score;//总分
          int math;//数学
          //方式一:作为成员函数重载,二元运算符,省略第一个参数,第一个const表示形参为只读,第二个const表示
          //不允许修改成员变量,固定格式。tongxue
          Stu operator +(const Stu &a)const{
              Stu temp;//临时结构体变量
              temp.score=this->score+a.score;//this->score等价与score表示改结构题的score成员变量
              temp.math=this->math+a.math;
              rerturn temp;//计算后的结构变量
          }
      };
      //全局重在略……
  • 结构体成员函数和构造函数
    struct Stu{
        int score;//总分
        int math;//数学
        char Id[maxn];//学号
        //创建结构题时会自动创建一个默认的同名构造函数,构造函数在定义变量时会自动调用
        Stu(){
            memset(this,0,sizeof(Stu));
        }
        //成员函数,需要调用才会执行
        void Init(){
            memset(this,0,sizeof(Stu));
        }
        //成员函数是自己定义的实现某些功能的函数,需要调用才能使用
        void Print(){
            printf("%s\n",Id);
        }
    }a;
    //调用
    a.Init();
    a.Print();
  • 有能力的同学可以尝试这重载一下高精度加、减、乘法。
    struct Stu{
      int a[maxn];
      Stu(){
          memset(this,0,sizeof(Stu));
      }
      //重载赋值语句
      Stu operator =(const Stu &b){
          for(int i=0;i<=b.a[0];++i)
              a[i]=b.a[i];
          return *this;
      }
      //重载赋值语句
      Stu operator +(const Stu &b){
          Stu c;
          int i=1;
          while(i<=a[0] || i<=b.a[0]){
              c.a[i]+=a[i]+b.a[i];
              c.a[i+1]=c.a[i]/10;
              c.a[i]%=10;
              ++i;
          }
          if(c.a[i])c.a[0]=i;
          else c.a[0]=i-1;
          return c;
      }
      void read(){
          char s[maxn];
          scanf("%s",s);
          a[0]=strlen(s);
          for(int i=0;i<a[0];++i)
              a[a[0]-i]=s[i]-48;
      }
      void Print(){
          for(int i=a[0];i>0;--i)
              printf("%d",a[i]);
          printf("\n");
      }
    };
    

原文地址:https://www.cnblogs.com/hbhszxyb/p/12232125.html

时间: 2024-10-09 18:56:55

六、结构体的相关文章

C语言:SWUST OJ,程序设计C 实验六 结构体 题目三 学生结构体链表(0068)

Description: 用结构体建立学生信息,学生信息包括学号.姓名.成绩,建立一个有 n 名学生的链表, 并将链表输出. Input: 一次输入学生信息包括学号.姓名.0 0 0结束程序. Sample Input: C1001 Li 70 M1002 He 89 E1003 Xie 83 M1004 Wu 92 E1005 Bao 80 Sample Output: C1001 Li 70 M1002 He 89 E1003 Xie 83 M1004 Wu 92 E1005 Bao 80

C语言(六)结构体

一.结构体概述 1.简介 结构体是一种数据类型,存储的元素可以使不同的数据类型. 结构体的组成元素,一般称为结构体成员. 2.定义 struct 结构体名{ 类型名1 成员名1; 类型名2 成员名2; -- 类型名n 成员名n; }; 3.定义结构体类型 struct Student { char *name; // 姓名 int age; // 年龄 float height; // 身高 }; 4.定义结构体变量 1)先定义结构体类型,再定义变量 2)在定义结构体类型的同时定义变量 3)直接

ios开发中的C语言学习—— 结构体简介

在开发过程中,经常会需要处理一组不同类型的数据,比如学生的个人信息,由姓名.年龄.性别.身高等组成,因为这些数据是由不同数据类型组成的,因此不能用数组表示,对于不同数据类型的一组数据,可以采用结构体来进行存储.当然,对于面向对象的语言来说,最好是用类来表示,但是C语言是面向过程的,因此选择用结构体来表示. 一.结构体的定义 struct 结构体名{ 类型名 成员名1; 类型名 成员名2; ... ... 类型名 成员名n; }; 二.结构体的变量声明 1.先定义结构体类型,再定义变量 代码 //

OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)

OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-while) 跳跃(discard, return, break, continue) 6.1函数定义   着色器是由一系列全局声明和函数定义组成的.函数声明规范如下: // prototype returnType functionName (type0 arg0, type1 arg1, ...,

【非凡程序员】 OC第六节课 (枚举,字典,结构体,NSRange,CG类型,NSnumber,空)

#import <Foundation/Foundation.h>#import "Article.h"#import "Person.h" int main(int argc, const char * argv[]) {    @autoreleasepool { //自动释放池 (半自动) //-------------------------枚举类---------------------------------//     NSArray *p

C++ 结构体(六)

1.结构体和指针 指向结构体变量的指针 定义形式:struct  结构体名   *结构体指针名; 例如:struct  student      *p; struct  student { int  num; char name[20]; char sex; int age; }stu; struct  student   *p = &stu; p->num = 15; 在main函数中定义一个struct  student类型的指针p p->num = 15;是给num赋值. 例子:

FFmpeg总结(六)AV系列结构体之AVPacket

AVPacket位置:libavcodec/avcodec.h下: AVPacket: 通常通过demuxer导出的data packet作为解码器的input data 或是收到来自编码器的data packet,通过muxer进入输出的output data 看如下图,更易理解: 对于视频来说,它通常应该包含一个压缩的帧,对于音频,可能包含多个压缩帧,允许编码器输出为空的packet,没有压缩数据,只包含数据(如一些更新参数的编码) AVPacket 是FFmpeg中为数不多的结构体,它的s

C++学习笔记(六)--结构体

1.一种自定义的类型--结构体定义: struct 结构体名称 { //成员表列也称作域 还可以包括函数,即函数成员,不过一般结构体类型中不包含,而是放在类中. 类型名 成员名; };这种结构体类型类似于数据库中的记录例: struct Me{ char name[20]; char IDnumber[20]; int age; };此时只是声明了一个Me类型,并未在内存中分配存储单元,只有定义了结构体类型的变量后,才会分配内存,类似int,float这些类型一样. 2.声明结构体变量的方法:

C#调用C++ 平台调用P/Invoke 结构体--含有内置数据类型的一维、二维数组、字符串指针【六】

[1]结构体中含有内置数据类型的一维数组 C++代码: typedef struct _testStru3 { int iValArrp[30]; WCHAR szChArr[30]; }testStru3; EXPORTDLL_API void Struct_ChangeArr( testStru3 *pStru ) { if (NULL == pStru) { return; } pStru->iValArrp[0] = 8; lstrcpynW(pStru->szChArr, L&quo

iOS开发之oc(十六)--Foundation(1)结构体

(一)要掌握这些的运用 NSRange(location length) ---范围                                    range:范围 NSPoint\(相当于)CGPoint ---点 NSSize\CGSize   ---尺寸 NSRect\CGRect (CGPint CGSize) ---相当于一个矩形 其实,看官方文档更能清楚,这些的用法,需要声明方法就Jump to去看,在此,仅仅列出简单用法,作为了解 (二)代码示例 1. void range