1.函数分为:库函数和自定义函数
查找库函数的网站:http://www.cplusplus.com 或着https://legacy.cplusplus.com/reference/
中文版的C语言函数网站:cpprefenrerence.com
函数的组成:
ret_type fun_name ( paral,*)
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
paral 函数参数
2.交换两个数的子函数
- 第一种方法 结果打印的是a=10;b=20;说明函数没有实现交换功能 。因为主函数中的a,b所在的地址和子函数中的x和y的地址并不一样,我们只是改变了x,y的内容,并不相当于改变了a和b的内容。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(int x, int y)
{
int temp = 0;
temp = x;
x = y;
y = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
printf("a=%d b=%d\n", a, b);
return 0;
}
- 第二种方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(int* x, int* y)//当子函数没有返回值的时候,返回函数类型写void
{
int temp = 0;
temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(&a,&b);
printf("a=%d b=%d\n", a,b);
return 0;
}
3.stringcopy 字符串拷贝函数
所在头文件为 #include <string.h>
一般格式:
strcpy(destination,source);
注:在进行字符串拷贝的时候,也会把源字符串中的终止符\0 也会复制过去,同时要注意目的地址的大小要大于原字符串所占空间的大小,否则会产生溢出。
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20]={0};
char arr2[20]={0};
arr1="HELLOW!";
arr2="############";
strcpy(arr2,arr1);
printf("%s\n",arr2);
return 0;
}
4.memset函数——内存设置
memset( void* ptr, int value, size_t num);
ptr :
被修改东西的第一位的地址
value:
要修改后的值
num:
要修改的位数
int main()
{
char arr[]="hello world";
memset(arr,'*',5);
printf("%s\n",arr);
return 0;
}
此程序的功能是把arr数组中的前五位换成‘*’,即最终结果是“***** world”。
5.什么是实参:
真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便这些值传给形参。
比如:max(100,200);这个实参是常量
什么是形参:
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完后就会自动销毁了,因此形式参数只在函数中有效。 形式参数可以看成实参的一份临时拷贝,会开辟出一个新的地址,所以修改形参不会改变实参的值。
6.函数的调用:
传值调用:函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参。
传址调用:(如果是函数需要改变函数外部的变量,就有可能用到传址调用)
- 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式
- 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
练习:
1.写一个函数可以判断一个数是不是素数
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <math.h>
int is_prime(int x)
{
int j = 0;
for (j = 2; j < sqrt(x); j++)
{
if (x%j == 0)
{
return 0;
break;
}
}
if (j >sqrt(x))
return 1;
}
int main()
{
int i=0;
for (i = 101; i <= 200; i++)
{
is_prime(i);
if(is_prime(i)==1)
printf("%d ", i);
}
return 0;
}
2.写一个函数判断一年是不是闰年
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int year(int x)
{
if ((x % 4 == 0) && (x % 100 != 0))
return 1;
else if (x % 400 == 0)
return 1;
else
return 0;
}
int main()
{
int i=0;
printf("请输入年份:>\n");
scanf("%d", &i);
year(i);
if (year(i) == 1)
printf("该年为闰年\n");
else
printf("该年不是闰年\n");
return 0;
}
3.写一个函数,实现一个整形有序数组的二分查找
- 正确写法
#define _CRT_SECURE_NO_WARNINGS
#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) / 2;
if (arr[mid] < k)
{
left = mid + 1;
}
else if (arr[mid] > k)
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int k = 8;
int get=binary_search(arr, k, sz);
if (get== -1)
{
printf("您所查找的数字不存在\n");
}
else
{
printf("您所查找的数字下标为%d\n", get);
}
return 0;
}
- 错误写法:不同之处就是把计算数组长度的语句放在了函数体内,此时的结果完全不同,因为,在数组传参的时候,不可能在函数中开辟新的地址来放数组,因为数组的空间可能很大,这就浪费很多地方,所以数组在传参的时候,只把数组中的第一个元素传了过去。所以,在函数体内计算数组长度会导致错误,因此我们可以在主函数中计算出了数组总长度,然后再传递给函数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int binary_search(int arr[], int k, int sz)
{
int left = 0;
sz=sizeof(arr)/arr[0];
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] < k)
{
left = mid + 1;
}
else if (arr[mid] > k)
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int k = 8;
int get=binary_search(arr, k, sz);
if (get== -1)
{
printf("您所查找的数字不存在\n");
}
else
{
printf("您所查找的数字下标为%d\n", get);
}
return 0;
}
4.写一个函数,每调用一次这个函数,就会将num的值增加1。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void ADD(int* p)
{
(*p)++;//注意:千万不要写成*p++,因为++的优先级要高于*
}
int main()
{
int num = 0;
ADD(&num);
printf("%d\n", num);//1
ADD(&num);
printf("%d\n", num);//2
ADD(&num);
printf("%d\n", num);//3
return 0;
}
7.函数的嵌套调用:函数和函数之间是可以有机组合的
不同子函数之间也是可以调用的
8.函数的链式访问:把一个函数的返回值作为另一个函数的参数
#include <stdio.h>
int main()
{
printf("%d",printf("%d",printf("%d",43)));
return 0;
}
此程序是链式访问的经典案例。
一个关键是printf函数的用法,它的返回值是打印出的字符的数量。
第一次打印出43,因为打印出了两个字符,返回值为2。
接着打印2,也就是打印了一个字符,返回值为1,那么再打印出1。
那么最终的结果是4321
9.函数的定义与声明
函数声明:
- 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么,但是具体是不是存在,无关紧要。
- 函数的声明一般出现在函数的使用之前,要满足先声明后使用。(如果一个函数并未在程序最前面声明,那么如果子函数出现在主函数的后面,就会出现报错,提示子函数未声明)
- 函数的声明一般要放在头文件(.h)中。
如:如果函数声明和主函数不在同一个文件中
#include“头文件名” 声明自己写的函数,用双引号,声明函数库中的函数要带<>。
函数定义:
函数的定义是指函数的具体实现,交待函数的功能实现。
在未来工作或者自己写代码的过程中,我们通常会把函数声明放在(.h)文件中,函数放在(.c)文件中,主函数放在一个文件中去。