我的C语言学习日记06——函数的使用和自定义函数

运用文档学习使用库函数

举例学习strcpy函数

int main()
{
	char arr1[] = "bit";
	char arr2[20] = "#######";//目的地要比源头长,否则会溢出
	strcpy(arr2, arr1);//string copy-字符串拷贝
	//将按源指向的 C 字符串复制到按目的地指向的数组中,包括终止空字符(并在该点停止)
	printf("%s\n", arr2);
	return 0;
}

举例学习memset函数

int main()
{
	char arr[] = "hello word";
	memset(arr, '*', 5);//memset(要改变值的内存块,要设置成*,改变几个字节)
	printf("%s\n", arr);//结果***** word
	return 0;
}

重要网站

https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5
http://cplusplus.com/

自定义函数
我的C语言学习日记06——函数的使用和自定义函数_第1张图片

 写一个函数可以找到两个整数中的最大值

 //定义函数
int get_max(int x, int y)//用x,y接收a,b
{
	if (x > y)
		return x;
	else
		return y;
}
int main()
{
	int a = 10;
	int b = 20;
	//函数的使用
	int max = get_max(a, b);//get_max获取a,b的最大值
	printf("max=%d\n", max);
	return 0;
}

自定义的函数也可以用数字做参数 

 //定义函数
int get_max(int x, int y)//用x,y接收a,b
{
	if (x > y)
		return x;
	else
		return y;
}
int main()
{
	//函数的使用
	int max = get_max(100, 300);//get_max可直接比较数值
	printf("max=%d\n", max);
	return 0;
}

写一个函数来交换两个整型变量的内容

 正常交换

int main()
{
	int a = 10;
	int b = 20;
	int tmp = 0;
	printf("a=%d,b=%d\n", a, b);
	tmp = a;
	a = b;
	b = tmp;
	printf("a=%d,b=%d\n", a, b);
	return 0;
}

用函数封装

void Swap1(int x, int y)//此处只交换x,y,与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);
    调用Swap1函数(传值调用)
	Swap1(a, b);
	printf("a=%d,b=%d\n", a, b);

	return 0;//交换失败
}

需使用指针

void Swap2(int* pa, int* pb)//pa、pb是形参,当&a、&b传递过来时才分配内存
  //此时形参时实参的一份临时拷贝
  //无需返回值,所以用void
{
	int tmp = 0;
	tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}
int main()
{
	int a = 10;
	int b = 20;
	printf("a=%d,b=%d\n", a, b);
	//调用Swap2函数(传址调用)
	Swap2(&a, &b);//&a、&b是实参
	printf("a=%d,b=%d\n", a, b);
	return 0;//交换成功
}

我的C语言学习日记06——函数的使用和自定义函数_第2张图片

 函数的参数

实际参数(实参)

真实传给函数的参数叫实参。可以是:常量、变量、表达式、函数等。在进行函数调用时必须有确定的值,以便把这些值传送给形参。

形式参数(形参)

形式参数是指函数名后括号中的变量,只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数,当函数调用完之后就自动销毁,因此形式参数只在函数中有效
形参实例化之后其实相当于实参的一份临时拷贝

函数的调用

传值调用

函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参

传址调用

把函数外部创建变量的内存地址传给函数参数的一种调用函数的方式,这种方式可以让函数和函数外的变量建立真正的联系,也就是函数内部可以直接操作外部的变量

如何选择

改变函数外部的变量需要传址调用,不改变则就传值调用

练习

 使用函数打印100-200之间的素数

int is_prime(int n)
{
	int j = 0;
	for (j = 2; j < n; j++)
	{
		if (n%j == 0)//判断2到i本身之间的数有无可整除的数
		{
			return 0;
		}
	}
	if (n == j)
	{
		return 1;
	}
}
int main()
{
	int i = 0;
	for (i = 100; i <= 200; i++)
	{
		//判断i是否为素数
		if (is_prime(i) == 1)
			printf("%d ", i);
	}
	return 0;
}

优化 

