介绍结构体

目录

一、前言

二、结构体详解 

(1)什么是结构体

(2)结构体的定义与基础结构

(3)结构体的使用

(3)结构体的初始化

(4)结构体的成员访问

(5)结构体数组

(6)结构体指针--------------指向结构体变量的指针(重点!!!!)

(7)结构体指针--------------指向结构体数组的指针(重点!!!!) 

(8)结构体指针--------------结构体成员是指针类型变量(重点!!!!)

(9)typedef关键字与结构体、结构体指针 (超重点!!!)

(10)使用typedef定义结构体

(11)使用typedef定义结构体指针 

(12) 结构体题目练习

正文:

一、结构体的定义:

官方来说结构体就是一些值的集合,这些值称为成员变量。结构体的每个成员可以是不同类型的变量。说到集合,数组也是集合,但是不同的是数组只能是相同类型元素的集合。结构体也是一种数据类型,它由程序员自己定义,可以包含多个其他类型的数据。像 int、float、char 等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为基本数据类型。而结构体可以包含多个基本类型的数据,也可以包含其他的结构体,我们将它称为复杂数据类型或构造数据类型。

二、结构体的基础结构:

 遵守的准则:(1)先定义结构体类型,再定义结构体变量

 struct   student //结构体类型 或 结构体名

{       

 int num;

 char  name[20];     //结构体成员

 char sex;

 int age; 

 float score;

 char arr[30];

 }

 struct student stu1,stu2;       //结构体变量

 (2)定义结构体类型的同时定义结构体变量

 struct   data   // 结构体类型 或结构体名

 {      

  int day int month;   //结构体成员

  int year

 }

time1,time2;   //结构体变量

 (3)直接定义结构体变量

 struct     // 定义结构体类型

{

 char name[20];

 char sex; 

 int num;        //结构体成员

 float score[3] 

 }

person1,person2;  //结构体变量 

注意:

▶只有结构体变量才分配地址,而结构体的定义是不分配空间的

▶结构体中各成员的定义和之前的变量定义一样,但在定义时也不分配空间

▶结构体变量的声明需要在主函数之上或者主函数中声明,如果在主函数之下则会报错

三、结构体的使用

(1)结构体的初始化

知识点1:

和其它类型变量一样,对结构体变量可以在定义时指定初始值。

#include <stdio.h>

struct books    // 结构体类型

{

char title[50];

char author[50];    //结构体成员

char subject[100];

int book_id;

}book={"C 语言","xingaosheng","编程语言",12345};  //结构体变量的初始化

int main()

{

printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);

return 0;

}

(2)结构体的成员访问

知识点1:

🔑为了访问结构的成员,我们使用成员访问运算符(.)。

🔑引用形式:<结构体类型变量名> . <成员名>

注意:结构体变量不能整体引用,只能引用变量成员

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

struct           // 无标签名,匿名结构体

{

char name[20];  //姓名

int num;     //学号

int age;     //年龄

char group;   // 所在小组

float score;  // 成绩

}stu1;            // 结构体变量

int main()

{

// 给结构体成员赋值

stu1 = { "Tom",12,18,'A',123.3f };

printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f\n", stu1.name, stu1.num, stu1.age, stu1.group, stu1.score);

return 0;

}

注意:需要注意的是,结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。

 (3)结构体数组

知识点1:

 结构体数组:是指数组中的每一个元素都式结构体。

 结构体数组常被用来表示一个拥有相同数据结构的群体。

例子:

struct student

{

    char name[20];  //姓名

    int num;  //学号

    int age;  //年龄

    char group;  //所在小组 

    float score;  //成绩

}class[5];

//表示一个班有5个人

struct stu

{

    char name[20];  //姓名

    int num;  //学号

    int age;  //年龄

    char group;  //所在小组 

    float score;  //成绩

}class[5] = {

    {"Li ping", 5, 18, 'C', 145.0},

    {"Zhang ping", 4, 19, 'A', 130.5},

    {"He fang", 1, 18, 'A', 148.5},

    {"Cheng ling", 2, 17, 'F', 139.0},

    {"Wang ming", 3, 17, 'B', 144.5}

};

