在计算机科学中,子程序 ,一个大型程序中的某部分代码, 由一个或多个语句块组
成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软
件库。
- 库函数
- 自定义函数
C语言早期没有库函数
如果每个人都定义一个printf,那么
1.代码冗余
2.开发效率低
3.不标准
所以厂商就把常用的一些功能实现成函数,集成为库,由C语言直接提供。
C语言标准就可以规定库函数的标准:
int strlen(const char* str);
功能:求str 指向的字符串的长度。
所有的编译器都遵循此规则。
Cplusplus
可以在上面这个网站找到所有库函数。
- IO函数
字符串操作函数
字符操作函数
内存操作函数
时间/日期函数
数学函数
其他库函数
#include#includeint main()
{char arr1[] = "abcdef";
char arr2[20] = "XXXXXXXXXXXXXX";
//能把arr1中的abcdef拷贝到arr2;
strcpy(arr2,arr1);
printf("%s",arr2);
return 0;
}
// memory set
//内存设置
//size_t ->unsigned int
#include#includeint main()
{char arr[] = "hello sfy";
//设置内存的时候是以字节为单位的
//每个字节的内容都是一样的
memset(arr,'x',5);
printf("%s",arr);
return 0;
}
自定义函数自定义函数和库函数一样,有函数名,返回值类型和函数参数。
但是不一样的是这些都是我们自己来设计。
写一个函数可以找出两个整数中的大值。
int Max(int a,int b)
{return (a>b)?(a):(b));
}
写一个函数可以交换两个整形变量的内容。
x y 的修改不影响 ab
当实参传给形参时,形参是实参的一份临时拷贝,对形参的修改不会影响实参。
正确版本:
// *(&a) == a
void Swap(int *a,int *b)
{int tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
}
//改int传int的地址,int*接收,解引用修改
这两张图很重要
实际参数(实参):
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形
参。
形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内
存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。
练习:
- 写一个函数可以判断一个数是不是素数。
int is_prime(int val)//返回1是素数,返回0表示不是素数
{int i = 0;
if (val == 1)
{return 0;
}
for (i = 2; i<= val - 1; ++i)
{if (val % i == 0)
{ return 0;
}
}
return 1;
}
int main()
{printf("%d",is_prime(3));
return 0;
}
TDD 测试驱动开发
test driven development
先想函数怎么使用—-测试
测试场景想好之后,设计函数
写一个函数判断一年是不是闰年
int is_leap_year(int y)
{return (((y%4 ==0) &&(y%100!=0))||(y%400==0));
}
设计函数的时候,功能足够单一!
写一个函数,实现一个整形有序数组的二分查找。
int binary_search(int arr[],int val,int sz)//找到了返回下标,找不到返回-1
{int begin = 0;
int end = sz-1;
int mid = left+(right-left)/2;
int i =0;
while(left<=right)
{if(arr[mid]>val)
{ right = mid-1;
}
else if(arr[mid] left = mid+1;
}
else
return mid;
}
return -1;
}
数组在传参时,传的是首元素地址。
写一个函数,每调用一次这个函数,就会将 num 的值增加1。
int Plus(int *p)
{(*p)++;
}
函数的嵌套调用和链式访问#includevoid new_line()
{printf("hehe\n");
}
void three_line()
{int i = 0;
for(i=0; i<3; i++)
{new_line();
}
}
int main()
{three_line();
return 0;
}
函数可以嵌套调用,但是不能嵌套定义。
链式访问把一个函数的返回值作为另外一个函数的参数。
int main()
{int len = strlen("abc");
printf("%d",len);
}
printf("%d", printf("%d", printf("%d", 43)));
4 3 2 1
函数的声明和定义告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数
声明决定不了。
2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用。
3. 函数的声明一般要放在头文件中的。
只有一个文件的时候,把函数定义放到调用前面
分文件书写
可以把文件编译成一个静态库
把.h 和 .lib文件给别人就可以使用这个函数 然后点生成解决方案
要放在当前文件目录里
引别人的头文件 直接添加现有项
lib使用
自己包的不是库里的头文件要用双引号 “ ”
函数递归程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接
调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的但规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
递归
自己调自己,不过这个函数栈溢出了 Stack overflow
接受一个整型值(无符号),按照顺序打印它的每一位。
例如:
输入:1234,输出 1 2 3 4
每次调用函数在栈上开辟空间,消耗很大,栈溢出就是空间不够了,死递归的话。
递归的必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。
编写函数不允许创建临时变量,求字符串长度。
int my_strlen(char* str)
{if (*str != '\0')
{return 1+my_strlen(++str);
}
else
return 0;
}
int main()
{char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
return 0返回到上一次的调用
递归与迭代求n的阶乘的一个递归的方法。
int fac(int n)
{if (n<= 1)
{return 1;
}
else
return n*fac(n - 1);
}
int main()
{int n = 0;
scanf("%d", &n);
int ret = fac(n);
printf("%d", ret);
return 0;
}
迭代版本
int fac(int n)
{int i = 0;
int ret = 1;
for (i = 1; i<= n; i++)
{ret *= i;
}
return ret;
}
斐波那契数列
1 1 2 3 5 8 13 21 34 55……
前两个数一加,变成第三个数。
int Fib(int n)
{if (n<= 2)
{return 1;
}
else
{return Fib(n - 1) + Fib(n - 2);
}
}
递归太慢
用非递归算
让abc动,c=a+b,然后后移重复动作
int Fib(int n)
{int a = 1;
int b = 1;
int c = 1;
while (n>2)
{c = a + b;
a = b;
b = c;
n--;
}
return c;
}
汉诺塔问题
青蛙跳台阶
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
网页名称:【C语言】函数-创新互联
文章出自:http://scgulin.cn/article/dsgcee.html