函数: 比如说
main()函数 printf()函数 scanf()函数 strlen() strcpy() strcmp() strcat()函数 getchar()函数 arc4random()等
函数定义: 具有特殊功能的代码段 可以有多个输入 但最多只能有一个输出
函数: 返回值类型 函数名 (形式参数列表) {
函数体
return 返回值;
}
返回值类型 : void int float double char ….
可以是所有的基本数据类型 也可以没有返回值
若没有返回值 用void表示 此时函数里可以没有return语句
函数的四种形态: 无返回值 无参数, 有返回值 无参数, 有返回值 有参数, 无返回值 有参数
形态一: 无返回值无参数
void
myPrintf() {
printf ( " 我是一个无返回值无参数的函数 \n" );
printf ( " 我是一个无返回值无参数的函数 \n" );
}
形态二: 有返回值 无参数
int returnValue() {
return 10;
return 10;
}
形态三: 有返回值 有参数
//
计算
两个
整数的
和
//
形式参数列表需要给出形式参数的类型, 给出多个形式参数时需要用逗号隔开 且参数名不能相同 不同参数类型可以不同
int sumNumber(int num1, int num2){
return num1 + num2;
}
return num1 + num2;
}
形态四: 无返回值 有参数的函数
void printSum (int num1, int num2) {
printf("%d", num1 + num2);
printf("%d", num1 + num2);
}
调用函数的方法:
优先在main函数里调用函数
形态一:
int
main(
int
argc,
const
char
* argv[]) {
myPrintf();
return0;
}
形态二:
int
main(
int
argc,
const
char
* argv[]) {
//
有返回值的函数
用与其相同类型的变量接收函数返回值
int
number =
returnValue
();
//
再对返回值进行处理
printf
(
"%d"
, number);
return0;
}
形态三:
int
main(
int
argc,
const
char
* argv[]) {
//给出和函数形式参数个数及,类型相同的参数
int sum = sumNumber(10,11);
printf
(
"%d"
, sum);
return0;
}
形态四:
int
main(
int
argc,
const
char
* argv[]) {
printSum(5,6);
return 0;
}
注意: 可以在调用有返回值函数时不用相同类型变量接收它, 但是这样这个函数就毫无意义 因为函数实现的功能是通过返回值告诉主程序的
函数中 return的作用
1.无返回值时, 直接结束 return都不执行
2.有返回值时, 结束的同时 把值返回去
函数参数的两种形式:
1.实际参数 函数调用时的参数
2.形式参数 函数声明时的参数
函数调用时 相当于实际参数赋值给形式参数 参数间的传递是一个值的传递而不是地址的传递
注意: 数组作为参数时 不但要传入数组, 还要传入数组的长度(数组的元素个数)
void
bubbleSort(
int
a[],
int
length) {
for ( int i = 0 ; i < length - 1 ; i++) {
for ( int j = 0 ; j < length - 1 - i; j++) {
if (a[j] > a[j + 1 ]) {
int temp = a[j];
a[j] = a[j + 1 ];
a[j + 1 ] = temp;
}
}
}
for ( int i = 0 ; i < length - 1 ; i++) {
for ( int j = 0 ; j < length - 1 - i; j++) {
if (a[j] > a[j + 1 ]) {
int temp = a[j];
a[j] = a[j + 1 ];
a[j + 1 ] = temp;
}
}
}
}
int main(){
int a[10] = {0};
for (int i =0; i <10; i++) {
a[i] = arc4random() % (50-10 + 1) + 10;
printf("%d ",a[i]);
}
for (int i =0; i <10; i++) {
a[i] = arc4random() % (50-10 + 1) + 10;
printf("%d ",a[i]);
}
printf("\n");
bubbleSort(a, 10
); // 调用函数 同时给出数组长度
for(int i =0; i <10; i++) {
printf("%d ", a[i]);
printf("%d ", a[i]);
}
return0;
}
分析原因 a 代表 a[0]的地址 即 &a[0] 所以实参仅仅将数组首地址的地址传给了形参, 形参只知道首地址的位置, 但是形参并不知道这个数组具体多长, 所以还需要告诉形参数组的长度
函数写在哪?
首先得知道3点:
1. 函数包括声明, 实现, 调用 三部分才是完整的
2. main函数是主函数, 本质也是一个函数
3 .一个函数的内部是不能定义另一个函数的 只能调用
C语言的程序入口是main函数, 代码的执行是从上到下的. 系统编译的顺序也是如此. 系统会从整个程序文件的第一行开始编译, 直到发现main函数以后 开始执行main函数内容 而main 函数之前没有出现过的内容 也就是还未编译到的内容, 系统是不会发现的. 所以函数必须把其声明写在main函数之前, 否则在main函数内是无法调用的
所以
1. 自定义函数只能写在main函数外面
2. 函数必须得在main函数前声明
所以可以这么写一个函数
// 声明和实现同时完成
void fun( int x, int y) {
…;
}
int main (){
fun(x, y);
return 0;
}
或者
// 先声明 再在另一个地方实现
void fun(int x, int y);
int main() {
fun(x, y);
return 0;
}
void fun(int x, int y) {
…;
}
函数的嵌套调用:
//
声明一个函数
比较两个数的大小
返回大的数
int biggerNumber( int num1, int num2) {
return num1 > num2 ? num1 : num2;
}
// 比较三个数 , 返回最大值
int biggerNumber( int num1, int num2) {
return num1 > num2 ? num1 : num2;
}
// 比较三个数 , 返回最大值
int
sortThreeNumber(
int
num1,
int
num2,
int
num3) {
// 调用比较2个数的函数
int
max =
biggerNumber
(num1, num2);
max = biggerNumber (max, num3);
return max;
}
// 比较四个数 , 返回最大值
max = biggerNumber (max, num3);
return max;
}
// 比较四个数 , 返回最大值
int
sortFourNumber(
int
num1,
int
num2,
int
num3,
int
num4) {
// 调用比较3个数的函数
int
max =
sortThreeNumber
(num1, num2, num3);
max = biggerNumber (max, num4);
return max;
}
// 比较五个数 , 返回最大值
max = biggerNumber (max, num4);
return max;
}
// 比较五个数 , 返回最大值
int
sortFiveNumber(
int
num1,
int
num2,
int
num3,
int
num4,
int
num5) {
// 调用比较4个数的函数
int
max =
sortFourNumber
(num1, num2, num3, num4);
max = biggerNumber (max, num5);
return max;
}
int main( int argc, const char * argv[]) {
printf ( "5 个数中最大数是 :%d" , sortFiveNumber ( 37 , 45 , 7 , 9 , 55 ));
return 0 ;
max = biggerNumber (max, num5);
return max;
}
int main( int argc, const char * argv[]) {
printf ( "5 个数中最大数是 :%d" , sortFiveNumber ( 37 , 45 , 7 , 9 , 55 ));
return 0 ;
}
结果是 :
55
以上4个函数 有3个函数都是调用已有的函数来帮自己完成特定功能 明显简化了代码和逻辑
函数的递归调用:
递归调用就是自己调自己.
注意: 递归一定要有出口.
计算阶乘: s = 5!
int
function(
int
n) {
//
本函数用于计算
n
阶乘的值
if (n == 0 || n == 1 ) { // 当 n = 0, 或者 n = 1 时 阶乘的结果是 1
return 1 ;
} else { // 当 n > 1 时 n 阶乘就等于 (n-1) 的阶乘 乘以 n
return n * function (n - 1 );
}
}
计算过程: 将n = 5 传进函数function 即 function(5)
1. 5 != 0 && 5 != 1 所以结果等于 5 * function(4)
2. 4 != 0 && 4 != 1 所以结果等于 5 * 4 * function(3)
3. 3 != 0 && 3 != 1 所以结果等于 5 * 4 * 3 * function(2)
4. 2 != 0 && 2 != 1 所以结果等于 5 * 4 * 3 * 2 * function(1)
5. 1 != 0 但是 1 == 1 所以return 1, 结果等于 5 * 4 * 3 * 2 * 1
输入数字n 计算 (1 * 1)! + (2 * 2)! + … +((n - 1) * (n - 1))! + (n * n)!的值
//
递归方法
int
recursive(
int
num) { // num为给定的数字n
int sum = 1; // 用于储存计算结果值
if
(num ==
1
) { // 当num = 1 时, 出口
sum =
1
; // 算式的值为 (1 * 1)! = 1
}
else
{ // 当num > 1 即算式不止一元时
for
(
int
i =
1
; i <= num * num; i++) {
sum *= i; // 当前大小num = i下, sum = (i*i)!
}
sum += recursive(num - 1); // sum = (i*i)! + ((i-1)*(i-1))! 递归调用
}
return sum;
}
int
main(
int
argc,
const
char
* argv[]) {
printf
(
"%d"
,
recursive
(
4
));
//
调用递归方法
return 0;
}
事实上, 递归方法虽然代码短, 但是极耗计算机资源, 通常不建议使用.
递归方法通常都可以改写成普通调用方法的形式, 代码如下:
int
factorial(
int
num) { // 本函数用于计算单个数字阶乘的计算方法
int
sum =
1
;
for ( int i = 0 ; i < num * num; i++) {
sum *= (i + 1 );
}
return sum;
for ( int i = 0 ; i < num * num; i++) {
sum *= (i + 1 );
}
return sum;
}
int
sumOfFormula(
int
num) { // 本函数用于计算 N个元素之和
int
sum =
0
;
for ( int i = 0 ; i < num; i++) {
for ( int i = 0 ; i < num; i++) {
sum += factorial(i + 1); // 调用阶乘计算方法
}
return sum;
return sum;
}
int main(int argc,constchar * argv[]) {
printf
(
"%d\n"
,
sumOfFormula
(
4
));
//
调用普通方法
return 0;
}
变量的作用域:
变量根据其有效范围可分为全局变量和局部变量
注意: 外部变量和局部变量可重名, 但是再局部变量作用域内只能访问局部变量
简单而言 变量的作用域是在其所在的最近的大括号内, 它声明后的所有地方
如
int a;
(地点一: main 外)
int main() {
int b;
(地点二: main 内)
if(1) {
int c;
(地点三: if语句内)
for (int i = 0; i < 2; i++ ){
int j;
(地点四: for循环内)
}
}
}
变量a 在main外, 整个程序中, main外层没有大括号了所以 a的作用域是全局, 在代码中的任意地点均可访问.
变量b 在main内, 它所在最近的大括号即是main函数的大括号, 所以它的作用域在main 以内, 在地点一处不可调用变量b, 其余地点均可
变量c 在if内, 它所在最近的大括号即是if语句, 所以它的作用域是再if 以内, 在地点一地点二处不可调用, 其余地点均可访问.
变量i 和j 都在for循环内, 不太一样的是i实在 for循环的小括号内的, 大括号外. 因而i 比j 的作用域大了那么一点点, 因为 i++ 实在for循环的大括号全部执行完以后再执行的 , i , j均只能在地点四调用, 其他地点均无法访问
引申: 声明和实现的分离 有利于代码的查询更利于代码的封装保密
从函数抽象到类 同类型的函数放在一个类中
具体: 在一个文件中完成函数的声明, 在另一个文件中完成函数的实现 在Xcode环境内OC语言体现在
.h 文件里写函数声明, .m文件里写函数实现 以后会提
类调用其他类方法 需要引入头文件
引入头文件分两种方法
#import <xxxx.h>
#import “xxxx.h"
<>表示引入系统头文件, “” 表示引入自定义头文件