Ps:当对数组中全部元素赋值时,也可以不给出数组长度

struct stu

{

    char name[20];  //姓名

    int num;  //学号

    int age;  //年龄

    char group;  //所在小组 

    float score;  //成绩

}class[] = {

    {"Li ping", 5, 18, 'C', 145.0},

    {"Zhang ping", 4, 19, 'A', 130.5},

    {"He fang", 1, 18, 'A', 148.5},

    {"Cheng ling", 2, 17, 'F', 139.0},

    {"Wang ming", 3, 17, 'B', 144.5}

};

(4)结构体指针--------------指向结构体变量的指针(重点!!!!)

知识点1:

结构体中可以定义指向结构的指针,方式与定义指向奇特类型变量的指针类似。

定义类型:struct 结构体名 * 结构体指针名

例子:struct books*struct_pointer 

其中 books 为结构体名   struct_pointer为结构体指针名

知识点2:

定义之后可以在上述定义的指针变量中存储结构变量的地址

struct_pointer = &Book1;

为了使用指向该结构的指针访问结构的成员,必须使用->运算符

定义结构体指针举例:

struct stu   // 结构体类型 或 结构体名

{

    char *name;  //姓名

    int num;  //学号

    int age;  //年龄

    char group;  //所在小组

    float score;  //成绩

} stu1 = { "Tom", 12, 18, 'A', 136.5 };

//结构体指针

struct stu *pstu = &stu1;

也可以在定义结构体的同时定义结构体指针:

struct stu{

    char *name;  //姓名

    int num;  //学号

    int age;  //年龄

    char group;  //所在小组

    float score;  //成绩

} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;

注意:

▶ 结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&符号,所以给p赋值只能写成。

▶ 结构体和结构体变量是两个不同的概念:结构体是一种数据类型,是一种创建变量的模板,编译器不会为它分配内存空间,就像 int、float、char 这些关键字本身不占用内存一样;结构体变量才包含实实在在的数据,才需要内存来存储。下面的写法是错误的,不可能去取一个结构体名的地址,也不能将它赋值给其他变量。

知识点3:注意结构体中的优先级问题;

通过结构体指针可以获取结构体成员,一般形式为:

(*pointer).memberMane                  //pointer为结构体指针名

  pointer->memberName             // 或者 

第一种写法中, .  的优先级高于  * ,(*pointer)两边的括号不能少

     如果去掉括号写成*pointer.memberName,

     那么就等效于*(pointer.memberName),这样意义就不对了。

第二种写法中,-> 是一个新的运算符,习惯称它为“箭头”

     有了它,可以通过结构体指针直接取得结构体成员,

     这也是 -> 在C语言中的唯一用途。

知识点4:

 结构体指针的使用:前面两种写法是等效的,我们通常采用第二种写法,这样更加直观。

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

struct stu

{

char name[20];

int num;

int age;

char group;

float score;

}stu1 = { "Tom",12,18,'A',136.5 }, * pstu = &stu1;

int main()

{

// 读取结构体成员的值

printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", (*pstu).name, (*pstu).num, (*pstu).age, (*pstu).group, (*pstu).score);

printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", pstu->name, pstu->num, pstu->age, pstu->group, pstu->score);

return 0;

}

(5)结构体指针--------------指向结构体数组的指针(重点!!!!) 

知识点1:

在我们想要用指针访问结构体数组的第n个数据时可以用:

struct Student

{

char cName[20];

  int number;

  char csex;  

}student1;     //结构体变量

struct Student stu1[5];   //结构体数组

struct Student*p;        // 结构体指针

p=stu[n];

(++p).number//是指向了结构体数组下一个元素的地址

知识点2:

结构体指针与结构体数组的联合使用:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

struct stu    //结构体类型 或结构体名

{

char name[20];

int num;

int age;   //结构体成员

char group;

float score;

}stus[]{           //结构体数组

{"Zhou ping", 5, 18, 'C', 145.0},

{"Zhang ping", 4, 19, 'A', 130.5},

{"Liu fang", 1, 18, 'A', 148.5},

{"Cheng ling", 2, 17, 'F', 139.0},

{"Wang ming", 3, 17, 'B', 144.5}

}, * ps;   //结构体指针

