函数就是一个能完成特定功能的模块,其程序代码独立,可以给函数传递参数,也可以得到返回值。函数的实现人员把函数设计成一个黑盒子,隐藏了实现细节,并对外部提供尽可能简单的接口。对此对于函数调用方来说,无需知道函数的内部工作原理,仅需知道功能、参数、返回值即可。
一 函数定义和声明 1.1函数定义函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。一般形式如下:
int function(int a , int b)
{
int c;
c = a + b;
return c;
}
1.2函数声明
函数的说明就是指函数原型 其中,<形式参数说明>可以缺省说明的变量名称,但类型不能缺省.
例如, double Power(double x, int n) ; double Power(double, int);
函数的使用也叫函数的调用,形式如下: 函数名称(〈实际参数〉)
实参就是在使用函数时,调用函数传递给被调用函数的数据。需要确切的数据
函数调用可以作为一个运算量出现在表达式中,也可以单独形成一个语句。对于无返回值的函数来讲,只能形成一个函数调用语句。
tips:实参和形参的区别?
形参指的是出现在函数定义中的参数列表。实参指的是函数调用时,里面的参数。如下例程所示,函数定义中,a,b为形参,函数在main中调用时,m,n为实参。整个程序运行过程中,是将实参m、n的数据传递到开辟的形参a、b中,实现整个程序的功能。
int function(int a , int b)
{
return a + b;
}
int main(int argc , char **aggv)
{
int m = 10 , n = 20;
int c = 0;
c = function(m , n);
}
2.2 函数的参数传递(重点)
函数之间的参数传递方式:
全局变量、复制传递方式、地址传递方式
1、全局变量传递
全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的,全局变量一经定义后就会在程序的任何地方可见。函数调用的位置不同,程序的执行结果可能会受到影响。不建议使用。
使用代码示例如下:
#includeint n; double factorial(); int main(int argc, char const *argv[]) { double s = 0; printf("input:"); scanf("%d", &n); s = factorial(); printf("%en", s); return 0; } double factorial() { double ret = 1; int i; for (i = 1; i < n; i++) ret *= i; return ret; }
2、复制传递方式(值传递)
调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始化。形参是新开辟的存储空间,因此,在函数中改变形参的值,不会影响到实参。如下程序所示:
#includevoid rev(int a , int b) { int t = 0; t = a; a = b; b = t; printf("a= %d , b= %dn", a, b); printf("a addr:%p , b addr:%pn",&a,&b); } int main(int argc , char **aggv) { int m = 10 , n = 20; rev(m , n); printf("m = %d, n = %dn", m, n); printf("m addr:%p , n addr:%pn",&m,&n); }
此代码中,目的是实现数据的交换功能,但是打印结果却不符合需求(俩数交换),就是我们提到的“在函数中改变形参的值,不会影响到实参”;
形参和实参的特点:
①、形参只有在函数被调用时才会分配内存空间(在栈上),在调用结束后,释放分配的内存空间。因此形参只在函数内部有效。
②、实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,进行函数调用时,必须具有特定的值,以便把这些值传给形参。
③、形参和实参在数量上、类型上、顺序上应该严格一致,否则发送“类型匹配错误”。
3、地址传递方式
按地址传递,实参为变量的地址,而形参为同类型的指针。
被调用函数中对形参的操作,将直接改变实参的值(被调用函数对指针的目标操作,相当于对实参本身的操作)。
#includevoid rev(int *a , int *b) { int t = 0; t = *a; *a = *b; *b = t; printf("*a= %d , *b= %dn", *a, *b); printf("a addr:%p , b addr:%pn",&a,&b); } int main(int argc , char **aggv) { int m = 10 , n = 20; rev(&m , &n); printf("m = %d, n = %dn", m, n); printf("m addr:%p , n addr:%pn",&m,&n); }
如果只是实现功能,不改变目标,可以使用值传递。如果要改变目标(实参),比如实现交换,小写转大写等,让目标值(实参)发生变化,就要用地址传递。
三 函数和数组 3.1 传递数组当形参是数组形式时,其本质也是一个指针。数组作为实参传递时,形参并没有复制形参所有的内容,而是复制了实参数组的首地址。
由于数组的特殊性,只要知道了数组的首地址,就可以依次访问数组中所有元素。
示例程序如下(计算数组所有元素和及数组中奇数个数):
#include3.2 传递指针int test_array(int a[] , int n , int *p) { int i = 0, sum = 0; *p = 0; for (i = 0; i < n; i++) { sum += a[i]; if(a[i]%2) (*p)++; } return sum; } int main(int argc, char **argv) { int a[] = { 9 , 12 , 2 , 3 , 29 , 31 , 40 , 80}, n = 0; int sum = 0 , odd = 0; n = sizeof(a)/sizeof(int); sum = test_array(a,n,&odd); printf("sum = %d odd numbers count = %dn",sum,odd); return 0; }
#include3.3 main函数参数int test_array(int *a , int n , int *p) { int i = 0, sum = 0; *p = 0; for (i = 0; i < n; i++) { sum += *(a+i); if(*(a+i)%2) (*p)++; } return sum; } int main(int argc, char **argv) { int a[] = { 9 , 12 , 2 , 3 , 29 , 31 , 40 , 80}, n = 0; int sum = 0 , odd = 0; n = sizeof(a)/sizeof(int); sum = test_array(a,n,&odd); printf("sum = %d odd numbers count = %dn",sum,odd); return 0; }
形式:int main(int argc, char **argv)
参数说明:argc是给main传递的参数个数 , argv是具体的参数集合。
示例如下:
#include四 综合练习int main(int argc, char const *argv[]) { int i = 0; printf("argc = %dn" , argc); for (i = 0; i < argc ; i ++) printf("argv[%d] = %sn", i, argv[i]); return 0; }
1、实现求x的n次方的函数
答:
#includefloat my_pow(float a,int n); int main(int argc,char *argv[]) { float a = 2; float sum = 0; int n = 10; puts("please input a:"); scanf("%f",&a); puts("please input n:"); scanf("%d",&n); sum = my_pow(a,n); printf("%frn",sum); return 0; } float my_pow(float a,int n) { int i = 0; float sum = 1; for(i = 0;i sum = sum*a; } return sum; }
2、编写一个函数,统计字符串中小写字母的个数,并把字符串中的小写字母转化成大写字母,并输出转换后的字符串及小写字母个数。
#include#include int my_str1tostr2(char *str); int main(int argc,char *argv[]) { char str[100] = {0}; char *p = str; int num = 0; puts("please input a str:"); gets(p); num = my_str1tostr2(p); printf("%s %drn",p,num); return 0; } int my_str1tostr2(char *str) { int num = 0; while(*str != ' ') { if(islower(*str)) { num++; *str = toupper(*str); } str++; } return num; }
3、编写函数,计算一个一维整型数组的所有元素之和。
答:
#includeint sum_array(int *str,int n); int main(int argc,char *argv[]) { int a[10] = {0}; int sum = 0,i = 0; int *p = a; for(i = 0;i < 10;i++) { scanf("%d",p+i); } p = a; sum = sum_array(p,10); printf("%drn",sum); return 0; } int sum_array(int *str,int n) { int sum = 0; int i = 0; while(i sum += *(str+i); //str++; i++; } return sum; }
4、 编程实例:编写函数,删除字符串中的空格。
答:
#includevoid del_sapce(char *s1); int main(int argc,char *argv[]) { char s[] = " a b s h"; puts(s); del_space(s); puts(s); return 0; } void del_space(char *s1) { char *s2 = s1; while(*s1 != ' ') { if(*s1 == ' ') { s1++; } else { *s2 = *s1; s1++; s2++; } } *s2 = ' '; }
5、利用函数,实现strlen函数的功能。
答:
#includeint my_strlen(const char *str); int main(int argc ,char *arrgv[]) { char str[100] = {0}; char *p = str; int length = 0; puts("please input a str :"); gets(p); length = my_strlen(p); printf("the str length is: %dn",length); return 0; } //确定指针目标的值在这里不需要修改,尝试使用const修饰符 int my_strlen(const char *str) { int n = 0; while(*str++ != ' ') n++; return n; }
ps:欢迎大佬指正,共同学习进步。



