函数知识学习和第一周简单总结

《Linux C程序设计 王者归来》这门课程的第三章是函数,函数的作用就是使得程序的模块性更强,不同作用的函数放在不同的地方,更重要的就是便于代码的修改和阅读。

学习函数首先要了解函数的本质,函数的本质是一段机器指令代码。而函数名的本质就是一个标号,该标号的值等于内存中存储函数代码的首地址。函数调用时会使空间的栈不断增长,从当前进程中的栈顶的位置到函数保存返回值的位置,这一块内存成为函数的栈帧。所有函数中定义的局部变量都存储在函数的栈帧上,当函数调用结束的时该块栈帧就消失了。如下图所示:

调用者函数开始调用之后,函数栈帧开始生长,调用完毕,该栈帧消失。一般地函数调用分为4个步骤:

将参数压入栈堆

保存寄存器的值

保存返回地址

跳转

这四步中的前三步都要访问内存,访问内存在计算机操作中很消耗时间,因此,函数调用比较好费时间,程序执行时应尽量减少函数的调用,对程序起到一定的优化作用。

从上图函数的本质中可以看出,C语言程序中的局部变量存储在栈上,全局变量存储在数据段上,也就是内存中。因为全局变量在整个程序的执行过程中一直存在,如果存在寄存器中会降低程序的运行效率。之前也提到过,尽量减少内存访问能够很大的提高程序的效率。局部变量会存储在寄存器中,因此一种程序的优化方式就是不要将循环算子等高频率使用的变量设置为全局变量或者静态变量。例如下边两个函数a.c和b.c:

a.c:

 1 int i;
 2
 3 void f()
 4
 5 {
 6
 7 int a[10];
 8
 9 for(i=0;i<100;i++)
10
11 a[i]=i;
12
13 }

b.c:

 1 void f()
 2
 3 {
 4
 5 int i;
 6
 7 int a[10];
 8
 9 for(i=0;i<100;i++)
10
11 a[i]=i;
12
13 }

从上边的两个程序对比可以看出,循环算子是i的程序中,每次访问全局变量的时候都要从内存中去数据。每次调用全局变量都要经过从内存中读取变量i的值,对变量i进行累加,将变量i的值重新存回到内存中这三步,而拒不变量只需要做累加变量所在的寄存器的值,从这两个简单程序的对比就能看出局部变量的执行效率要比全局变量高的多,如果要进行多次访问的话尽量采用局部变量。

函数作用就是使得程序的模块性更强,为了能够使程序模块化更强,代码易于管理,需要将同一类型的代码放在一个文件中,这样将代码分为若干个模块放在不同的文件中,在调用和编译的时候需要从不同的文件中去调用函数,这就会导致多个C语言文件链接的问题。链接中经常会发生会出现的就是一个文件可能需要引用另一个文件中定义的全局变量或者函数。在这一章讲了链接时符号的解析规则,这是最基本的但是容易被忽略的东西。

在C语言中,声明和定义是有区别的,声明只需要告知编译器变量的存在,不需要分配存储空间,例如:

定义不仅要告诉编译器变量的存在还有为变量分配存储空间,例如:

int a=1;

但是,当一个变量在作用域范围内只有声明,没有定义时,编译器会自动将第一个声明认定为变量的定义,下面我们来看C语言中的符号解析规则。

规则1:不允许有多个对同一变量或者函数的定义。

比如a.c中函数为:

 1 int a=123;
 2
 3 int main(void)
 4
 5 {
 6
 7 printf(“hello world”);
 8
 9 return 0;
10
11 }

b.c中的函数为:

 1 int a=121;
 2
 3 int main(void)
 4
 5 {
 6
 7 printf(“hi world”);
 8
 9 return 0;
10
11 }

这两个函数在进行链接的时候会出现错误,连个文件中都对同一个函数main()进行了定义,而且他们还对同一个变量进行了定义,这两条都违反了规定一,因此在调用的时候会出粗。

规则2:如果有一个符号定义和多个符号的声明,则选择被定义的符号。

比如两个函数a.c和b.c:

a.c:

b.c:

两个文件中都对a进行了定义和声明,运行结果如下图所示,当出现一个变量定义和多个变量声明的时候应该要符合规则2,选择变量的定义。所以这个程序中全局变量a在f()中被修改为121,结果保存在全局变量a的存储空间中。

规则3:如果有多个字符的声明,则从其中任选一个作为符号的定义。

a.c

b.c  

这个程序中有a的定义和a的声明,根据解析规则2是不会造成链接错误的,根据规则2我们知道b.c程序中对于a的操作实际是对a.c中的全局变量a进行操作的。但是在b.c中的声明的变量是双精度的,双精度的变量是8个字节,整型的数字是4个字节。因此a在进行赋值之后会把b的空间也占掉就会出现下面的错误显示。

书上的程序是b.c中赋值为0.0打印出来之后最后a,b的值都为0,解释为将8个字节都清0了。后来我处于好奇觉得如果赋值为其他的数字,比如3.5会不会显示成a=3,b=5。然后改完程序发现,a打印整数显示0,b打印整数显示为1074528256。紧接着我去查了double类型数字在机内的指数形式表示分为四部分,数符,尾数,指数符,指数四个部分,double类型数字数符加尾数占48位,指数符加指数占16位。因此,会出现乱码这种情况,至于具体的为什么产生的是0和1074528256,我觉得肯定是可以算出来为什么的,但是具体数符,尾数,指数符,指数是怎么存储的,占多少位我还不清楚,接下来有时间时的话会去算一算,深究一下。

