实参
真实传给函数的参数,叫实参,实参可以是常量,变量,表达式函数等,无论实参是何种类型的量,进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参
形参
函数名后括号中的变量,形参只有在被调用过程中才能实例化,所以叫形式参数,当函数调用完后就自动销毁了,因此形式参数只在函数中有效
实例1
定义函数
int get_max(int x, int y)
{
if (x > y)
return x;
else
return y;
}int main()
{
int a = 10;
int b = 20;
//函数的使用
int max=get_max(a, b);
printf("max= %d\n", max);
max= get_max(100, 200);
printf("max= %d\n", max); //直接调用
return 0;
}
实例2:交换两个整型的值
** 当实参传给形参的时候 **
** 形参其实是实参的一份临时拷贝 ***
** 对形参的修改不会改变实参 **
Swap(int x, int y) //void -表示返回值为空,就是没有返回值
//形参:函数名后括号中的变量a,b
{
int tmp = 0;
tmp = x;
x = y;
y = tmp;}
int main()
{
int a = 10;
int b = 20;
printf("a=%d b=%d\n", a, b);
//不使用函数实现
/*int tmp = 0;
tmp = a;
a = b;
b = tmp;
printf("a=%d b=%d\n", a, b);*/
//使用函数实现
错误示范
*-*-*-* a,b把值传给x,y,然后通过监视发现a,b和x,y的地址是不一样的,他们分别开辟了单独的空间,所以x,y在通过tmp交换值,跟a,b无关,所以打印结果是a,b没有交换。 **//调用Swap函数(这里是传值调用:函数的形参实参分别占用不同内存块,对形参的修改不会影响实参)
Swap(a, b); //a,b是真实传过去的参数,是实参
printf("a=%d b=%d\n", a, b); //结果并没有交换
return 0;
}
正确的写法
要使用取地址的方法
因为直接将a,b的值传到参数x,y上,他们的地址是不一样的
因此x,y的值通过tmp交换,跟a,b无关
void Swap2(int* pa, int* pb) //将a,b的地址传到参数
形参:函数名后括号中的变量pa,pb
{
int tmp = 0;
tmp = *pa;
*pa = *pb;
*pb = tmp;}
int main()
{
int a = 10;
int b = 20;
int tmp = 0;
printf("a=%d b=%d\n", a, b);//调用Swap2函数(这里是传址调用: 把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式,
//这种参方式可以让函数和外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量)
Swap2(&a, &b); //取a,b的地址,传到参数x,y
//&a,&b是真实传给函数的参数,是实参
printf("a=%d b=%d\n", a, b);return 0;
}
a,b把值传给x,y,然后通过监视发现a,b和x,y的地址是不一样的,他们分别开辟了单独的空间,所以x,y在通过tmp交换值,跟a,b无关,所以打印结果是a,b没有交换。
将a,b的地址直接传到pa,pb,就可以远程调用a,b,然后通过tmp这个中间变量实现值的交换
实例3 判断1000-2000的闰年
不要在函数中打印
int is_leap_year(int y)
{
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
return 1;
else
return 0;
}
int main()
{
int year = 0;
for (year = 1000; year <= 2000; year++)
{
//判断year是否为闰年
if (1 == is_laep_year(year))
{
printf("%d ", year);
}
}
return 0;
}
实例4在一个有序的数组中找到想要的元素
本质上arr是一个指针
int binary_search(int arr[], int k,int sz)
{
//算法实现
int left = 0;
//int sz = sizeof(arr) / sizeof(arr[0]); //sz不能放在这里求,要放在下面的主函数求,然后传上来
int right = sz - 1;
int i = 0;
for (i = 1; i <= sz; i++)
//while(letf<=right) //如果使用while循环,条件中的等号不能少,否则会出错
{
int mid = (left + right) / 2; //这一条必须放在for循环里面,因为每次循环过后mid的值会更新
if (k > arr[mid])
{
left = mid + 1;
}
else if (k < arr[mid]) //要使两个if并列,后面的if前要加else
{
right = mid - 1;
}
else
{
return mid;
}}
return -1;
}
int main()
{
//二分查找
//在一个有序数组中查找具体的某个数
//如果找到了返回这个数的下标,找不到返回-1
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k =6;
int sz = sizeof(arr) / sizeof(arr[0]);
// 传递过去的是数组arr的首个元素的地址,而不是整个数组
int ret = binary_search(arr, k,sz);
if (ret == -1)
{
printf("找不到");
}
else
{
printf("找到了,下标是:%d\n",ret);
}
return 0;
}
实例5 每调用一次函数,num就会加1
void Add(int* p)
{
(*p)++; // ++的优先级是比较高的,不加()的话就先执行p++,再执行*,所以这里要括起来
}
int main()
{
int num = 0;
Add(&num); //如果想用函数内部变量,改变外部变量的时候,就可以使用传址的方式
printf("num= %d\n", num); //调用1次
Add(&num);
printf("num= %d\n", num); //调用2次
Add(&num);
printf("num= %d\n", num); //调用3次
return 0;
}
函数的嵌套
void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for (i = 0; i < 3; i++)
{
new_line(); //将new_line()嵌套到three_line()里面
}
}
int main()
{
three_line(); //主函数直接调用three_line()函数return 0;
}
链式访问
int main()
{
int len = 0;
//写法1
len = strlen("abc");
printf("%d\n", len);
//写法2(链式访问)
printf("%d\n", strlen("abc"));
return 0;
}
实例
int main()
{
printf("%d", printf("%d", printf("%d",43)));
//最里面这一层打印的是43
//第二层打印的是最里面一层的返回值,这个返回值是最里面一层字符的个数也就是2
//第三层打印第二层的返回值也就是1
//三层连起来就是4321
return 0;
}
函数的声明,定义,调用
//函数声明
int Add(int x, int y);
int main()
{
int a = 10;
int b = 20;
int sum = 0;
//函数调用
sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
//如果把函数的定义放在函数调用的后面,会报错,为了避免这种情况
// 在函数调用前加一个函数声明//函数的定义
int Add(int x, int y)
{
int z = x + y;
return z;
}
引用自己写的源文件用双引号
函数的定义模块
函数的声明
函数声明,定义,调用是可以以不同的源文件分开的,在需要时调用,多个模块组成一个整体