结构体知识点

 

问题引入:管理学生信息(学生信息管理系统)。

假设每个学生,学校关心如下内容:

学号 char StuId[9];             // 西邮学号8位,再加一个0结束标志,故而设定为9位

姓名 char StuName[21];     // 一个汉字两个字节,此处假设最多十个汉字,再加一个0结束标志,故而设定为21位

性别 int StuSex;       

年龄 int StuAge;                // 一般设定为出生年月日,这样不用每年进行管理

成绩 int Score;                  // 成绩本可能出现小数,但是此处为了练习用整型表示,不到万不得已不用float和double,运算太慢了

 

假设有50名学生的相关信息需要管理……

char StuId[50][9];

char StuName[50][21];

int StuSex[50];

int StuAge[50];

int Score[50];

 

若使用上述多个数组形式处理相关任务,则,应保证同一名学生5个方面的信息数据,保存在下标相同的数组元素中,以保证逻辑上的一致性。但是,在“排序”等事务要求下,需要用多次交换来保证逻辑一致性,这使得上述方法太可怕了!

另外:上述方法并没有在逻辑层面保持与人文信息的一致性。

为了简化上述问题的解决,也为了能使C语言更符合人类思维习惯,提出结构体的概念。

 

补充:二维数组

int a[3][4] <=> int [4] a[3]   理解为:a数组有3个元素,每个元素是一维数组,即 int [4] 类型

上述语句定义了一个3行4列的二维数组。

二维数组m共有12个元素,每个元素都是int类型的。

这12个元素的下标分别是:

a[0][0]、a[0][1]、a[0][2]、a[0][3]、

a[1][0]、a[1][1]、a[1][2]、a[1][3]、

a[2][0]、a[2][1]、a[2][2]、a[2][3]、

 

char StuName[50][21] => char[21] StuName[50]

一、结构体的基本操作

1.结构体的声明

struct  STUDENT_INFORMATION

{

char StuId[9];

char StuName[21];

int StuSex;

int StuAge;

int Score;

};

结构体的声明,实质上是定义了一个新的数据类型

 

 

struct  STUDENT_INFORMATION

{

char StuId[9];

char StuName[21];

int StuSex;

int StuAge;

int Score;

}a;

在声明类型的同时定义变量,定义了一个struct STUDENT_INFORMATION类型的变量a

2.结构体的使用方法

(1)

struct STUDENT_INFORMATION  a;

int  b;

上述两条语句都是变量定义语句;

其中,a和b地位相同,都是变量名称;

int和struct STUDENT_INFORMATION地位相同,都是数据类型

 

(2)

strcut STUDENT_INFORMATION  a, b[50], *p;

通常将结构体类型的变量称为:(结构体)实例;

b是一个拥有50个struct STUDENT_INFORMATION实例元素的数组,b[0]到b[49]就是独立的50个类似a的结构体实例;

p是一个能够指向struct STUDENT_INFORMATION实例的指针变量,其指类就是struct STUDENT_INFORMATION。

 

(3)

结构体的使用有2个基本步骤:

1)声明结构体数据类型;

2)用结构体类型作为数据类型,定义新的实例(数组、指针)。

在上述两步之后,通过对实例的成员的引用,实现对实例的引用。

3.访问结构体的成员

struct  STUDENT_INFORMATION

{

char StuId[9];

char StuName[21];

int StuSex;

int StuAge;

int Score;

};

 

不能将一个结构体变量作为一个整体进行输入和输出,只能对结构体变量中的各个成员分别进行输入和输出。

“.”是成员运算符,它在所有的运算符中优先级最高。

 

(1)

strcut STUDENT_INFORMATION  a, b[50], *p;

 //要求:对a实例进行赋值      张三,男,19岁,03151038,61    注:男为1,女为0

正确写法:

strcpy(a.StuName, “张三”);                                 strcpy("a.StuName", “张三”);   (错误)

strcpy(a.StuId, “03151038”);

a.StuSex = 1;

a.StuAge = 19;

a.Score = 61;

 

注意:

a.StuName = 张三;

a.StuName = “张三”;

a.StuName[21] = “张三”;

a.StuName[0] = “张三”;

a.StuName = {“张三”};

上述5种写法都是错误的!原因:StuName是常量!数组名称的本质是首地址常量,常量不能被赋值!

 

(2)

strcut STUDENT_INFORMATION  a, b[50], *p;

//要求:对b数组的第一个元素所代表的学生赋值如下信息:   04151038  李四  女  18  99

strcpy(b[0].StuName, “李四”);

strcpy(b[0].StuId, “04151038”);

b[0].StuSex = 0;

b[0].StuAge = 18;

b[0].Score = 99;

 

(3)

strcut STUDENT_INFORMATION  a, b[50], *p;

p = &a;   (p指向a)

*p = a;    (*在等号左边应念作:p所指向的空间,即实例a)

如何通过指针引用其所指向的实例的诸成员?

