文章目录
- 1、函数的基本用法
- 2、函数的参数传递
- 2.1 全局变量
- 2.2 复制传递方式
- 2.3 地址传递方式
- 3、函数的传参—数组
- 4、指针函数
- 5、递归函数和函数指针
- 5.1 递归函数
- 5.2 函数指针
- 5.3 函数指针数组
1、函数的基本用法
函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。
一般形式如下:
-
<数据类型> <函数名称>(<形式参数说明>) { 语句序列; return[(<表达式>)]; }
-
<数据类型>
是整个函数的返回值类型。 -
return[(<表达式>)]
语句中表达式的值,要和函数的<数据类型>
保持一致。如无返回值应该写为void型 -
<
形式参数说明>
是逗号”,
”分隔的多个变量的说明形式 -
大括弧对
{<语句序列> }
,称为函数体;<语句序列>
是大于等于零个语句构成的
函数的说明就是指函数原型
其中,<形式参数说明>
可以缺省说明的变量名称,但类型不能缺省
- 例如:
double Power(double x, int n) ;
double Power(double, int);
函数的使用也叫函数的调用,形式如下:
函数名称(〈实际参数〉)
- 实参就是在使用函数时,调用函数传递给被调用函数的数据。需要确切的数据
- 函数调用可以作为一个运算量出现在表达式中,也可以单独形成一个语句。对于无返回值的函数来讲,只能形成一个函数调用语句。
编写一个函数显示 “Hello, guy! ”,然后编写主程序main调用它。
#include <stdio.h>
void Displayhello()
{
printf("Hello,guy!\n");
}
int main()
{
Displayhello(); //调用
return 0;
}
定义求xn值的函数( x是实数, n为正整数)
#include <stdio.h>
double power(double x, int n) //函数的说明(需要放在主函数前面)
{
double r = 1;
int i;
for (i = 1; i <= n; i++)
r *= x;
return r;
}
int main()
{
double x, ret;
int n;
printf("input:");
scanf("%lf%d", &x, &n);
ret = power(x, n);//函数的调用
printf("%lf %d = %lf\n", x, n, ret);
return 0;
}
2、函数的参数传递
函数之间的参数传递方式:
- 全局变量
- 复制传递方式
- 地址传递方式
2.1 全局变量
- 全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的
- 全局变量一经定义后就会在程序的任何地方可见。函数调用的位置不同,程序的执行结果可能会受到影响。不建议使用
例如:
#include <stdio.h>
double x = 2;//全局变量
int n = 3; //全局变量
double power();
int main()
{
// double x = 2;
// int n = 3;
double ret;
ret = power();
printf("%lf %d = %lf\n", x, n, ret);
return 0;
}
double power()
{
double r = 1;
int i;
for (i = 1; i <= n; i++)
r *= x;
return r;
}
2.2 复制传递方式
- 调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始化
- 形参是新开辟的存储空间,因此,在函数中改变形参的值,不会影响到实参
例如:
#include <stdio.h>
double power(double, int);
int main()
{
double x = 2;
int n = 3;
double ret;
printf("&x=%p &n=%p\n", &x, &n);
ret = power(x, n);
printf("%lf %d = %lf\n", x, n, ret);
return 0;
}
double power(double a, int b) //double a = x; int b = n;
{
double r = 1;
int i;
printf("&a=%p &b=%p\n", &a, &b);
for (i = 1; i <= b; i++)
r *= a;
return r;
}
例如:写一个函数,实现两个数据的交换
#include <stdio.h>
void swap(int x, int y);
int main()
{
int a = 10;
int b = 20;
printf("before:%d %d\n", a, b);
swap(a, b);
printf("after:%d %d\n", a, b);
return 0;
}
//int x = a; int y = b;
void swap(int x, int y)
{
int t;
t = x;
x = y;
y = t;
}
2.3 地址传递方式
- 按地址传递,实参为变量的地址,而形参为同类型的指针
- 被调用函数中对形参的操作,将直接改变实参的值(被调用函数对指针的目标操作,相当于对实参本身的操作)
#include <stdio.h>
void swap(int * x, int * y);
int main()
{
int a = 10;
int b = 20;
printf("before:%d %d\n", a, b);
swap(&a, &b);
printf("after:%d %d\n", a, b);
return 0;
}
//int * x = &a; int *y = &b;
void swap(int * x, int * y)
{
int t;
t = *x;//a
*x = *y;
*y = t;
}
例如:编写一个函数,统计字符串中小写字母的个数,并把字符串中的小写字母转化成大写字母
#include <stdio.h>
int str_fun(char * p);
int main(int argc, char *argv[])
{
char s[] = "welcome2025Beijing";
int n;
n = str_fun(s);
printf("n=%d %s\n", n, s);
return 0;
}
int str_fun(char * p) //char * p = s;
{
int num = 0;
while (*p != '\0') {//while (*p)
if (*p <= 'z' && *p >= 'a') {
num++;
*p -= ' ';
}
p++;
}
return num;
}
3、函数的传参—数组
全局数组传递方式
复制传递方式
- 实参为数组的指针,形参为数组名(本质是一个指针变量)
地址传递方式
- 实参为数组的指针,形参为同类型的指针变量
例如:编写函数,计算一个一维整形数组的所有元素的和
//写法1:
#include <stdio.h>
int array_sum(int data[], int n);
int main(int argc, char *argv[])
{
int a[] = {5, 9, 10, 3, 10};
int sum = 0;
sum = array_sum(a, sizeof(a)/sizeof(int));
//sizeof(a)/sizeof(int)=元素个数
printf("sum=%d\n", sum);
return 0;
}
int array_sum(int data[], int n) // int data[] = a;error int * data = a;
{//int n = sizeof(a)/sizeof(int);
int ret = 0;
int i;
for (i = 0; i < n;i++) {
printf("%d\n", data[i]);
ret += data[i];
}
return ret;
}
//写法2:
#include <stdio.h>
int array_sum(int * data, int n);
int main(int argc, char *argv[])
{
int a[] = {5, 9, 10, 3, 10};
int sum = 0;
sum = array_sum(a, sizeof(a)/sizeof(int));
printf("sum=%d\n", sum);
return 0;
}
int array_sum(int * data, int n) //int * data = a;
{//int n = sizeof(a)/sizeof(int);
int ret = 0;
int i;
for (i = 0; i < n;i++) {
printf("%d\n", data[i]);
ret += data[i];
}
return ret;
}
例如:编写函数,删除字符串中的空格
#include <stdio.h>
void del_space(char * s1);
int main(int argc, char *argv[])
{
char s[] = " h a sdf g ";
puts(s);
del_space(s);
puts(s);
return 0;
}
void del_space(char * s1)
{
char * s2;
s2 = s1;
while (*s1) {
if (*s1 == ' '){
s1++;
}
else {
*s2 = *s1;
s1++;
s2++;
}
}
*s2 = '\0';
}
多维数组与函数
- 多维数组作为参数在函数间的传递也有全局数组、复制传递和地址传递三种方式。
4、指针函数
指针函数是指一个函数的返回值为地址量的函数
指针函数的定义的一般形式如下
<数据类型> * <函数名称>(<参数说明>) {
语句序列;
}
返回值:全局变量的地址/static变量的地址/字符串常量的地址/堆的地址
下面程序是否有问题,若有问题,如何修改?
#include <stdio.h>
char * mystring() {
char str[20];//局部变量,
strcpy(str, “Hello”);
return str;
}
int main(void)
{
printf(“%s\n”, mystring());//最后结果乱码
return 0;
}
修改后
#include <stdio.h>
#include <string.h>
//char str[20];
char * mystring();
int main(int argc, char *argv[])
{
char * r;
r = getstring();
printf("---%s---\n", getstring());
//(*r)++;
puts(r);
return 0;
}
char * mystring()
{
//char str[20];//error
//static char str[20]; //静态变量
char * str = "hello"; //不需要改的情况下可以使用
// strcpy(str, "hello");
return str;
}
例如:编写一个指针函数, 删除一个字符串中的空格
#include <stdio.h>
#include <string.h>
char * del_space(char * s);
int main(int argc, char *argv[])
{
//char * r;
char str[]= " how are you ";
char s[50], s2[50];
// r = del_space(str);
// printf("---%s---\ n", r);
//strcpy(s, del_space(str));
strcpy(s2, strcpy(s, del_space(str)));//m=n=k
puts(str);
puts(s);
puts(s2);
return 0;
}
char * del_space(char * s) //char * s = str;
{
char * r = s;
char * p = s;
while (*s) {
if (*s == ' ')
s++;
else {
*p = *s;
s++;
p++;
}
}
*p = '\0';
return r;
}
例如:编写一个指针函数, 实现字符串连接
#include <stdio.h>
char * mstrcat(char * dest, const char * src);
int main(int argc, char *argv[])
{
//char * r;
char dest[50] = "welcome to";
char src[] = "China";
puts(mstrcat(dest, src));
puts(dest);
return 0;
}
char * mstrcat(char * dest, const char * src)
{
char * r = dest;
while (*dest++);
dest--;
while (*dest++ = *src++);
return r;
/*
char * r = dest;
while (*dest++);
dest--;
while (*src) {
*dest++ = *src++;
}
*dest = '\0';
return r;
*/
/*
char * r = dest;
while (*dest) {
dest++;
}
while (*src) {
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return r;
*/
}
例如:编写一个指针函数,把整数123转化成字符串”123”。
#include <stdio.h>
char * itoa(int n);
int main(int argc, char *argv[])
{
int n;
char * s;
printf("input:");
scanf("%d", &n);
s = itoa(n);
puts(s);
return 0;
}
char * itoa(int n)
{
int r, i = 0, j;
static char p[50];
while (n) {
r = n % 10;
n /= 10;
p[i] = r + '0';
i++;
}
p[i] = '\0';
j = i-1;
i = 0;
while (i < j) {
r = p[i];
p[i] = p[j];
p[j] = r;
i++;
j--;
}
return p;
}
5、递归函数和函数指针
5.1 递归函数
递归函数是指一个函数的函数体中直接或间接调用了该函数自身
递归函数调用的执行过程分为两个阶段:
- 递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件
- 回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解
例如:编写一个递归函数,计算n!
#include <stdio.h>
int fac(int n);
int main(int argc, char *argv[])
{
int n;
printf("input:");
scanf("%d", &n);
printf("%d\n", fac(n));
return 0;
}
int fac(int n)
{
if (n == 0 || n == 1)
return 1;
return n * fac(n-1);
}
例如:编写一个递归函数,计算斐波那契数列(与下面类似)
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
我们不妨拿新出生的一对小兔子分析一下:第一个月小兔子没有繁殖能力,所以还是一对两个月后,生下一对小兔对数共有两对三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对
#include <stdio.h>
int fib(int n);
int main(int argc, char *argv[])
{
int n = 1;
while (n <= 10) {
printf("%d ", fib(n));
n++;
}
printf("\n");
return 0;
}
int fib(int n)
{
if (n == 1 || n == 2)
return 1;
return fib(n-1)+fib(n-2);
}
5.2 函数指针
函数指针用来存放函数的地址,这个地址是一个函数的入口地址
函数名代表了函数的入口地址
函数指针变量说明的一般形式如下
<数据类型> (*<函数指针名称>)(<参数说明列表>);
<数据类型>
是函数指针所指向的函数的返回值类型<参数说明列表>
应该与函数指针所指向的函数的形参说明保持一致(*<函数指针名称>)
中,*说明为指针()不可缺省,表明为函数的指针
#include <stdio.h>
int add(int a, int b) {
return a+b;
}
int sub(int a, int b) {
return a-b;
}
int mul(int a, int b) {
return a*b;
}
int main(int argc, char *argv[])
{
int m = 10, n = 20;
int (* p)(int, int);
p = add;
//printf("%d\n", add(m, n));
printf("%d\n", (*p)(m, n));
p = sub;
printf("%d\n", (*p)(m, n));
return 0;
}
5.3 函数指针数组
函数指针数组是一个保存若干个函数名的数组
一般形式如下
<数据类型> (*<函数指针数组名称> [<大小>] )(<参数说明列表> );
- 其中,<大小>是指函数指针数组元数的个数
- 其它同普通的函数指针
#include <stdio.h>
int add(int a, int b) {
return a+b;
}
int sub(int a, int b) {
return a-b;
}
int mul(int a, int b) {
return a*b;
}
int main(int argc, char *argv[])
{
int m = 10, n = 20;
int (* p[2])(int, int);//int * p[3]
p[0] = add;
//printf("%d\n", add(m, n));
printf("%d\n", (*p[0])(m, n));
p[1] = sub;
printf("%d\n", (*p[1])(m, n));
return 0;
}
例如:调用C库中的qsort函数来实现整形数组的排序。
#include <stdio.h>
#include <stdlib.h>
int compare(const void *, const void *);
int main(int argc, char *argv[])
{
int s[] = {89, 23, 10, 8, 7, 61}, n, i;
n = sizeof(s)/sizeof(int);
qsort(s, n, sizeof(int), compare);
for (i = 0; i < n; i++)
printf("%d ", s[i]);
puts("");
return 0;
}
int compare(const void * p, const void * q)
{
return (*(int *)p - *(int *)q);
}