C语言基础教程(9)结构体

结构体


为什么需要结构体

为了表示一些复杂的事物,而普通的基本类型无法满足实际要求。

什么叫结构体

把一些基本类型数据组合在一起形成的一个新的复合数据类型。

如何定义结构体

// 3种方式:

// 第一种  只是定义了一个新的数据类型,并没有定义变量   推荐采用1

struct Student

{  Int age;

   Float score;

   Char sex;

}; 

//第二种

   struct Student

{  Int age;

   Float score;

   Char sex;

} st; 

// 第三种

struct

{  Int age;

   Float score;

   Char sex;

} st;  

怎样使用结构体变量

  赋值和初始化

   定义的同时可以整体赋值。

   如果定义完之后,则只能单个赋初值。

如果取出结构体变量中的每一个成员{重点}

1 结构体变量名.成员名

2 指针变量名->成员名 (更常用)

  它会在计算机内部转化成 (* 指针变量名).成员名  的方式来执行。

  所以两者是等价的。

例子:

Struct Student {

   Int age;

   Float score;

   Char sex;

};

Int main(void) {

   Struct Student st = {80,66.6f,’F’};

   //初始化定义的时候赋值  66.6在C语言中默认是double类型,如果希望一个实数是float类型,则必须在末尾加f或F, 因此66.6是double, 66.6f或66.6F是float

   struct Student st2;

   st2.age = 10;

   st2.score = 88;

   st2.sex = 'F';   // 第二种方式 单独赋值


   Struct Student *pst = &st; // &st 不能写成 st

   Pst->age = 88; // 通过结构体指针变量

   printf("%d %f\n", st.age, pst->score);

   Return 0;

}

 

理解

   1 pst->age 会在计算机内部转化成 (*pst).age  的方式来执行,没有为什么这就是->的含义这也是一种硬性规定。

   2 所以 pst->age 等价于  (*pst).age 也等价于 st.age

   3 pst->的含义:pst 所指向的那个结构体变量中的age这个成员。 

结构体变量的大小略大于其内部成员类型所占字节数之和。试:sizeof(struct)

若想通过函数对主函数结构体变量进行修改,则主函数必须发送地址,外函数定义指针结构体变量,通过外函数内部语句完成对变量的修改。

而仅想输出、读取操作,则不用传地址,定义指针过程

 

例:
 

/*
   通过函数完成对结构体变量的输入和输出
*/

# include <stdio.h>
# include <string.h>

struct Student {

   int age;

   char sex;

   char name[100];

}; //分号不能省


void InputStudent(struct Student *);

void OutputStudent(struct Student ss);

int main(void){

   struct Student st;  //15行


   InputStudent(&st); //对结构体变量输入  必须发送st的地址

   //printf("%d %c %s\n", st.age, st.sex, st.name);  // 此行和 下行输出函数 功能相同

   OutputStudent(st); //对结构体变量输出  可以发送st的地址也可以直接发送st的内容


   return 0;

}


void OutputStudent(struct Student ss){

   printf("%d %c %s\n", ss.age, ss.sex, ss.name);

}


void InputStudent(struct Student * pstu) //pstu只占4个字节
{

   (*pstu).age = 10;

   // pstu->name = "张三丰"; 或(*pstu).name = "张三丰";  都是error,提示错误信息: cannot
      convert from 'char [5]' to 'char [100]'

   strcpy(pstu->name,"张三丰"); // 用字符串拷贝命令解决问题

   pstu->sex = 'F';

}


/*

//本函数无法修改主函数15行st的值 所以本函数是错误的

void InputStudent(struct Student stu) {

   stu.age = 10;

   strcpy(stu.name, "张三");  //不能写成 stu.name = "张三";

   stu.sex = 'F';

}

*/


结构体:应该发送地址还是内容

设计函数的目的:必须考虑 功能单一, 还要考虑安全因素

C++中指针前可加const 则只能读而不能修改其指向的变量。

