《c和指针》读书笔记3

来源:互联网 发布:小米max usb网络共享 编辑:程序博客网 时间:2024/05/02 04:46

读书笔记3

     下面是今天整理的第7章关于函数的内容。

1.函数定义

函数的定义就是函数体的实现。函数体就是个代码块。在函数被调用时执行。另外,函数声明出现在函数被调用的地方。函数声明向编译器提供该函数的相关信息。

具体语法:

类型

函数名

代码块

结构是

function

{

  .....

}

程序实例

#include<stdio.h>

int *

find_int{int key,int array[],int array_len)

{

             int i;

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

             {

                                     if(array[i]==key)

                                     return &array[i];

                                     }

                                     return NULL;

                                     }

2return语句return语句容许你在任意位置返回,并不一定在函数末尾。

它的用法:

return   expression

如果函数无需向调用程序返回一个值,它就被省略。注意,在没有返回值的函数声明里应该把函数类型确定为void3.函数声明

函数原型总结了函数定义的起始部分的声明,向编译器提供有关函数的类型及参数信息。使用原型最简单的方法是把它放到单独的一个文件中,如果源文件需要调用它的话,就直接用#include的指令就行了。

4.函数值得缺省认定

所有的函数都应该有原型,尤其是那些返回类型不是整形的函数,值的类型并不是值的内在本质,而是取决于它被使用的方式。

5.函数的参数

c函数的所有参数均以传值调用的方式进行传递,这意味着函数将获得参数值的一个拷贝。如果被传递的参数是一个数组名,并且函数使用下标引用该数组的参数,那么在函数中对数组元素进行修改实际上是调用函数中的数组元素,函数将访问数组元素,数组不会被复制,这被叫做传址调用。

大家只需记住两个原则就行

1.传递给函数的标量参数是传值调用的。

2.传递给函数的数组参数在行为上就像他们是通过传址调用一样。

比如奇偶校验程序

/*对值进行偶校验*/

int 

even_parity(int value,int n_bite)

{

                int parity=0;

                while(n_bite>0){

                parity+=value & 1;

                value>>=1;

                n_bite-=1;

                } 

                return (parity%2)==0;

                }

6,递归

c通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。

实例:

#include<stdio.h>

void

binary_to_ascii(unsighed int value)

{

                         usigned int quotient;

                         quotient=value/10;

                         if(quotient!=0)

                         binary_to_ascii(quotient);

                         putchar(value%10+'0');

                         }


下面来跟着这个递归函数:

我们以4267为初始值调用这个函数,当函数刚开始执行时,堆栈情况如上图;


接着,执行除法运算,结果如上图:

接着,if语句判断quotient非零,对函数执行递归调用,当函数第二次调用之初,堆栈情况如下:


以此类推,最后的输出结果为4267;

下面讨论一下递归与迭代。

以斐波那契数列为例;

斐波那契数其实就是一个数列,数列中每个数的值都是他前面两个数的和。

其递归形式表示为

fibonacci(n)=n<=1:1;

                        n=2:1;

                        n>2:fibonacci(n-1)+fibonacci(n-2);

它的算法实现为:

longfibonacci(int n){              if(n>2)              return 1;              return fibonacci(n-1)+fibonacci(n-2);              } 
它的迭代实现为:

longfibonacci(int n){              long result;              long previous_result;              long nextorder_result;              while(n>2)              {                        n-=1;                        nextorder_result=previous_result;                        previous_result=result;                        result=previous_result+nextorder_result;                        }                        return result;                        } 

其实用递归实现斐波那契数列是一个很极端的事情,这里有一个大的陷阱,就是计算
fibonacci(n-1)+fibonacci(n-2);
,大家可以算一算它的额外代价。它的代价不仅仅是一个冗余运算,每个递归调用都触发另外两个递归调用。而这两个递归调用的任何一个都会触发另外两个递归调用。,以后还是如此。例如,fibonacci(10),fibonacci(3)的值被计算了21次,但是在递归调用fibonacci(30)时,fibonacci(3)被调用了31万次。可见这是相当恐怖的。可是让人吐糟的是,国内很多教材还是这个例子当做递归函数的典型例子。哎。不知该如何评论!

总结这一章的几个要点:

1.return语句用于返回一个函数的返回值。没有返回值的函数的返回类型应该声明为void;

2.那些返回值不是整形的函数,调用之前声明这个函数是非常重要的。

函数的参数是通过传值调用进行传递的。他实际上传递的是参数的一个拷贝。

3.在函数中,数组参数中使用了下标引用。并且执行了间接引用,就是传址调用。

4.抽象数据类型ADT也叫做黑盒。由接口和实现两个部分组成。接口是共有的。实现是私有的。

5.如果一个函数在内部最后一条语句就是它本身的递归调用。那么就叫做尾部递归。尾部递归容易改写为循环的形式。并且效率更好。

有些函数的参数列表包含可变的参数数量。它可以使用头文件stdarg.h的头文件、来定义实现.





0 0