目录
4.3.2 写一个代码打印1000到2000年之间的闰年 并 计算闰年的个数
4.3.4 写一个函数,每调用一次这个函数,就会将 num 的值增加1
1.函数是什么
函数是子程序——是一个大型程序中的某部分代码,由一个或多个语句块组成,它负责完成某项特定任务,相较于其他代码,具备相对的独立性。
2.C语言中函数的分类:
1、库函数
2、自定义函数
2.1库函数
C语言常用的库函数:
1、IO函数:(stdio.h)
2、字符串操作函数(string.h)
3、字符操作函数
4、内存操作函数
5、时间/日期函数
6、数学函数
7、其他库函数
2.1.1 strcpy
strcpy(destination,source)拷贝字符串,将后拷贝到前(包括'\0'这个字符),返回前
头文件<string.h>
代码:
-
#define _CRT_SECURE_NO_WARNINGS
-
#include <stdio.h>
-
#include <string.h>
-
-
int main()
-
{
-
char arr1[
20] = {
0 };
-
char arr2[] =
"I can do it!";
-
strcpy(arr1, arr2);
-
printf(
"%s\n",arr1);
-
-
return
0;
-
}
运行结果:
2.1.2 memset
memset(ptr,value,num)内存设置:把从ptr这个位置开始的向后的num个字节的内容设置成指定的value值
头文件<string.h>
代码:
-
#define _CRT_SECURE_NO_WARNINGS
-
#include <stdio.h>
-
#include <string.h>
-
-
int main()
-
{
-
char arr[
20] =
"hello world";
-
memset(arr,
'x',
5);
//数组名就是首元素的地址
-
memset(arr +
6,
'y',
3);
-
-
printf(
"%s\n",arr);
-
}
运行结果:
注意:
1、库函数的使用,必须包含 #include 对应的头文件。
2、需要学会查询工具的使用:
MSDN(Microsoft Developer Network)
www.cplusplus.com
http://en.cppreference.com(英文版)
http://zh.cppreference.com(中文版)
3、英文很重要。最起码得看懂文献。
2.2自定义函数
2.2.1 函数的组成:
2.2.2 写个函数求两个整数的较大值
-
#include <stdio.h>
-
//函数的定义
-
int get_max(int x, int y)
-
{
-
return (x > y ? x : y);
-
}
-
int main()
-
{
-
int a =
0;
-
int b =
0;
-
scanf(
"%d %d", &a, &b);
-
//求最大值
-
//函数的调用
-
int m =
get_max(a, b);
-
printf(
"%d\n",m);
-
-
return
0;
-
}
类比:
2.2.3 写一个函数可以交换两个整型变量的内容
错误的代码和运行结果:
-
#include <stdio.h>
-
-
void Swap(int x, int y)
-
{
-
int temp = x;
-
x = y;
-
y = temp;
-
}
-
-
int main()
-
{
-
int a =
0;
-
int b =
0;
-
scanf(
"%d %d",&a,&b);
-
printf(
"交换前:a=%d b=%d\n", a, b);
-
//a和b叫实参
-
Swap(a,b);
-
printf(
"交换后:a=%d b=%d\n",a,b);
-
return
0;
-
}
错误的原因:
a和b是实际参数,x和y是形式参数
当实参a和b传给形参x和y的时候,形参将会是实参的一份临时拷贝,
形参确实将实参的数据拷贝了一份,但是形参有自己独立的空间,
因为有独立的空间(地址是没联系,独立的),所以修改形参并不会影响到实参总结:当实参传给形参的时候,形参是实参的一份临时拷贝,修改形参不会影响实参
正确的代码和运行结果:
-
#include <stdio.h>
-
-
void Swap(int* px, int* py)
-
{
-
int temp = *px;
-
*px = *py;
-
*py = temp;
-
}
-
-
int main()
-
{
-
int a =
0;
-
int b =
0;
-
scanf(
"%d %d",&a,&b);
-
printf(
"交换前:a = %d b = %d\n", a, b);
-
Swap(&a, &b);
//传地址
-
printf(
"交换后:a = %d b = %d\n", a, b);
-
-
return
0;
-
}
解题思路:通过传地址在实参和形参之间建立联系
px中存了a的地址,py中存了b的地址,通过解引用就找到了实参a和b,从而可以 对实参a和b进行更改。
比较2.2.2与2.2.3,思考:
在什么情况下参数部分要传地址,什么情况下不需要传地址,传值就可以?
传址:不仅仅要得到值,而且这个函数内部要改变函数外边变量a,b,(想改变a和b的值),传变量搞不定,需要传地址。让函数与函数外的变量a和b建立联系
传值:只想得到值,不需要改变a和b的值
总结:想改变实参就传址,不改变实参就传值
3. 函数的参数
3.1实际参数(实参):
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
如:
int c = Add(a + 3, b); int d = Add( Add( 10, a), b); //这样写,要保证Add有返回值,这样Add(10, a)才是个确定的值,才能放在Add函数中无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
3.2形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。
形参实例化之后其实相当于实参的一份临时拷贝。
当函数调用完之后形式参数就自动销毁了(像局部变量一样),形参只在函数中有效。
4.函数调用
4.1传值调用:
传的是变量本身
函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参
4.2 传址调用:
传的是变量的地址
可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量
4.3练习
4.3.1 写一个代码打印100-200之间的素数
(用函数的方法来写在方法四)
素数:只能被1和它本身整除的数是素数
解题思路:先产生100-200之间的数,再判断是否为素数,是素数就打印
如何表示是素数和不是素数:可以创建一个flag变量,flag是1,表示是素数;flag是0,表示不是素数。
方法一:
判断是否为素数:拿 2 到 i-1 之间的数字去试除 i
-
#include <stdio.h>
-
-
int main()
-
{
-
int i =
0;
-
for (i =
100; i <=
200; i++)
-
{
-
int flag =
1;
-
int j =
0;
-
for (j =
2; j <= i -
1; j++)
-
{
-
if (i % j ==
0)
-
{
-
flag =
0;
-
break;
-
}
-
}
-
if (flag ==
1)
-
printf(
"%d ",i);
-
}
-
return
0;
-
}
方法二:(代码优化)
判断是否为素数:拿 2 到 sqrt(i) 之间的数字去试除 i
sqrt是一个数学库函数,是用来开平方的, 头文件 <math.h>
简单解释一下可以这样优化的原因:
一个非素数m一定可以写成 m = a*b
例如: 16 = 2*8
= 4*4即 a和b中一定有一个数字是 <= sqrt(m)的( sqrt(m)是m的开平方 )
所以只要试除到sqrt(m)就可以了
-
#include <stdio.h>
-
#include <math.h>
-
-
int main()
-
{
-
int i =
0;
-
for (i =
100; i <=
200; i++)
-
{
-
int flag =
1;
-
int j =
0;
-
for (j =
2; j <=
sqrt(i); j++)
//优化在这里!!!
-
{
-
if (i % j ==
0)
-
{
-
flag =
0;
-
break;
-
}
-
}
-
if (flag ==
1)
-
{
-
printf(
"%d ",i);
-
}
-
}
-
return
0;
-
}
方法三:(在方法二的基础上再进一步优化)
100到200中的偶数也不可能是素数,所以可以直接产生100到200之间的奇数,优化代码
-
#include <stdio.h>
-
#include <math.h>
-
-
int main()
-
{
-
int i =
0;
-
for (i =
101; i <=
200; i+=
2)
//优化在这里!!!
-
{
-
int flag =
1;
-
int j =
0;
-
for (j =
2; j <=
sqrt(i); j++)
-
{
-
if (i % j ==
0)
-
{
-
flag =
0;
-
break;
-
}
-
}
-
if (flag ==
1)
-
{
-
printf(
"%d ",i);
-
}
-
}
-
return
0;
-
}
方法四:(写一个函数来判断是否为素数)
写一个代码打印100-200之间的素数 并 算出素数的个数
约定:
是素数返回1
不是素数返回0
-
#include <stdio.h>
-
#include <math.h>
-
-
int is_prime(int n)
-
{
-
int j =
0;
-
for (j =
2; j <=
sqrt(n); j++)
-
{
-
if (n % j ==
0)
-
{
-
return
0;
//return 比 break 强大很多!
-
}
-
}
-
return
1;
-
}
-
-
int main()
-
{
-
int i =
0;
-
int count =
0;
-
for (i =
101; i <=
200; i +=
2)
-
{
-
if (
is_prime(i))
-
{
-
count++;
-
printf(
"%d ", i);
-
}
-
}
-
printf(
"\ncount = %d\n", count);
-
return
0;
-
}
4.3.2 写一个代码打印1000到2000年之间的闰年 并 计算闰年的个数
(用函数的方法来写在方法三)
解题思路:先产生1000-2000之间的年份,再判断是否为闰年,是闰年就打印
判断year是不是闰年
1、能被4整除并且不能被100整除是闰年
2、能被400整除也是闰年
方法一:
-
#include <stdio.h>
-
-
int main()
-
{
-
int count =
0;
-
int year =
0;
-
for (year =
1000; year <=
2000; year++)
-
{
-
if (year %
4 ==
0)
-
{
-
if (year %
100 !=
0)
-
{
-
count++;
-
printf(
"%d ",year);
-
}
-
}
-
if (year %
400 ==
0)
-
{
-
count++;
-
printf(
"%d ", year);
-
}
-
}
-
printf(
"\ncount = %d\n",count);
-
return
0;
-
}
方法二:
-
#include <stdio.h>
-
-
int main()
-
{
-
int count =
0;
-
int year =
0;
-
for (year =
1000; year <=
2000; year++)
-
{
-
if (((year %
4 ==
0) && (year %
100 !=
0)) || (year %
400 ==
0))
-
{
-
count++;
-
printf(
"%d ",year);
-
}
-
}
-
printf(
"\ncount = %d\n",count);
-
return
0;
-
}
方法三:(写一个函数来判断是否为闰年)
约定:
是闰年返回1
不是闰年返回0
-
#include <stdio.h>
-
-
int is_leap_year(int y)
-
{
-
if (((y %
4 ==
0) && (y %
100 !=
0)) || (y %
400 ==
0))
-
{
-
return
1;
-
}
-
else
-
{
-
return
0;
-
}
-
}
-
-
int main()
-
{
-
int count =
0;
-
int year =
0;
-
for (year =
1000; year <=
2000; year++)
-
{
-
if (
is_leap_year(year))
-
{
-
count++;
-
printf(
"%d ",year);
-
}
-
}
-
printf(
"\ncount = %d\n",count);
-
return
0;
-
}
函数的功能尽量足够单一,高内聚低耦合
4.3.3 写一个函数,实现一个整形有序数组的二分查找。
先想好函数怎么用,再去写函数 !!!!
去哪里查,查什么,数组有几个元素,找到了怎么办
约定;
找到了返回下标
找不到返回-1
形参和实参的名字可以相同,也可以不同
这是正确的代码
-
#include <stdio.h>
-
-
int binary_search(int arr[], int k, int sz)
-
{
-
int left =
0;
-
int right = sz -
1;
-
while (left <= right)
-
{
-
int mid = left + (right - left) /
2;
-
if (k > arr[mid])
-
{
-
left = mid +
1;
-
}
-
else
if (k < arr[mid])
-
{
-
right = mid -
1;
-
}
-
else
-
{
-
return mid;
-
}
-
}
-
return
-1;
-
-
}
-
-
int main()
-
{
-
int arr[] = {
0,
1,
2,
3,
4,
5,
6,
7,
8,
9 };
-
int sz =
sizeof(arr) /
sizeof(arr[
0]);
-
int k =
7;
-
int ret =
binary_search(arr, k, sz);
-
if (ret ==
-1)
-
{
-
printf(
"找不到\n");
-
}
-
else
-
{
-
printf(
"找到了,下标是%d\n",ret);
-
}
-
return
0;
-
}
下面是错误的做法:
错误原因:形参是实参的一份临时拷贝,为了避免空间浪费,
数组传参实际上传递的是数组首元素的地址(数组名是首元素的地址),而不是 整个数组
所以在函数内部计算一个函数参数部分的数组元素个数是不靠谱的
4.3.4 写一个函数,每调用一次这个函数,就会将 num 的值增加1
也就是说这个函数的作用就是将num的值增加1
-
#include <stdio.h>
-
-
void Add(int* p)
-
{
-
(*p)++;
-
}
-
-
int main()
-
{
-
int num =
0;
-
Add(&num);
-
printf(
"%d\n",num);
-
Add(&num);
-
printf(
"%d\n", num);
-
return
0;
-
}
5. 函数的嵌套调用和链式访问
函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。
5.1 嵌套调用
函数可以嵌套调用,但是不能嵌套定义。函数的地位是平等的
5.2 链式访问
把一个函数的返回值作为另一个函数的参数就叫做链式访问
链式访问的前提:函数得有返回值
-
#include <stdio.h>
-
#include <string.h>
-
-
int main()
-
{
-
int ret =
strlen(
"abcdef");
//6
-
printf(
"%d\n",ret);
-
//链式访问
-
printf(
"%d\n",
strlen(
"abcdef"));
//6
-
-
return
0;
-
}
strlen函数的返回值做了printf函数的参数
下面是一个非常典型的链式访问题目:
-
#include <stdio.h>
-
-
int main()
-
{
-
printf(
"%d",
printf(
"%d",
printf(
"%d",
43)));
//4321
-
-
return
0;
-
}
printf 返回值是:打印的字符的个数
printf("%d",43); 这个函数,会打印43,返回值是2
转载:https://blog.csdn.net/m0_61731585/article/details/125367017