指针的优点:

  耗用内在小(4字节)

  快速传递数据

  执行速度快。

因此:推荐使用结构体变量作为函数参数来传递
 

/*
   示例:

       发送地址还是发送内容

   目的:

       指针的优点之一:

          快速的传递数据,

          耗用内存小

          执行速度快
*/

# include <stdio.h>
# include <string.h>

struct Student{

   int age;

   char sex;

   char name[100];

}; //分号不能省


void InputStudent(struct Student *);

void OutputStudent(struct Student *);

int main(void){

   struct Student st ;  //15行

   //printf("%d\n", sizeof(st));


   InputStudent(&st); //对结构体变量输入  必须发送st的地址

   OutputStudent(&st); //对结构体变量输出  可以发送st的地址也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址


   return 0;

}


void OutputStudent(struct Student *pst){

   printf("%d %c %s\n", pst->age, pst->sex, pst->name);

}


void InputStudent(struct Student * pstu) //pstu只占4个字节
{

   (*pstu).age = 10;

   strcpy(pstu->name, "张三");

   pstu->sex = 'F';

}

结构体变量的运算

   不能加减乘除操作,只能相互赋值。

例如:

struct Student
{ 

       Int age;

       Char sex;

       Char[100];

};

Struct Student str1, str2;

Str1 = str2 /  str2 = str1 ;  都是正确的。


// 举例:动态构造存放学生信息的结构体数组

# include <stdio.h>
# include <malloc.h>   // 必须先添加头文件 malloc

struct Student{

   int age;

   float score;

   char name[100];

};


int main(void){

   int len;

   struct Student * pArr;

   int i, j;

   struct Student t;

   
   //动态的构造一维数组

   printf("请输入学生的个数:\n");

   printf("len = ");

   scanf("%d", &len);

   pArr = (struct Student *)malloc(len * sizeof(struct Student));

   //printf("%d\n",sizeof(struct Student));   // 108字节 

   //输入

   for (i=0; i<len; ++i)

   {

       printf("请输入第%d个学生的信息:\n", i+1);

       printf("age = ");

       scanf("%d", &pArr[i].age);


       printf("name = ");

       scanf("%s", pArr[i].name);  //name是数组名,本身就已经是数组首元素的地址, 所以
       pArr[i].name 不能改成 &pArr[i].name


       printf("score = ");

       scanf("%f", &pArr[i].score);

   }


   //按学生成绩升序排序 冒泡算法

   for (i=0; i<len-1; ++i)

   {
       for (j=0; j<len-1-i; ++j)
       {

          if (pArr[j].score > pArr[j+1].score)  // >升序 <降序
          {

             t = pArr[j];    // 注意 t 的类型为  Struct Student

             pArr[j] = pArr[j+1];

             pArr[j+1] = t;

          }

       }

   }


   printf("\n\n学生的信息是:\n");

   //输出

   for (i=0; i<len; ++i)
   {

       printf("第%d个学生的信息是:\n", i+1);

       printf("age = %d\n", pArr[i].age);

       printf("name = %s\n", pArr[i].name); 

       printf("score = %f\n", pArr[i].score);

  

       printf("\n");

   }


   return 0;

}

总结:

对于一个人事管理或图书管理项目,分析流程:

第一步;存储 

第二步:操作

第三步:输出

前两个过程最难、最核心 是“数据结构”研究的重点,一般都屏蔽了。

数组 和 变量 虽然都可以存储,但都不完美。

比如:人事关系图、交通图等,都不好用数组保存。

从事关系结构只能用“树”还保存,而对于 两个起终点:公交线路查询,实现时间最小/ 距离最短/ 花费最低 等功能,只能用“图”来存。

而图 和 树 都必须有指针知识,它们属于较高深的思想层次的东西。因此要学好数据结构必须要 懂得指针。

若感兴趣:可以继续学习郝斌老师的《数据结构》教学视频。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值