int main()

{

//求数组长度 : sieof(结构体变量)/sizeof(结构体类型名)

int len = sizeof(stus) / sizeof(struct stu);

printf("Name\t\tNum\tAge\tGroup\tScore\t\n");

for (ps = stus; ps < stus + len; ps++)

{

printf("%s\t%d\t%d\t%c\t%.1f\n", ps->name, ps->num, ps->age, ps->group, ps->score);

}

return 0;

}

(6) 结构体指针--------------结构体成员是指针类型变量(重点!!!!)

知识点1:

举例代码:

struct Student

{

  char* Name;//这样防止名字长短不一造成空间的浪费

  int number;

  char csex;  

}student1;

注意:在使用时可以很好地防止内存被浪费,但是注意在引用时一定要给指针变量分配地址,如果你不分配地址,结果可能是对的,但是Name会被分配到任意的一的地址,结构体不为字符串分配任何内存存储空间具有不确定性,这样就存在潜在的危险。

进行代码改进:

struct Student

{

  char* Name;

  int number;

  char csex;  

}stu,*stu;

stu.name=(char*)malloc(sizeof(char));//内存初始化

如果我们定义了结构体指针变量,他没有指向一个结构体,那么这个结构体指针也是要分配内存初始化的,他所对应的指针类型结构体成员也要相应初始化分配内存

struct Student

{

  char* Name;

  int number;

char csex;  

}stu,*stu;

stu = (struct student*)malloc(sizeof(struct student));./*结构体指针初始化*/

  stu->name = (char*)malloc(sizeof(char));/*结构体指针的成员指针同样需要初始化*/  

(7)typedef关键字与结构体、结构体指针 (超重点!!!)

1.使用typedef定义结构体

知识点1:

typedef用来定义新的数据类型,通常typedef与结构体的定义配合使用。使用typedef的目的使结构体的表达更加简练(所以说typedef语句并不是必须使用的。)

用大白话来说:

▶ struct 是用来定义新的数据类型——结构体

▶ typedef是给数据类型取别名。

定义一个名字为TreeNode的结构体类型(现在并没有定义结构体变量,并不占用内存空间):

struct TreeNode   // 结构体类型

{

        int Element;

        struct TreeNode* LeftChild;   //结构体成员

        struct TreeNode* RightChild;

};

为结构体起一个别名Node,这时Node就等价于struct TreeNode

typedef struct TreeNode Node;

将结构体的定义和typedef语句可以连在一起写:

typedef struct TreeNode   //结构体类型

{

        int Element;              //结构体成员

        struct TreeNode* LeftChild;

        struct TreeNode* RightChild;   

}Node;     // Node 是 struct TreeNode 的别名

注意:Node 是 struct TreeNode 的别名(重点!!!!!!!!!)

注意 :不要与“定义结构体类型的同时定义结构体类型变量”混淆:

使用typedef关键字定义结构体类型 定义结构体类型的同时定义结构体类型变量 

typedef struct student

{

        int age;

        int height;

}std;

//std相当于struct student

struct student

{

        int age;

        int height;

}std1,std2;//定义了student数据类型的结构体和std1、std2结构体变量

2.使用typedef定义结构体指针 

知识点1:

使用typedef关键字用一个单词Node代替struct TreeNode,并定义指向该结构体类型的指针PtrToTreeNode:

struct TreeNode

{

        int Element;

        struct TreeNode* LeftChild;

        struct TreeNode* RightChild;

};

typedef struct TreeNode Node;   //用Node代替struct TreeNode

Node *PtrToTreeNode;            //定义指针

将结构体的定义和typedef连在一起写,再次缩短代码:

typedef struct TreeNode

{

        int Element;

        struct TreeNode* LeftChild;

        struct TreeNode* RightChild;

}Node;                          //定义结构体并用Node代替struct TreeNode

