切换风格
开启辅助访问 切换到窄版

[提问] 关于结构

[复制链接]
作者:chronosphere 
版块:
Discuz!The Future 编程 c语言 发布时间:2018-12-4 10:48:42
20053
chronosphere 发表于 2018-12-4 10:34:36 | 显示全部楼层 |阅读模式
结构如何使用?
结构在task13中的应用?
ctx 发表于 2018-12-4 10:38:20 | 显示全部楼层
结构类型是在程序中定义的类型,以指定记录的格式,它包括成员名称和类型,以及成员在内存中的存储次序。一旦定义了结构类型,就可以像使用其他所有类型一样使用这种结构类型,可以声明具有这种结构类型的对象,定义指向这种对象的指针,以及定义具有这种结构类型元素的数组。

结构类型的定义从关键字 struct 开始,大括号内包含声明结构成员的列表:
  1. struct [标签名称] {成员声明列表};
复制代码
结构必须包含至少一个成员。下面的例子定义了 struct Date 类型,它有 3 个 short 类型的成员:
  1. struct Date { short month, day, year; };
复制代码

标识符 Date 是该结构类型的标签(tag)。标识符 year、month 和 day 是成员名称。结构类型的标签属于一个不同的命名空间:即使结构标签与变量名或函数名相同,编译器也仍然可以区分。类似地,对于每个结构类型,其中的每个结构成员名称都属于不同的命名空间。
结构的成员,可以定义为任何所需的完整类型,包括之前已定义的结构类型。但是不能是长度可变的数组,或者指向长度可变数组的指针。
下面的结构类型 struct Song 有 5 个成员,可以存储关于音乐记录的5种信息。成员 published 的类型是 struct Date,这正是前面的例子中所定义的结构类型:
  1. struct Song { char title[64];
  2.               char artist[32];
  3.               char composer[32];
  4.               short duration;    // 播放时间(秒)
  5.               struct Date published;     // 出版日期
  6.            };
复制代码
结构类型无法将自己的类型作为其成员的类型,因为自己的类型定义尚不完整,要在结束的大括号(})后才算定义完整。然而,结构类型可以包含指向自己类型的指针,这样的应用很常见。例如,在实现链表(linked list)和二叉树(binary tree)时,就会用到这种自引用结构(self-referential structure)。下面的例子为一个单向链表成员定义了一个类型:
  1. struct Cell { struct Song song;        // 这条记录的数据
  2.               struct Cell *pNext;        // 指向下一条记录的指针
  3.             };
复制代码

如果在多个源代码文件中使用同一个结构类型,应该将它的定义放在头文件中,再在各个源代码文件中包含该头文件。通常,同一个头文件中也会定义操作该结构类型的函数原型。那么,在所有包含给定头文件的源代码文件中,均可以使用该结构类型及其对应的操作函数。
回复 支持 反对

使用道具 举报

ctx 发表于 2018-12-4 10:42:14 | 显示全部楼层
1 什么是结构体
结构体是一种聚合数据类型,它是一种数据元素的聚合。比如我们描述一个学生时,要求有他的姓名、学校、分数等等信息,在之前的处理中,我们通常会使用单独的数据类型来描述。比如,定义一个字符串数组来描述姓名char name[20] = "xiaoming",定义一个浮点数来描述成绩float f = 96.5等等。但是这种做法有个缺点。所有的这些数据都是为了描述一个学生来定义的,但是它们又没有什么关联。有同学说,我们可以使用数组来定义一个学生,但是数组也有缺陷,一次只能定义一种数据类型。放在这里显然也不合适。所有,一种新的数据类型将被介绍:结构体。

所谓结构体就是将一些已知的数据类型放在一起来定义的一种数据类型。结构体并没有创造出新的数据类型,这点要搞清楚。C语言的结构体和其他高级语言的类有点相似的概念,可以完成对一种事物的抽象。但是C语言的结构体又不具备高级语言的继承和多态的功能。

1.1 结构体声明和定义
和其他类型变量的声明一样,结构体也有自己的关键字:struct 就像我们定义一个整形变量a一样int a,定义一个结构体变量b同样简单:
  1. struct
  2. {
  3.     char name[20];
  4.     float score;
  5. }XiaoMing;
复制代码

这样,我们就定义了一个结构体变量XiaoMing。这个变量包含两个成员,一个是char型的名字,一个是float型的分数,关于结构体的使用我们放在后面介绍。