一般思路: *p.Age    错误       上述的”.”是一个运算符:取结构体实例成员运算符;其优先级高于!(逻辑非)运算符!

                                                在C语言的所有运算符中,优先级最高的前三个运算符是: () -> [] -> . (注意此处的点)

                  *p.Age <-> *(p.Age)   这应该称为:“p实例的Age”所指向的空间,这与原本要表达的意义完全无关!

正确表达: (*p).Age         繁琐           通过(),提高*的运算顺序:

                   p->Age          简单           正确念法是:p所指向的实例的Age成员

 

.运算符与->运算符优先级相同!

两个运算符的差别: 实例.成员

                                     指针->成员

 

综上:访问结构体的成员规则如下(以StuSex为例)

strcut STUDENT_INFORMATION  a, b[50], *p;

a.StuSex 

b[0].StuSex

p->StuAge

 

 

strcut STUDENT_INFORMATION  a;

strcut STUDENT_INFORMATION   b[50];   结构体数组  数组各元素在内存中连续存放

strcut STUDENT_INFORMATION   *p;

二、结构体内存映像图

struct ABC

{

int a;

char b;

double c;

};

 

 

从上述结构体的内存映像图可知,一个结构体的长度,原则上是各成员长度之和。因此,sizeof(struct ABC) => 13B

注意:上机实验时,结果并非13B,而是比13B大,个中原因与一个较难、较深的概念有关:内存对其模式,该问题只能在进一步的课程《数据结构与算法》中深入探讨。

三、结构体实例赋初值

struct STI      

{

char Id[9];

char Name[21];

char Sex;    //也可以用int Sex;

int Age;

int Score;

};

 

struct STI a = {"03142069", "安宁", 'f', 23, 100};

struct STI b[3] =

{

         {“02150103”, “张三疯子”, ‘m’, 19, 100}, 

         {“02150101”, “仇娇雅子”, ‘f’, 22, 30},

         {“02150013”, “啤酒瓶子”, ‘m’, 20, 0},

};

struct STI b[3] = {“02150103”, “张三疯子”, ‘m’, 19, 100, “02150101”, “仇娇雅子”, ‘f’, 22, 30, };   //不完全赋初值

struct STI b[ ] = {“02150103”, “张三疯子”, ‘m’, 19, 100, “02150101”, “仇娇雅子”, ‘f’, 22, 30, };   //不指定数组元素个数

也可以将结构体变量一个一个地赋初值

struct student{
    int num;
    char name[20];
    float score[3];
};

 

void main(void){
    struct student  stu;
    
    stu.num = 12;
    strcpy(stu.name, "AnAn");
    stu.score[0] = 67.5;
    stu.score[1] = 89;
    stu.score[2] = 78.6;

用户自己输入

struct student{
    int num;
    char name[20];
    float score[3];
};

 

void main(void){
    struct student  stu;
    
    scanf("%d%s%f%f%f", &stu.num, stu.name, &stu.score[0], &stu.score[1], &stu.score[2]);

 

 

问题:表示性别时为何用单引号,忘记了,下去去查,进行理解。

答:因为是char型,是字符型

 

注意:C语言允许在结构体实例之间直接赋值!

struct STI a = {…};

struct STI b;

b = a; // 这就可以完成将a的所有成员数据,赋值给b的所有成员(不要再进行成员内部一个一个的赋值)

四、复合结构体

稍微专业一些的学生信息,示例如下:

struct DATE     //先定义出生日期

{

       short year;

       char month;

       char day;

};      // 经过上述语句,定义了一个struct DATE的数据类型,以后,就可以使用这个数据类型了!

 

struct STU_INF

{

       char stuId[9];

       char stuName[21];

       char stuSex;

       struct DATE stuBirth; // 这个成员本身是另一个结构体的实例!它有着自己的三个成员:year,month和day成员!

};

 

对struct STU_INF的使用:

struct STU_INF  a;

a有四个成员:a.stuId、a.stuName、a.stuSex和a.stuBirth;

其中的a.stuBirth自己存在3个成员:a.stuBirth.year 、a.stuBirth.month 、a.stuBirth.day 。

指向结构体类型数据的指针

1.指向结构体变量的指针

eg11.3

 

这3种形式等价:

结构体变量.成员名

(*p).成员名

p->成员名

 

p -> n  得到p指向的结构体变量中的成员n的值

p -> n++  得到p指向的结构体变量中的成员n的值,用完该值后使它加1

++p -> n  得到p所指向的结构体变量中的成员n的值加1,然后再使用它

2.指向结构体数组元素的指针 

eg11.4

 

(++p) -> n  先使p自加1,然后得到它指向的元素中的n成员值

(p++) -> n  先得到p -> n的值,然后使p自加1

 

3.用结构体变量和指向结构体的指针作函数参数

将一个结构体变量的值传递给另一个函数,有3个办法:

(1)用结构体变量的成员作参数(值传递)

(2)用结构体变量作实参(值传递),结构体变量所占的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。

(3)用指向结构体变量(数组)的指针作实参,将结构体变量(或数组)的地址传递给形参

 

eg11.5

eg11.6

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安安csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值