用驴子拖宝马——怎样滥用结构体
买了一辆宝马,但不知道如何正确使用,找头驴子拖着宝马满世界兜风。这情景多半会让人感到很滑稽。不正确地使用结构体,代码同样会产生一种滑稽的喜感。
只有按照合适的方式使用一件物品才能得到恰如其分的效果,而滥用一件物品只能起到适得其反的作用。
/*题目:输入两个学生的学号、姓名和成绩,输出成绩较高的学生的学号、姓名和成绩。*/#include <stdio.h> int main(){struct Student { int num;char name[20];float score; }student1,student2; scanf("%d%s%f",&student1.num,student1.name,&student1.score); scanf("%d%s%f",&student2.num,student2.name,&student2.score); printf("The higher score is:\n");if(student1.score>student2.score) printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);else if(student1.score<student2.score) printf("%d %s %6.2f\n",student2.num,student2.name,student2.score);else {printf("%d %s %6.2f\n",student1.num,student1.name,student1.score); printf("%d %s %6.2f\n",student2.num,student2.name,student2.score); }return 0;}
————谭浩强 ,《C程序设计》(第四版),清华大学出版社,2010年6月,p299
首先,这段代码把结构体的类型声明写在了main()之内,这是让人感到惊异的。因为,根据标识符的作用域原则,这意味着struct Student是一种“局部”的类型,也就是说只能在main()只能使用这种结构体。
这样使用结构体其实反倒不如不使用结构体,因为基本上这样的写法只收获了使用结构体的麻烦:定义结构体类型,臃长复杂的成员引用,……,但是,没有得到任何好处。对比一下不用结构体的代码就清楚了:
不难看出,后者与前者功能一致,但是更加清爽,代码也更简洁。既然如此,又有什么必要舍近求远地使用结构体呢?可见样本代码使用结构体完全是一种吃力不讨好的行为。之所以吃力不讨好,是因为样本代码并非是正确使用结构体的方式,而是一种错误方式——只使用了结构体的短处,而没有发挥结构体的任何优势。
当然,后来的这段代码也并非没有缺点:几句形式上完全一致但却有些臃长的printf()函数调用缺乏视觉美感(两个scanf()函数调用也有同样的感觉)。可以把这些臃肿的内容各自用一个函数来实现:
这段代码首先在视觉上比前一个要更富于美感,这种美感并不是一种装饰,而是有着更为实惠的利益,那就是整洁优美的代码更不容易出错,即使出错也比看起来烂糟糟的代码更容易查找和得到改正。
这段代码的另一个优势在于,如果现在需要修改输出的格式,比如把%6.2f改为%6.0f,现在只需要修改一处而对main()函数部分的代码毫无影响,而前两个代码则需要修改4处,且修改之处一起纠结于main()函数之内。俗话说,常在河边走难免不湿鞋。修改的地方多,工作量大不说,出错的可能性也大。
现在,你可能会觉得传递的参数也忒多了些。这个代码中传递的参数是3个,如果是7、8个呢?你可能会感到非常烦躁。并且,我在前一个代码中悄悄的特意留下了一个小BUG(某个name2被写成了name1),你可能根本就没有察觉。查找这类错误往往非常困难,比那种“比眼力找差别”的智力游戏还要困难。
那么,应该如何回避这些问题呢?答案显然是避免分散地传递这些参数。既然这些数据在逻辑上从属于一个主体,最好把它们都捏合在一起。就像电工布线时是把两个电线拧在一起一样。你没见过把火线和地线分别铺设的电工吧?
在代码中怎样才能把几个在逻辑上从属于一个主体的数据捏在一起呢?显然就是结构体。结构体的作用之一就是简化函数之间的参数传递。既然如此,就意味着不只一个函数会使用这种结构体类型,所以绝对不应该把结构体的类型声明放在某个函数内部。现在你总应该懂得为什么把结构体类型声明放main()里是一种愚蠢的、似是而非的写法了吧?
在使用结构体的前提下对前一个代码继续改进:
现在,只需要传递一个参数,传递多个参数时个别实参写错的可能性大大降低,代码也更加简洁了。并且,由于结构体各个参数在逻辑上从属于一个整体,代码更具有概括力,函数的意义也更为清晰。
总之,结构体的意义在于其“整体性”,如果建立了结构体,而只是对其进行了成员运算,那么结构体的意义如果不能说是全部丧失,恐怕也可以说是几乎全部丧失。
此外要补充一点的是,在结构体尺寸较大的情况下,结构体的赋值可能比较费时,这时可以用传递指向结构体指针的办法来解决。如前面的output()函数,可以写为
形参中的第一个const表示p_std指针所指向的结构体对象不应该被函数改变,第二个const表示p_std这个指针本身也不应该在函数中被改变。这种写法在必须提供给函数一个结构体对象的备份时并不适用。
转载于:https://www.cnblogs.com/swjm119/archive/2012/01/21/2328557.html
用驴子拖宝马——怎样滥用结构体相关推荐
- go struct 静态函数_Go语言学习笔记(四)结构体struct 接口Interface 反射reflect...
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...
- 【UE4】蓝图结构体入门及案例
结构体 结构体是什么? UE4中存在许多不同的变量类型,浮点,布尔,整数,字符串,等等.我们赋予变量意义,用于处理程序的运行,在需要很多意义相同的数据时,我们会应用数组的概念来储存一系列相同类型的数据 ...
- 被遗忘的C结构体封装技术
编译器倾向于将结构体成员对齐到数据类型的长度,以获得最佳的访问效率. 1. 谁该阅读本文 本文是关于如何减少C程序的内存占用的:手工重新排列C结构体的成员声明来减小尺寸.为了读懂它,你需要基本的C语言 ...
- Gin 框架学习笔记(02)— 参数自动绑定到结构体
参数绑定模型可以将请求体自动绑定到结构体中,目前支持绑定的请求类型有 JSON .XML .YAML 和标准表单 form数据 foo=bar&boo=baz 等.换句话说,只要定义好结构体, ...
- Go 知识点(04)— 结构体字段转 json格式 tag 标签的作用
我们知道在 Go 语言中无论是变量.常量还是函数,对于首字母大小写有不同的处理. 首字母大写,标志着该字段或者函数是能导出的,也就是可以被其它包所能访问的: 首字母小写,标志着该字段是私有的,只能在本 ...
- 【C#】枚举_结构体_数组
最近看C#视频,关于这部分,先看了一遍,又照着敲了一遍,自己敲的过程发现了一些有意思的东西. 枚举:定义一个枚举类型的变量,这个变量有很多相同类型的值.比如性别Gender这个变量可以有男和女这两个值 ...
- C++ 结构体struct 的使用
结构体是什么 结构体是一种有开发者定义的数据类型,以容纳许多不同的数据值 结构体的注意事项: 声明结构体的方式和声明类的方式大致相同,其区别如下: 使用关键字 struct 而不是关键字 class. ...
- C语言结构体篇 结构体
在描述一个物体的属性的时候,单一的变量类型是无法完全描述完全的.所以有了灵活的结构体变量. 结构体变量从意义上来讲是不同数据类型的组合,从内存上来讲是在一个空间内进行不同的大小划分. 1.1 结构体类 ...
- 33. 使用fread()/fwrite()往文件中写入结构体,从文件中读出结构体
1 //读写结构体 2 #include <stdio.h> 3 typedef struct student 4 { 5 int num; 6 char name[30]; 7 char ...
最新文章
- mysql sum 为 0 的解决方法
- 我的HTML学习记录(七)
- 20年IT老兵分享:账务系统设计及应用--转
- 上市近一年,良品铺子的“高端化”之路走通了吗?
- 计算机与新闻业未来发展,计算机学院举办“智创未来,谈思维与职业发展”活动...
- STM32上使用JSON
- nodejs里的module.exports和exports
- 一些学习笔记和工作布置
- 链路负载需求及基本原理
- 自从用了 OkHttp,别的都完全不想用了!
- 我在GitHub上找到了这些游戏项目,刺激!
- Vue 实例常用的属性和方法
- MySQL——MySQL 图形化管理工具的介绍
- 【愚公系列】2022年10月 微信小程序-电商项目-商品详情页面说明和商品导航
- 【JS】用JS实现系统常见日周月时间按钮切换效果
- js实现开平方 Math.sqrt
- fatal Couldn‘t find remote ref master
- mysql异地多活方案_数据库异地多活解决方案
- 【设计模式】Builder模式
- 用计算机画函数图象的软件,信息技术应用 用计算机画函数图象优秀教案
热门文章
- uap连接oracle,UAP环境初始化操作手册Oralce版.pdf
- 安装mysql初始化date_0001_mysql 5.7.25安装初始化
- 回文数Python解法
- python目录下的文件夹_Python列出当前文件夹下文件的两种方法
- TIMING_02 浅谈时序约束与时序分析
- c语言 srand time 0,c++ 随机数 srand(time(0)) 用法 | 求索阁
- mysql数据传输完整性_mysql – 处理数据库完整性
- MySQL error 1477_mysql_error.md
- burp爆破线程设置多少_多线程到底需要设置多少个线程?
- python 混淆矩阵_绘制混沌矩阵