Node *PtrToTreeNode;            //定义指针

3.引用鹏哥课程中的测试样例:

#include<stdio.h>

struct peo//结构体的声明(创建了一个struct的结构体类型,类似于一个图纸)

{

    char name[20];//这四个整型加字符型都为结构体中的成员变量

    char tele[12];

    char sex[5];

    int high;

}//p1,p2//p1p2是两个全局的结构体变量

struct st//声明名字为st的结构体

{

    struct peo p;

    int num;

    float f;

}

int main()

{

    struct peo p1 = {“张三”,”15596668862“,"男",181};//结构体变量的创建,创建了结构体的对象

    struct st s ={{"lisi","15596668888","女",166},100,3.14f};//初始化st结构体的名字

    printf("%s %s %s %d\n",p1.name,p1.tele,p1.sex,p1.high);//结构体变量。成员变量

    printf("%s %s %s %d %d %f\n",s.p.name,s.p.tele,s.p.sex,s.p.high,s.num,s.f);

    return 0;

}

//另外一种打法:printf("%s %s %s %d\n",sp->name,sp->tele,sp->sex,sp->high);

//结构体指针->成员变量

结构体题目讲解:

详情见牛客网上的结构体问题,此处只介绍最简单的一个:

CC13 KiKi定义电子日历类:

描述

KiKi学习了面向对象技术,学会了通过封装属性(变量)和行为(函数)定义类,现在他要设计一个电子日历类TDate。

它有3个私有数据成员:Month,Day,Year和若干个公有成员函数,要求:

(1)带有默认形参值的构造函数,默认值为0, 0, 0;

(2)输出日期函数,用“日/月/年”格式输出日期;

(3)设置日期函数,从键盘输入年、月、日。

输入描述:

一行,三个整数,用空格分隔,分别表示年、月、日。

输出描述:

一行,用“日/月/年”格式输出日期。

示例1

输入:

2019 12 30

输出:

30/12/2019

代码:

解法一:

#include<stdio.h>

typedef struct day_t Pday_t ;

typedef void (*TInitDay)(Pday_t* day);

typedef void (*TSetDay)(Pday_t* day, int y, int m, int d);

typedef void (*TShowDay)(Pday_t* day);

struct day_t {

    int Day;

    int Month;

    int Year;

    TInitDay init;

    TSetDay  set;

    TShowDay show;

};

void day_init(Pday_t* day) {

    day->Year  = 0;

    day->Day   = 0;

    day->Month = 0;

}

void day_set(Pday_t* day, int y, int m, int d) {

    day->Year  = y;

    day->Month = m;

    day->Day   = d;

}

void day_show(Pday_t* day) {

    printf("%d/%d/%d", day->Day, day->Month, day->Year);

}

Pday_t M_day = {

    .init = day_init,

    .set  = day_set,

    .show = day_show,

};

int main() {

    int y, m, d;

    scanf("%d", &y);

    scanf("%d", &m);

    scanf("%d", &d);

    M_day.init(&M_day);

    M_day.set(&M_day, y, m, d);

    M_day.show(&M_day);

    return 0;

}

解法二:

#include <stdio.h>

//配合指针缩小存储压力

typedef struct ki

{

 int year;

 int month;

 int day;

} ki;

void p(ki*e,int a,int b,int c)//直接传入地址,操作ki的成员值,不再构造虚拟空间进行值传递

   {

    e->day=c;   //等价于(*e).day=c,加括号原因是防止*与.优先级影响结果

    e->month=b; //等价于(*e).month=b

    e->year=a;  //等价于(*e).year=a

    printf("%d/", e->day); 

    printf("%d/",(*e).month); 

    printf("%d",e->year); 

     

}

int main() 

{

    void p(ki*e,int a,int b,int c);

    int a,b,c;

    ki ki1={0,0,0};                          //初始化为0

   scanf("%d %d %d",&a,&b,&c);

   p(&ki1,a,b,c);

   

}

本文借鉴了以下文章的样例与知识,原文链接如下:原文链接:https://blog.csdn.net/weixin_45031801/article/details/127621419

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值