赞
踩
函数的思想:从上到下,逐步求解问题的过程。将一个大的问题拆开成一个个小问题,每一个小问题都有与之对应的解决方案,这个解决方案就是“函数”。
1.main函数之前:
2.main函数之后:需要在调用函数之前声明该函数,函数头+分号 就是函数声明
表示形式:
- 类型标识符 函数名(形式参数)
- {
- 函数体代码;
- }
类型标识符:表示函数要带出的结果的类型,既返回值的数据类型。
注意:
1、数组类型也是数据类型,但这里不能用数组类型来表示返回值的类型。
2、如果函数不需要带出什么结果,此时返回结果的类型说明符一般设计为void。如果类型为void,一般不写return。
3、如果返回结果的类型与类型说明符不一致,以类型说明符为准,最终结果的类型都会转为类型说明符表示的类型。
4、类型说明符如果不写,默认是int型。
函数名:函数的入口地址,命名规则符合标识符的命名规则。(由字母、数字、下划线组成组成,不能以数字开头)
形式参数:表示该函数要用到的数据,表明将来使用时需要用到的实际参数该怎么写。
注意:
1、每一个形参变量都必须明确指定类型,不能写成(int a,b)。
2、实参和形参对应的关系:类型匹配,个数相同,顺序一一对应。
3、函数传参,传递的是实际参数的数值(值传递)。
4、如果不需要接收实际参数,形参一般设计为void(表示空类型)。
函数体代码:这是用来实现函数具体功能的代码。
eg:写一个函数,实现两数求和。
1.先确定函数名
2.考虑函数需要用到哪些数据 ---- 形参
形参的写法:
(数据类型 形参变量名1,数据类型 形参变量名2 ...)
3.处理数据---- 函数体的具体实现
4.考虑需不要带出结果 --- (返回值对应)类型说明符
- #include <stdio.h>
-
- //函数的定义
- int add(int num1,int num2)
- {
- int sum;
- sum = num1 + num2;
-
- return sum;
- }
-
- int main()
- {
- int ret;
-
- //函数的调用
- ret = add(1,2);
- printf("ret = %d\n",ret);
-
- return 0;
- }
1、函数语句
把函数调用作为一个语句。如"printstar(); "这时不要求函数带回值, 只要求函数完成一定的操作。
2、函数表达式
函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值以参加表达式的运算。例如: c=2*max(a,b);函数 max 是表达式的一部分,它的值乘2再赋给c。
3、函数参数
函数调用作为一个函数的实参。
例如: m=max(a,max(b,c));
其中 max(b, c) 是一次函数调用,它的值作为 max 另一次调用的实参。 m的值是a,b,c三者中的最大者。
又如: printf ("%d\n", max (a,b));
也是把 max(a, b) 作为 printf 函数的一个参数。
函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数的参数本来就要求是表达式形式。
在函数里又调用另一个函数,叫做函数的嵌套调用。
注意:函数不支持嵌套定义(在定义的函数里又定义新的函数),但是可以嵌套调用。
函数调用的关系:
调用者与被调用者
- int main(void)
- {
- printf("%d\n",getMonthDays());
- return 0;
- }
这个个示例的代码里面:
main 为调用者 ---main函数是整个程序的入口,只能作为调用者
getMonthDays --- 在此处是被调用者
实现函数调用的本质,实际上是利用了栈的结构,先入后出,保证了函数可以层层调用。
栈:实际上是一种数据结构,数据结构表示数据的一种组织形式。栈的特点是:先进后出(first in last out)FILO。
从c语言角度的栈,本质上是一块内存空间,只是按照栈这种数据结构来处理和使用的。
栈还可以放局部变量,变量的空间自动申请,自动释放。
c语言程序把内存划分了五个区域,栈只是其中的一个区域,栈(主要用来存放自动变量或函数调用的数据),堆(空间大,堆上的空间使用需要手动申请,手动释放),字符串常量区(只读),静态区,也叫全局区(用来存放全局变量和静态变量),代码区(只读)。
在 Linux 系统中,默认情况下栈的大小通常为 8MB,这是一个常见的默认设置。 然而,这个默认值是可以修改的。修改栈大小的方式可能因不同的情况和需求而有所不同。 一种常见的方法是通过编译器的选项来设置。例如,在使用 GCC 编译器时,可以使用 `-Wl,--stack=<size>` 选项来指定栈的大小,其中 `<size>` 是以字节为单位的栈大小值。 另外,在一些特定的环境或应用场景中,可能还可以通过系统配置文件或相关的内核参数来进行修改。 需要注意的是,修改栈大小应该谨慎进行。如果将栈大小设置得过小,可能会导致程序在运行时出现栈溢出的错误。相反,如果设置得过大,可能会浪费系统资源。 例如,如果一个程序需要处理大量的递归操作,可能需要适当增加栈的大小以避免栈溢出。但如果是一个简单的小型程序,过大的栈大小可能是不必要的。
递归就是函数自己调用自己,递归有两种形式,一是直接递归,二是间接递归。递归类似于循环——递归是一种特殊的循环。
下面是递归的几个简单的示例:
- #include <stdio.h> // 包含标准输入输出头文件
-
- /**
- * 计算斐波那契数列的第 n 项
- * @param n 项数
- * @return 斐波那契数列第 n 项的值
- */
- int pbnq(int n)
- {
- if(n==1 || n==2) // 如果是第 1 项或第 2 项
- {
- return 1; // 返回 1
- }
- else // 否则
- {
- return pbnq(n-1)+pbnq(n-2); // 递归计算,前两项之和
- }
- }
-
- /**
- * 计算 1 到 n 的累加和
- * @param n 上限
- * @return 1 到 n 的累加和
- */
- int sum(int n)
- {
- if (n==1) // 如果 n 为 1
- {
- return 1; // 返回 1
- }
- else // 否则
- {
- return sum(n-1)+n; // 递归计算,前 n - 1 项的和加上 n
- }
- }
-
- /**
- * 计算 n 的阶乘
- * @param n 数字
- * @return n 的阶乘
- */
- int jieCheng(int n)
- {
- if (n==1) // 如果 n 为 1
- {
- return 1; // 返回 1
- }
- else // 否则
- {
- return jieCheng(n-1)*n; // 递归计算,前 n - 1 项的阶乘乘以 n
- }
- }
-
- /**
- * 主函数
- */
- int main()
- {
- int n; // 定义输入的数字
- scanf("%d",&n); // 从用户输入获取数字
-
- //printf("%d\n",sum(100));
- //printf("%d\n",jieCheng(n));
- printf("%d\n",pbnq(n)); // 输出斐波那契数列的第 n 项
-
- return 0;
- }
经典的汉诺塔问题:
汉诺塔(Tower of Hanoi)是一个经典的数学问题和递归算法的示例。
问题描述:
有三根柱子 A、B、C ,在 A 柱上有 n 个圆盘,圆盘大小不等,大的在下,小的在上。要把这 n 个圆盘从 A 柱移动到 C 柱,在移动过程中始终保持大盘在下,小盘在上。每次只能移动一个圆盘,并且只能在三根柱子之间移动。解决思路:
通过递归的方式来解决。
当只有一个圆盘时,直接将其从 A 柱移动到 C 柱。
当有多个圆盘时,把上面 n - 1 个圆盘看成一个整体,先将这 n - 1 个圆盘从 A 柱借助 C 柱移动到 B 柱,然后把最大的圆盘从 A 柱移动到 C 柱,最后再把 B 柱上的 n - 1 个圆盘借助 A 柱移动到 C 柱。
- #include <stdio.h> // 包含标准输入输出头文件
-
- /**
- * 移动函数,用于打印移动的起始位置和结束位置
- * @param befor 起始位置
- * @param after 结束位置
- */
- void move(int befor, int after)
- {
- printf("%c ---> %c \n",befor,after); // 打印移动的起始位置和结束位置
- }
-
- /**
- * 汉诺塔问题的递归函数
- * @param n 盘子的数量
- * @param begin 起始柱子
- * @param mid 中间柱子
- * @param end 目标柱子
- * @return 无
- */
- int hannuo(int n, int begin, int mid, int end)
- {
- if(n == 1) // 如果只有一个盘子
- {
- move(begin,end); // 直接从起始柱子移动到目标柱子
- }
- else // 如果盘子数量大于 1
- {
- hannuo(n-1,begin,end,mid); // 先将上面 n - 1 个盘子从起始柱子借助目标柱子移动到中间柱子
- move(begin,end); // 将最底下的盘子从起始柱子移动到目标柱子
- hannuo(n-1,mid,begin,end); // 再将中间柱子上的 n - 1 个盘子借助起始柱子移动到目标柱子
- }
- }
-
- /**
- * 主函数
- */
- int main()
- {
- int n; // 定义盘子数量变量
- scanf("%d",&n); // 从用户输入获取盘子数量
- hannuo(n,'A','B','C'); // 调用汉诺塔函数进行计算
-
- return 0;
- }
普通变量可以作为函数参数,数组也可以作为函数参数。
数组作为函数参数, 传递的是数组首元素的地址。---数组名可以做形参,也可以做实参。
1、数组元素作为函数参数
由于实参可以是表达式,而数组元素可以是表达式的组成部分,因此数组元素当然可作为函数的实参,与用变量作实参一样,是单向传递,即“值传送”方式。
2、数组本身作为函数参数
总结:一维整形数组做函数的参数
做形参:写成数组形式,还需要传数组长度
做实参:传数组名,数组长度
- eg:
- printArrray(int a[],int len) //函数头,数组作为形参
- //printArrray (int *a,int len) ---编译器最终理解的形式
-
- printArray(a,len); //调用函数
练习:
- #include <stdio.h> // 包含标准输入输出头文件
-
- /**
- * 打印数组函数
- * @param a 数组
- * @param len 数组长度
- */
- void printfArray(int a[],int len)
- {
- int i; // 循环变量
- for ( i=0; i<len; i++ ) // 遍历数组
- {
- printf("a[%d] = %d\n",i,a[i]); // 打印数组元素
- }
- }
-
- /**
- * 数组逆序函数
- * @param a 数组
- * @param len 数组长度
- */
- void nixu(int a[], int len)
- {
- int i=0; // 起始索引
- int j=len-1; // 结束索引
- int temp; // 临时变量用于交换
-
- while(i<j) // 当起始索引小于结束索引时
- {
- temp = a[i]; // 交换元素
- a[i] = a[j];
- a[j] = temp;
- i++; // 起始索引递增
- j--; // 结束索引递减
- }
- return ;
- }
-
- /**
- * 插入排序函数
- * @param a 数组
- * @param len 数组长度
- */
- void crpaixu(int a[], int len)
- {
- int i=0, j=0; // 循环变量
- int temp; // 临时变量用于存储待插入元素
-
- for( i=1; i<len; i++ ) // 从第二个元素开始
- {
- temp = a[i]; // 保存当前待插入元素
- j = i;
- while(j>0 && temp<a[i-1]) // 寻找插入位置
- {
- a[i] = a[i-1]; // 元素后移
- j--;
- }
- a[j] = temp; // 插入元素
- }
- return ;
- }
-
- /**
- * 二分查找函数
- * @param a 数组
- * @param len 数组长度
- * @param n 要查找的数字
- * @return 找到返回索引,未找到返回 -1
- */
- int chazhao(int a[], int len, int n)
- {
- int begin, mid, end; // 起始、中间、结束索引
- begin = 0;
- end = len - 1;
-
- while ( begin <= end ) // 当查找范围有效
- {
- mid = (begin+end)/2; // 计算中间索引
-
- if( n < a[mid] ) // 如果要查找的数字小于中间元素
- {
- end = mid - 1; // 缩小查找范围到前半部分
- }
- else if ( a[mid] < n ) // 如果中间元素小于要查找的数字
- {
- begin = mid + 1; // 缩小查找范围到后半部分
- }
- else
- {
- break; // 找到
- }
- }
-
- if (begin <= end) // 如果找到了
- {
- return mid; // 返回索引
- }
- else
- {
- return -1; // 未找到返回 -1
- }
-
- }
-
- /**
- * 主函数
- */
- int main()
- {
- int a[] = {1,2,3,4,5,6,7,8,9}; // 定义并初始化数组
- int len = sizeof(a)/sizeof(a[0]); // 计算数组长度
-
- /*printfArray(a,len);
- printf("-------------------\n");
- nixu(a,len);
- printfArray(a,len);
- printf("-------------------\n");
- crpaixu(a,len);
- printfArray(a,len);
- printf("-------------------\n");
- */
-
- int n; // 要查找的数字
- printf("input n : "); // 提示输入
- scanf("%d",&n); // 读取输入
-
- chazhao(a,len,n); // 执行查找
-
- if(chazhao(a,len,n)>=0) // 如果找到
- printf("found!\n"); // 打印找到
- else
- printf("no found!\n"); // 打印未找到
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。