《一站式C编程》读书笔记(5)

第三章 简单函数
这个章节的内容需要仔细看,个人觉得比较重要哦。。。
3.1 数学函数
例3.1 在C语言中使用数学函数

#include #include

int main(void)
{
double pi=3.1416;
printf("sin(pi/2)=%f\n ln1=%f \n",sin(pi/2),log(1.0));
return 0;
}

运行结果如下:
屏幕快照 2016-07-22 下午3.38.56

例如log(1.0)(数学中写一个函数有时候可以省略括号,但是C语言中一定要加上括号)
在C语言的术语中,1.0是参数,log是函数(Function),log(1.0)是函数调用(Function Call)。Log(1.0)可以称作表达式,并且这个表达式是由操作数log和函数调用运算符()括号组成,函数调用运算符是一种后缀运算符(Postfix Operator),()括号及其中的参数是操作数log的后缀。操作数log是一个函数名(Function Designator),它的类型是一种函数类型(Function Type)。Log(1.0)这个表达式的值是取自然对数运算的结果,类型是double型,在C语言中函数调用表达式的值称为函数的返回值(Return Value)。
现在我们可以完全理解printf语句了:原来printf也是一个函数,上例中的printf(”sin(pi/2)=%f\n ln1=%f \n”,sin(pi/2),log(1.0))是带三个参数的函数调用,而函数调用也是一种表达式,因此printf语句也是表达式语句的一种。我们调用printf不是为了得到它的返回值,而是为了利用它所产生的副作用(Side Effect)——打印。C语言的函数可以有Side Effect,这一点是它和数学函数在概念上的根本区别。(这里的内容是我第一次看到,感觉有意思,写出来大家看看。)
在学习的过程中,初学者一开始接触到的很多概念从严格意义上说是错的,但是很容易理解,随着一步步学习,在理解原有概念的基础上不断纠正,不断泛化(Generalize)。(这段话的内容呢,我在开始看这本书的时候发现有些改变跟之前我接触到的不同,我就没有写入读书笔记,以后我在写笔记的时候会写出来,并点出来,这样可以供大家参考)
程序第一行的#号(Pound Sign,Number sign或Hash Sign)和include 表示包含一个头文件(Header File),后面尖括号<>(Angle Bracket)中就是文件名(这些头文件通常位于/usr/include目录下。)
查看/usr/include 目录下的文件可以使用一下命令:

$cd /usr/include
$ls

头文件中声明了我们程序中使用的库函数,根据县声明后使用的原则,要使用printf函数必须包含stdio.h,要使用数学函数必须包含math.h。
接下来要注意的一点就是书中写了使用math.h库函数编译程序时,gcc命令必须要加-lm。(然后在mac电脑下并不需要,因为math.h是在/usr/include文件目录下的)

3.2 自定义函数
书中从定义main函数来说明自定义函数,但是个人觉的main函数是一个固定写法,这里就略过main函数的定义,直接先看下面一个自定义函数。

#include

void newline(void)
{
printf("\n");
}

int main (void)
{
printf("First Line.\n");
newline();
printf("Second Line.\n");
return 0;
}

运行的结果是:

屏幕快照 2016-07-24 下午12.52.18

我看的是手机里的电子书,书中的结果是错误的,这里面大家注意下

函数定义的语法规则:
类型表示符 函数名(参数列表)
{
声明部分
语句部分
}
书中的表述看的不是很直观,因此我就改成这样子了。大家对照上面的例子中的函数定义,看看吧。
下面是代码阅读的顺序,大家可以参考一下:

屏幕快照 2016-07-24 下午1.13.29

下面澄清一下函数声明、函数定义、函数原型(Prototype)这几个概念。比如void threelines(void)//这一行
声明了一个函数的名字,参数类型和个数、返回值类型,这称为函数原型。在代码中也可以单独写一个函数原型后面加;号结束,而不写函数体,例如:

void threelines(void);

这种写法只能叫函数声明而不能叫函数定义,只有带函数体的声明才叫函数定义

#include

int main (void)
{
printf("First Line.\n");
newline();
printf("Second Line.\n");
threeline();
printf("Three line.\n");
return 0;
}

void newline(void)
{
printf("\n");
}

void threeline(void)
{
printf("\n\n\n");//书中用的是3个printf语句,我这里偷懒了:)
}

这样的顺序编译有的不同的平台编译结果不同,反正在mac下面会报错,编译通不过。所以建议使用下面的写法:

#include

void newline(void)
{
printf("\n");
}

void threeline(void)
{
printf("\n\n\n");
}

int main (void)
{
printf("First Line.\n");
newline();
printf("Second Line.\n");
threeline();
printf("Three line.\n");
return 0;
}

3.3形参和实参
形参相当于函数中定义的变量,调用函数传递参数的过程相当于定义形参变量并且用实参的值来初始化
这章内容个人认为理解起来有点难度,但是本书说的又比较简单,因此找到了这个来说明会比较清楚一点。

我觉得这篇文章里面说的比价哦清楚:实参与形参、全局变量与局部变量的区别

习题:
1. 定义一个函数increment,它的作用是把传进来的参数加1。例如:

void increment(int x)
{
x=x+1;
}
int main(void)
{
int i=1,j=2;
increment(i);
increment(j);
return 0;
}

我们在main函数中调用increment增加变量i和j的值,这样能奏效么?为什么?
答:不能奏效,因为i和j是作为实参将数据传到increment函数里面,但是传递的是形参,实参实际并没有传递进去。函数里面更改的内容只是形参的内容,函数调用结束了,x的值就被释放了。i和j没有发生任何改变。
2. 说出一下代码哪些属于函数声明,哪些属于函数定义,哪些属于函数原型。
main(){ } 都不是
int foo() 函数原型
int bar (void){ } 函数定义
void baz(int I,int); 函数声明

 

3.4 全局变量、局部变量和作用域

我们把函数中定义的变量称为局部变量(Local Variable),由于形参相当于函数中定义的变量,所以形参也是一种局部变量。全局变量(Global Variable)定义在所有的函数体之外,他们在程序开始运行时分配存储空间,在程序结束时,释放存储空间,在任何函数中都可以访问全局变量。

虽然全局变量用起来很方便,但是一定要慎用,能用函数传参代替的就不要用全局变量。

局部变量可以用类型相符的任意表达式来初始化,而全局变量只能用常量表达式初始化(Constant Expression)来初始化。如果全局变量在定义时不初始化则初始值为0,如果局部变量在定义时不初始化则初始值是不确定的。

0 Comments
Leave a Reply