1.函数是什么?
函数的定义:子程序;
在计算机科学中,子程序是一个大型程序中的某部分代码,由一个或多个语句块组成。
它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。
这些代码通常被集成为软件库。
C语言中的函数分类:
①库函数;
②自定义函数。
2.Strcpy() - 字符串拷贝
语法:
char * strcpy ( char * destination, const char * source );
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[] = "PZY";
char arr2[20] = "######";
strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
//strcpy - string copy - 字符串拷贝
//strlen - string length - 字符串长度有关
}
注意:strcpy会把数组中的“\0”也一同复制。
3.memset() - 内存设置
语法:
void * memset ( void * ptr, int value, size_t num );
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
//memset()的使用
int main()
{
char arr1[] = "hello world";
memset(arr1, '*', 5);
//memset - memory 内存 set 设置
printf("%s\n", arr1);
return 0;
}
如上代码最终执行结果,屏幕上会打印出“***** world”
4.自定义函数:
函数的组成:
举例:
①找出两个数的最大值:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//定义函数
int get_max(int x, int y)
{
return (x > y) ? (x) : (y);
}
int main()
{
int max;
int a = 10;
int b = 20;
//函数的使用
max = get_max(a, b);
printf("较大值为:%d\n", max);
return 0;
}
②交换两个数:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void swap(int x, int y)
{
int tmp;
tmp = x;
x = y;
y = tmp;
}
int main()
{
int a, b;
a = 10;
b = 20;
printf("%d %d\n", a, b);
swap(a, b);
printf("%d %d\n", a, b);
return 0;
}
当代码运行后会发现a , b 两个数并未交换,问题出在哪里呢?
如图,a, b, x, y四个变量的地址都不一样,a,b的数值传给x,y后,
swap()函数最终的输出结果只是x, y的数值交换了,
a, b变量中存放的数值仍然是10, 20,并不会发生交换。
那如果我们不传数值而是远程调用a, b变量的地址呢?这时候我们就想到了指针变量。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void swap(int*pa, int*pb)
{
int tmp;
tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main()
{
int a, b;
a = 10;
b = 20;
printf("%d %d", a, b);
swap(&a, &b);
printf("%d %d", a, b);
return 0;
}
最终,a, b的数值成功交换了。
5.函数的参数:
①实际参数(实参):
真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,
以便把这些值传给形参。
②形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中
才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后
就自动销毁了。因此形式参数只在函数中有效。
总结:
当实参传给形参的时候,形参只是实参的一份临时拷贝。
对形参的修改是不会改变实参的。
6.函数的调用:
①传值调用:
函数的实参和形参分别占有不同的内存块,对形参的修改不会影响实参。
②传址调用:
把函数外部创建变量的内存地址传递给函数参数
→函数内部可以直接操作函数外部的变量。
7.练习:
①打印100~200之间的素数:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int is_prime(int a)
{
for (int j = 2; j <= sqrt(a); j++)
{
if (a % j == 0)
return 0;
}
return 1;
}
int main()
{
int i;
for (i = 100; i <= 200; i++)
{
if (is_prime(i) == 1)
printf("%d ", i);
}
return 0;
}
②判断闰年:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int is_leap_year(int x)
{
if (x % 4 == 0 && x % 100 != 0 || x % 400 == 0)
return 1;
else
return 0;
}
int main()
{
int year;
for (year = 1000; year <= 2000; year++)
{
if (1 == is_leap_year(year))
printf("%d ", year);
}
return 0;
}
③整形有序数组二分查找:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//指针才能接收地址,因此本质上arr是一个指针
int binary_search(int arr[], int k)
{
//算法的实现
//假设在32位系统上运作,指针大小为4个字节,arr[0]也占4个字节
//因此sz = 1,而不为10
int sz = sizeof(arr) / sizeof(arr[0]);
int left = 0;
int right = sz - 1;
int mid = (left + right) / 2;//中间元素的下标
while (left <= right)
{
if (k < mid)
right = mid - 1;
else if (k > mid)
left = mid + 1;
else
return mid;
}
return -1;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7
// 此处传递过去的是数组arr首元素的地址
int ret = binary_search(arr, k);
if (binary_search(arr, k) == -1)
printf("数组中无法找到指定数字\n");
else
printf("找到啦!指定数字下标为>: %d\n", ret);
return 0;
}
数组arr[]中的元素存在数字7,但为何输入后仍然查找不到对应下标呢?
具体原因在上述代码块中的注已说明,由此我们能得出一个结论:
在函数的内部,想要去求参数或者数组元素的个数是无法实现的。
那怎么无法在函数内部求,那我们就在外部求就可以了,
直接把int sz = ...这行代码移到main函数中,
并且在binary_search()函数中多加一个参数修改为:
int binary_search(int arr[], int k, int sz)
即可
最终我们的代码就能正常运行了。
④每调用一次函数,num自增:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void Add(int* p)
{
(*p)++;
}
int main()
{
int num = 0;
Add(&num);
printf("num = %d\n", num);
Add(&num);
printf("num = %d\n", num);
Add(&num);
printf("num = %d\n", num);
return 0;
}
8.函数的嵌套调用和链式访问:
嵌套调用:
程序在编译或运行时,使用某个函数来完成相关功能,称之为函数调用。
在上述介绍中有体现。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
链式访问:
把一个函数的返回值作为另外一个函数的参数
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
//1
int len;
len = strlen("abc");
printf("%d\n", len);
//2
printf("%d\n", strlen("abc"));
return 0;
}
上述代码中//1等价于//2
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
上述代码输出结果为:
printf()返回值:
返回值为整型,是输出字符的个数,即格式化字符串中字符的个数。
第三个printf()先是打印43,字符个数有两个,所以返回2;
第二个printf()再打印2,字符个数只有一个,所以返回1
第三个printf()打印1收尾,因此最终打印结果为4321。
9.函数的声明和定义:
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//函数的声明
int Add(int x, int y);
int main()
{
int a = 10;
int b = 20;
//函数的调用
int sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
//函数的定义
int Add(int x, int y)
{
int z = x + y;
return z;
}
但在正常使用环境下,一般不这么写函数的声明和定义
正确用法如下:
按如图所示添加新建项:
再把声明和定义部分分别放置到对应项目中:
最后在需要引用Add()函数的项目中添加头文件即可:
#include"add.h"
注意:引用自定义头文件时用"",使用库里的头文件时用<>