个人博客网址:https://ljsblog.com
函数(三)
函数是一段可以重复使用的代码,用来独立地完成某个功能。
函数的分类
- 库函数:C语言本身提供给我们的函数,使用库函数必须包含#include对应的头文件
- 自定义函数:自己设置的函数
库函数列举
strlen
需要引用头文件string.h,用来计算字符串长度,遇\0结束,最终字符串长度不包括\0。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char a[]="myblog";
printf("长度为%d\n",strlen(a));//长度为6
return 0;
}
strcpy
需要引用头文件string.h,strcpy() 函数用于对字符串进行复制(拷贝)。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char a[]="myblog";
char b[]="##########";
strcpy(b,a);
printf("%s\n",b);//myblog
return 0;
}
memset
格式:
void *memset(void *str, int c, size_t n)
复制一个无符号字符到参数 str 所指向的字符串的前 n 个字符。
需要引用头文件string.h
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[]="C programming language";
memset(arr,'x',5);
printf("%s\n",arr);//xxxxxgramming language
return 0;
}
自定义函数的格式
类型 名称(参数声明)
{
语句;//可以是多条语句
}
函数的参数
实际参数(实参):
真是传给函数的参数,会被函数内部的代码使用,所以称为实际参数,简称实参。
形式参数(形参):
就是个形式上的参数,在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为形式参数,简称形参。
形参和实参的功能
传递数据,发生函数调用时,实参的值会传递给形参。
例:
//求两数和
#include <stdio.h>
//定义函数
int Add(int x,int y)
//x,y为形参,当实参传给形参时,形参其实是实参的一份临时拷贝
{
int z=0;
z=x+y;
return z;//返回值
}
int main()
{
int a=3,b=5,sum=0;
//使用函数
sum=Add(a,b);
//a,b为实参
//注:实参a,b和形参x,y使用的不是同一空间,通俗点来讲,形参实例化化后其实就相当于实参的一份临时拷贝,
printf("%d\n",sum);
return 0;
}
函数的调用
传值调用:
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
传址调用:
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。这种传参方式可以让函数和函数外边的变量建立起正真的联系,也就是函数内部可以直接操作函数外部的变量。
例子
打印100-200之间的素数
#include <stdio.h>
#include <math.h>
//是素数返回1,不是返回0
int prime(int x)
{
int j=2;
for(j=2;j<=sqrt(x);j++)
{
if(x%j==0)
{
return 0;
}
}
if(j>sqrt(x))
{
return 1;
}
}
int main()
{
int i=0;
for(i=100;i<=200;i++)
{
if(prime(i)==1)//调用函数,判断i是否是素数
{
printf("%d\n",i);
}
}
return 0;
}
打印1000-2000之间的闰年
#include <stdio.h>
int leap(int x)
{
if( (x%4==0 && x%100!=0) || (x%400==0))
{
return 1;
}
else
{
return 0;
}
}
int main()
{
int i=0;
for(i=1000;i<=2000;i++)
{
if(leap(i)==1)
{
printf("%d\n",i);
}
}
return 0;
}
调用函数,使得n每次加1
#include <stdio.h>
void num(int* p)
{
(*p)++;
//注:++优先级比*高,所以不能*p++,要用(*p)++
}
int main()
{
int n=0;
int* z=&n;
num(z);//或者num(&n)
printf("%d\n",n);
num(z);//或者num(&n)
printf("%d\n",n);
num(z);//或者num(&n)
printf("%d\n",n);
return 0;
}
函数的嵌套调用
函数的嵌套调用是指在一个C语言函数里面在执行另一个函数,这样通常称为函数的嵌套调用。
例:
#include <stdio.h>
void print()
{
printf("hello world\n");
}
void nested()
{
print();
}
int main()
{
nested();
return 0;
}
函数的递归调用(链式访问)
把一个函数的返回值作为另外一个函数的参数
例:
#include<stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));//4321
//printf的返回值是打印的字符的个数
//printf("%d", 43)打印了43,是两个字符,所以返回2
//printf("%d", printf("%d", 43)),打印2,是一个字符。所以返回1
//所以打印结果为4321
return 0;
}
函数的声明
C语言代码由上到下依次执行,原则上函数定义要出现在函数调用之前,否则就会报错。
但在实际开发中,经常会在函数定义之前使用它们,这个时候就需要提前声明
所谓声明(Declaration),就是告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在无关紧要。
函数声明格式:
类型 名称(参数声明);
错误示例:
#include<stdio.h>
int main()
{
int a=10,b=5,s=0;
s=sum(a,b);
printf("%d\n",s);
return 0;
}
int sum(int x,int y)
{
int z=0;
z=x+y;
return x+y;
}
//当然,如果你的编译器足够聪明那即使你没有事先声明还是能够运行成功的,但是应当尽量避免这种情况。
正确示例:
#include<stdio.h>
int sum(int x,int y);//声明
int main()
{
int a=10,b=5,s=0;
s=sum(a,b);
printf("%d\n",s);
return 0;
}
int sum(int x,int y)
{
int z=0;
z=x+y;
return x+y;
}
函数递归
递归就是程序自己调用自己
递归条件
- 存在限制条件,当满足这个限制条件时,递归不再继续
- 每次递归调用后越来越接近这个限制条件
例子1
//接受一个整型,按照顺序打印它的每一位,例:输入456,输出4 5 6
#include <stdio.h>
int print(int x)
{
int s=0;
if(x>9)
{
print(x/10);
}
printf("%d ",x%10);
}
int main()
{
int n=0;
scanf("%d",&n);//输入456
//递归
print(n);
return 0;
}
//4 5 6
例子2
//编写函数不允许创建临时变量,求字符串的长度
#include <stdio.h>
int strl(char* x)
{
if(*x!='\0')
{
return 1+strl(x+1);
}
else
return 0;
}
int main()
{
char a[]="myblog";
printf("len=%d\n",strl(a));//a是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
return 0;
}
迭代
迭代就是重复的做一件事情
例:
//求n的阶乘
#include <stdio.h>
int fac(int x)
{
if(x<=1)
{
return 1;
}
else
{
return x*fac(x-1);
}
}
int main()
{
int n=0;
scanf("%d",&n);
printf("%d\n",fac(n));
return 0;
}