总结这几天的学习来说,学习编程,主要还是在于实践,一定要敲代码。我在博客中举的例子一般都是我第一次看书的时候没有完全理解的东西,有些话说的很简单,看似理解其实并没有理解,只是理解了字面意思,甚至来说书上的例子都不能够完全帮助你去理解。每次遇到这些不懂得东西,我都会把书上的例子敲出来,运行然后去理解,不知道为什么的话去修改一下参数,加断点去调试去看,这样能够比较好的理解。在看书和敲书上代码的时候要多问一下为什么看看能不能自己去解答,通过改代码编译实现来验证自己的解答,如果正确那说明自己理解的没有问题,如果错误那就要找到错在哪,最终才能真正的理解。

时间: 2024-12-12 06:44:05

函数知识学习和第一周简单总结的相关文章

学习Linux第一周所有命令总结

一周总结 开学第一周,总结这周所学知识点 以命令首字母顺序整理 alias 用来设置指令的别名 alias命令的作用只局限于该次登入的操作. 若要每次登入都能够使用这些命令别名,则可将相应的alias命令存放到bash的初始化文件/etc/bashrc中. 或者存放在用户家目录的.bashrc中 用法 alias 新的命令='原命令 -选项/参数' unalias 别名 (删除别名) unalias -a 别名 (删除全部别名) 编辑家目录下配置文件(只在当前用户生效) vim ~/.bashr

javascript学习笔记第一周Array

Javascript第一周 Array数组 创建数组 自定义方式和实例化方式 使用数组 1. join() join方法是将数组中的元素连接成字符串.参数可选.参数即是连接符.为空时,参数为逗号. 2.reverse() reverse方法是将数组里的元素的顺序全部颠倒,逆序排列. 3.sort() sort方法,是将数组中的元素排序.默认无参时按ascii增序排列.可以一个参数.该参数是一个比较函数,比较函数有两个参数. 4.concat() 将数组和参数合并成一个新数组并返回.参数可以是单个

javascript学习笔记第一周DOM

Javascript第一周 DOM基础 DOM (Document Object Model) 即文档对象模型 DOM 有三个等级,分别是 DOM1.DOM2.DOM3. 获取DOM元素的方法根据W3C标准有以下几种: 1.getElementById() getElementById()方法,接受一个参数:获取元素的 ID.如果找到相应的元素则返回该元素的 HTML 对象,如果不存在,则返回 null. 2.getElementsByTagName() getElementsByTagName

javascript学习笔记第一周Math

Javascript第一周 Math常用的方法 1.parseInt() 取整:把字符串最前边的整数取出来并返回 2.Math.ceil() 向上取整:有小数就整数部分加1 3.Math.round() 四舍五入 4.Math.floor() 向下取整 5.Math.abs() 返回数的绝对值 Math的方法 Math.abs():计算绝对值. Math.acos():计算反余弦值. Math.asin():计算反正弦值. Math.atan():计算反正切值. Math.atan2():计算从

2020年度春季学习总结--第一周

日期:2020.02.23 博客期:157 星期日 其实吧,感觉状态不是很好,希望早点能够回到学校学习,在这里没有自习室的好氛围.那么,简单地评价一下这一周,我还是在主要攻克<崩溃大陆>的修改器,那个无限物品实在是太难做了,首先是我没有学过关于浮点数的汇编,更致命的是它的赋值代码是单独分离出来的,就相当于你使用的双精度不是 C 语言里的基础类型 double ,而是 Java 语言里的 Double 类!这个类有固定的赋值函数,所以我们使用 CE 找到修改的汇编代码的时候会发现好多 doubl

2017.3.12 H5学习的第一周

本周我开始了H5的学习,在这一周里我们从html的基本标签开始一直讲到了才算css的用法,接下来我将记录下来本周我学到的H5的内容. 首先是声明文档,声明文档类型是HTML5文件,它在HTML文档必不可少且必须放在文档第一行. 写法:<!DOCTYPE html>. 接着我们学习了html的基本结构: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title&

学习编程第一周

学习编程已经一周时间了,断断续续的从视频和书本这周断断续续的看看视频看看书自学Java,心想着是学习Android的,后来根据了解知道学习android是要有一点java基础的,所以开始了java的学习.现在刚学不久有好多还是不怎么会记得第一天学习时,还是同样的编写一句"Holle world!"还要对着把代码敲上去模仿呢?现在大概的,简单的代码还是可以自己敲出来,不过时间还是需要一点点,而且经常编译不通过要重复修改. 这几天基本上掌握了不少语法不过有些系统一点的知识还是不太明白 im

JS学习:第一周——NO.3面向对象

[面向对象基础知识] 封装:对于功能相同的代码,我们只需封装一次,以后再遇到类似的功能,只需调用即可,无需重写,避免大量冗余代码. 对象的特征:方法和属性: 面向对象的特点: 封装:低耦合高内聚: 继承:子类继承父类的属性和方法,但是不影响父类的功能: 多态:主要包括重载和重写: 备注:①重载:JS没有严格意义上的重载,但是有类似重载的功能,传不同的参数可以实现不同的功能, ②重写:子类可以重写父类的方法属性: [单例模式](本质就是对象) 单例模式优缺点: (1)实现模块化开发,是最简单的模块

struts2学习的第一个简单例子

下面是本人学习struts2的第一个例子 1,建立工程,把相关的jar包复制到项目的lib目录下面,使用到的jar和公测的大体结构如下图: 2,编辑web.xml,配置过滤器 <?xml version="1.0" encoding="UTF-8"?><web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="