int is_prime(int n)
{
	int j = 0;
	for (j = 2; j <= sqrt(n); j++)
	{
		if (n%j == 0)//判断2到i本身之间的数有无可整除的数
		{
			return 0;
		}
	}
	if (j>sqrt(n))
	{
		return 1;
	}
}
int main()
{
	int i = 0;
	for (i = 100; i <= 200; i++)
	{
		//判断i是否为素数
		if (is_prime(i) == 1)
			printf("%d ", i);
	}
	return 0;
}

写一个函数判断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_leap_year(year))
		{
			printf("%d ", year);
		}
	}
	return 0;
}

 写一个函数,实现一个整型有序数组的二分查找

如果找到了返回这个数的下标,找不到返回-1;函数内求参数数组的个数无法实现,需在外部求出

int binary_search(int arr[], int k)//本质上arr是一个指针
{
	int left = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//arr的大小是4个字节,arr[0]是四个字节,所以sz=1
	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[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int k = 7;     
	int ret = binary_search(arr, k);//传递过去的是arr数组首元素的地址
	if (ret == -1)
	{
		printf("找不到指定的数字\n");
	}
	else
	{
		printf("找到了,下标是:%d\n", ret);
	}
	return 0;//找不到
}

出现错误,一直找不到,因为数组在传参的过程中只传递数组首元素的地址,所以导致数组元素个数sz的计算错误 ,可修改如下

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[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int k = 7;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = binary_search(arr, k,sz);//传递过去的是arr数组首元素的地址
	if (ret == -1)
	{
		printf("找不到指定的数字\n");
	}
	else
	{
		printf("找到了,下标是:%d\n", ret);
	}
	return 0;//找不到
}

写一个函数,每调用一次这个函数,就会将num的值增加1 

void Add(int* p)
{
	(*p)++;//*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);
	Add(&num);
	printf("num=%d\n", num);
	return 0;
}

用while也可以

void Add(int* p)
{
	(*p)++;//*p++因为++优先级较高,作用于p
}
int main()
{
	int num = 0;
	while (num < 5)
	{
		Add(&num);
		printf("num=%d\n", num);
	}
	
	return 0;//打印结果:5
}

函数的嵌套调用和链式访问

嵌套调用

函数和函数之间可以有机的结合在一起,互相调用

链式访问

把一个函数的返回值作为另一个函数的参数

int main()
{
	int len = 0;
	//第一种正常写法
	len = strlen("abc");
	printf("%d\n", len);
	//第二种,用链式访问
	printf("%d\n", strlen("abc"));

	return 0;
}

在链式访问时,printf 函数编译成功后返回字符的个数

int main()
{ //printf函数编译成功后返回字符的个数
	printf("%d", printf("%d", printf("%d", 43)));
	//首先第一个执行的printf打印43,返回值为2
	//所以第二个执行的printf函数打印2,返回值为1
	//第三个执行的printf打印1,返回值为1
	return 0;//打印结果:4321
}

函数的声明和定义


把复杂功能分开模块化实现,引用头文件组合到一起使用我的C语言学习日记06——函数的使用和自定义函数_第3张图片

 函数声明

告诉编译器有一个函数叫什么,参数是什么,返回类型是什么,但是具体是否存在无关
先声明后使用;一般放到头文件中

函数定义

指的是函数的具体实现,交代函数的功能实现

 //函数声明    正确用法:函数声明放到头文件里,在头文件新建add.h文件
int Add(int x, int y);

int main()
{
	int a = 10;
	int b = 20;
	int sum = 0;
	 //函数的调用  正确用法:要使用Add函数只需包含头文件即可#include "add.h"
	//引用库函数用<>,引用自定义函数用""
	sum = Add(a, b);
	printf("%d\n", sum);
	return 0;
}
 //函数的定义  正确用法:放到在源文件新建add.c的文件里
int Add(int x, int y)
{
	int z = x + y;
	return z;
}

我的C语言学习日记06——函数的使用和自定义函数_第4张图片

我的C语言学习日记06——函数的使用和自定义函数_第5张图片

 #ifndef __ADD_H__的意思是:如果没有定义__ADD_H__,就把下面代码包含过去,到#endif结束,如果定义过__ADD_H__就不包含下面的代码;这句话的目的就是防止重复包含

我的C语言学习日记06——函数的使用和自定义函数_第6张图片

你可能感兴趣的:(C程序员的自我修养,编程语言,c++,开发语言,编辑器,visual,studio)