但是这样定义一个结构体也有些问题,比如我们的程序中有大量的结构体需要使用,每个结构体我们都这样定义,数量一多,就完全的乱掉了,根本无法维护和扩展。所以,有了下面这种声明和定义来解决这个问题。
  1. struct _Student
  2. {
  3.     char name[20];
  4.     float score;
  5. };
  6. struct _Student XiaoMing;
复制代码

在声明中给这个结构体加上一个“_Student”的标签后,我们在需要定义的结构体变量的地方可以这样来定义:struct _Student XiaoMing; 。 这样我们就一目了然,原来这个结构体定义的是关于一个学生。

更常见的使用方法是在声明中用typedef 来给结构体起一个别名,这样在定义一个结构体变量时,能使定义看上去更简单明了。
  1. typedef struct _Student
  2. {
  3.     char name[20];
  4.     float score;
  5. } Student;
  6. Student XiaoMing;
复制代码

通过上面方式的声明,我们在使用该结构体定义变量时将会变得非常简单:Student XiaoMing; Student XiaoHua; 怎么样,是不是和定义一个整型变量aint a;一样简单。但是注意我们并没有创建一个新的类型Student,而是使用typedef来重命名了一下而已。这点非常重要。

1.2 结构体的使用
通过上一节的讨论,我们已经可以声明和定义一个结构体了,但是结构体怎么使用呢?这里要引入一个新的操作符“.”,通常我们也叫做点操作符。这个操作符是专门用来访问结构体成员的。比如,我们定义的struct _Stuent XiaoMing; 要使用其中的变量可以这样来使用:XiaoMing.score = 98.5; strncpy("XiaoMing", XiaoMing.name, 8);

在结构体指针中,我们使用‘->’来操作结构体指针所指向的变量。还是用上述的例子来说明:我们定义的struct _Stuent * XiaoMing; 对其所指的变量可以这样来使用:XiaoMing->score = 98.5; strncpy("XiaoMing", XiaoMing->name, 8)。

结构体在C语言编程中占用很重要的篇幅,尤其是结构体和指针结合起来的编程。同时,结构体也是实现C语言面向对象的编程思想的基础,在我们日常开发中,经常将一个对应的需求抽象为一个结构体,然后进行处理。比如:我们需要对一个学生的综合素质进行评定,可以这样来实现:
  1. typedef (float)(* average_socres)(float * socres_array, unsigned int nums);

  2. typedef struct _Student
  3. {
  4.     float math_scores;  //数学成绩
  5.     float english_scores;   //语文成绩
  6.     float physical_scores;  //物理成绩
  7.     average_socres av_socres;   //平均成绩指针函数



  8. }Student;
复制代码
回复 支持 反对

使用道具 举报

ctx 发表于 2018-12-4 10:48:42 | 显示全部楼层
You may have noticed that functions can only return one variable. But what if want to return more information than we can hold in one variable? The answer is to pack multiple variables together into a single structure. This creates a new type of variable which contains a number of fields. In this section's example, we create a new type of variable called struct SquareData. We can declare this just like other variables -- instead of writing int or float, we write struct SquareData.
After we have declared a variable of this type with: struct SquareData mySquare;  
we can access its fields with mySquare.side, mySquare.area or any other field name after the period.

Returning a struct is a modern addition to the language. It was not supported in the original C standard in 1972, but was added in the ANSI C standard (also sometimes known as "C89" or "C90"). Some very old compilers might not support ANSI C. We will see another way to return multiple values in a few weeks.
Structure:
  1. #include <stdio.h>   
  2. struct SquareData {   
  3. float area;   
  4. float perimeter;   
  5. int side;  };   
  6. struct SquareData calcSquare(int x) {      //define variable of data type structure     
  7. struct SquareData mySquare;        
  8. mySquare.side = x;      
  9. mySquare.perimeter = 4*x;     
  10. mySquare.area = x*x;        
  11. // we need to return this to main()      
  12. return mySquare;  }   
  13. void printStuff(struct SquareData mySquare) {      // this is not useful here, but it works      
  14. float areaBAD = mySquare.area;
  15. printf("The square's sides are ");      
  16. printf("%i units long, ", mySquare.side);      
  17. printf("and thus has \nan area of ");     
  18. printf("%f units, and ", areaBAD);   
  19.   printf("a perimeter of ");     
  20. printf("%f units.\n", mySquare.perimeter);  }   

  21. int main() {      
  22. struct SquareData square;      
  23. square = calcSquare(2);     
  24. printStuff(square);  
  25. getchar();      
  26. return 0;
  27. }  
复制代码

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表