c语言初阶——函数

目录

1.函数是什么  

2.c语言中函数的分类

2.1库函数

2.1.1strcpy

2.2自定义函数

2.2.1函数的组成

实例1:写一个函数找到两个整数的较大值。

2.2.2函数的调用

2.2.2.1实参与形参

实参

形参

2.2.2.2传值与传址

传值

传址

实例2:写一个函数交换两个整型变量的内容。

实例3:写一个函数判断一个数是不是素数

2.2.3函数的嵌套调用

2.2.4函数的链式访问

3.函数的声明与定义

3.1函数的声明

3.2函数的定义

3.3函数的递归

什么是递归

实例1:编写一个函数,输出一个无符号整数的每一位。

递归的两个必要条件

实例2:编写函数,不创建临时变量,求字符串长度。

实例3:实现一个数的阶乘计算。

实例4:计算第n个斐波那契数。

补充知识点1:数组的初始化

补充知识点2:main()函数冲突

补充知识点3:常用的缩写变量名

补充知识点4:监测调试的方法

补充知识点5:指针与地址

1.*代表解引用操作

2.&代表取地址操作

3.区分 * 的不同作用

4.字符数组


1.函数是什么  

  • 维基百科中函数的定义是子程序它负责完成某项特定任务,具备相对独立性。
  • 一般会有输入参数与返回值,提供对过程的封装和细节的隐藏。

2.c语言中函数的分类

  1. 库函数
  2. 自定义函数

2.1库函数

  • 编程语言提供的预定义函数,存储在库文件中,供人们在编写代码时直接调用使用。库函数封装了许多常用的功能,如输入输出操作、数学计算、字符串操作、内存管理等,不需要重新编写这些功能的具体实现

2.1.1strcpy

  • 用法:
char* strcpy(*des,*src);
  • 示例:
#include<stdio.h>
int main()
{
    char arr1[20] = { 0 };
    char arr2[] = { "人类就是愚蠢" };
    strcpy(arr1, arr2);
    printf("%s ", arr1);
    return 0;
}

2.2自定义函数

2.2.1函数的组成

ret_type func_name(para1 , * )//ret_type是返回类型,func_nume是函数名
{
    statement;//语句项
}

其中函数的参数可以有一个、多个,也可以是0个。

实例1:写一个函数找到两个整数的较大值。
#include<stdio.h>

int get_max(int a, int b)
{
	if (a >= b)
		return a;
	else
		return b;
}

int main()
{
	int i = 10;
	int j = 20;
	int res = 0;
	res = get_max(i, j);
	printf("最大数为%d ", res);
	return 0;
}

2.2.2函数的调用

2.2.2.1实参与形参
实参
  • 定义:实参是指在函数调用时实际传递给函数的值或变量。
  • 作用:实参的值会传递给形参,作为函数执行的输入。
  • 位置:出现在函数调用部分。
形参
  • 定义:形参是指函数定义中用于接收值的变量,是函数的一部分,定义时写在函数名后面的括号中。
  • 作用:形参起到占位符的作用,在函数被调用时用于接收传递进来的实参值,在函数调用结束后自动销毁。
  • 位置:出现在函数定义部分。

在函数调用过程中,形参相当于对实参拷贝,其运行结果对不会影响到实参!又称为传参不传址

2.2.2.2传值与传址
传值
  • 定义:传值是指在调用函数时,将实参的值复制一份传递给形参。在函数内部,形参是实参值的副本,对形参的修改不会影响实参。
  • 特点:函数内部操作的是值的副本,而不是原始变量本身。
传址
  • 定义:传址是指在调用函数时,将实参的地址传递给形参,这样函数内部可以直接操作实参的内存地址,从而直接修改实参的值。
  • 特点:函数内部操作的是原始变量的内存地址,修改会直接影响实参。
实例2:写一个函数交换两个整型变量的内容。
#include<stdio.h>

void change(int* pa, int* pb)
{
	int reg = 0;
	reg = *pa;
	*pa = *pb;
	*pb = reg;
}

int main()
{
	int i = 10;
	int j = 20;
	printf("交换前i=%d,j=%d\n", i, j);
	change(&i, &j);
	printf("交换后i=%d,j=%d\n", i, j);
	return 0;
}
实例3:写一个函数判断一个数是不是素数
#include<stdio.h>
#include<math.h>
#include<stdbool.h>

bool is_prime(int a)
{
	int i = 2;
	if (a % 2 == 0 || a == 1)
		return false;
	else
	{
		while (i < sqrt(a))
		{
			if (a % i == 0)//这里出现报错:”表达式不是一个可以修改的左值“,意味着我在对a进行赋值,显然是漏了一个”=“。
			{
				return false;
				break;
			}
			i++;
		}
		if (i >= sqrt(a))
		{
			return true;
		}
	}
}

int main()
{
	int num = 107;
	if (is_prime(num) == false)
		printf("no");
	else if (is_prime(num) == true)
		printf("yes");
	return 0;
}
  • 对代码的优化:不需要使用布尔类型,只需要让函数返回1和0,在打印时,if(sqrt(a)),即可自动判断真与假。
#include<stdio.h>
#include<math.h>

int is_prime(int a)
{
	int i = 2;
	if (a % 2 == 0 || a == 1)
		return 0;
	else
	{
		while (i < sqrt(a))
		{
			if (a % i == 0)//这里出现报错:”表达式不是一个可以修改的左值“,意味着我在对a进行赋值,显然是漏了一个”=“。
			{
				return 0;
				break;
			}
			i++;
		}
		if (i >= sqrt(a))
		{
			return 1;
		}
	}
}

int main()
{
	int num = 107;
	if (is_prime(num))
		printf("yes");
	else
		printf("no");
	return 0;
}

2.2.3函数的嵌套调用

  • 嵌套调用是指一个函数在其内部调用另一个函数的情况,或者函数在自身内部调用自身(递归)的情况。函数可以嵌套调用,但是不能嵌套定义。

2.2.4函数的链式访问

  • 链式访问依赖函数的返回值,将函数的返回值作为另一个函数的参数

3.函数的声明与定义

3.1函数的声明

  1. 函数的声明一般出现在函数的使用之前,先声明后使用。
  2. 函数的声明一般要放在头文件里。库函数中的头文件使用尖括号<>,自己定义的头文件使用双引号""。
  3. 告诉编译器函数叫什么,参数是什么,返回类型是什么。参决定不了函数是否存在。
  4. 在使用函数的前方没有函数的定义时,需要声明函数。
#include "add.h"

3.2函数的定义

  • 函数的定义时指函数的具体实现,交代函数的功能实现。

3.3函数的递归

什么是递归

  • 程序调用自身的变成技巧称为递归。递归是一种方法,可以将复杂大规模问题层层转化为一个与原问题相似的简单问题。
实例1:编写一个函数,输出一个无符号整数的每一位。
#include<stdio.h>
#include<math.h>

//输入一个整数,按顺序打印它的每一位

typedef unsigned int uint;

void print(uint a)
{
	if (a >= 10)
	{
		print(a / 10);
	}
	printf("%d", a % 10);
}

int main()
{
	uint num = 1234;
	print(num);
	return 0;
}

递归的两个必要条件

  • 存在限制条件,当条件满足时,递归不再继续。
  • 每次递归调用后越来越接近这个条件。
实例2:编写函数,不创建临时变量,求字符串长度。
#include<stdio.h>
#include<math.h>

//编写函数不创建临时变量,求字符串长度。
int str_long(char* str)
{
	if (*str != 0)
		return 1 + str_long(str+1);//这里最开始错误的使用了str++,使得每层的形参值不变,产生死循环

	else
		return 0;
}

int main()
{
	char arr[] = "abc";
	printf("%d",str_long(arr));
	return 0;
}
  • 理解:一个巧妙的返回值递归,后一层函数的返回值嵌套在前一层函数,实现不需要临时变量count++的累计计数。同时巧妙地运用str+1来执行指针的位移。

实例3:实现一个数的阶乘计算。

#include<stdio.h>
#include<math.h>

//编写函数不创建临时变量,求字符串长度。
int fac(int a)
{
	if (a > 1)
		return a * fac(a - 1);
	else
		return 1;
}

int main()
{
	int num = 4;
	printf("%d",fac(num));
	return 0;
}

实例4:计算第n个斐波那契数。

#include<stdio.h>

int fibo(int a)
{
	if (a == 1||a == 2)
		return 1;
	else
		return fibo(a-1)+fibo(a-2);
}

int main()
{
	int num = 10;
	printf("%d",fibo(num));
	return 0;
}
  • 函数的嵌套技巧性很强,需要多理解!!

补充知识点1:数组的初始化

  • 数组初始化的性质:部分初始化后的数组,未初始化的数组元素会自动填充0,即‘\0’.注意,
  • 在字符中,‘0’和0,即\0是不同的,常见的初始化数组为空的定义方式为:
char arr[20] = {0};
char arr[20] = {'a'};//第一个元素为a,其余为空字符.

补充知识点2:main()函数冲突

  • 一个项目(多个.c文件中只能有一个main()函数)中只能有一个main函数

补充知识点3:常用的缩写变量名

  • i, j, k - 通常用作循环控制变量(iterators)。
  • n - 常用于表示数量(number)、大小(size)或计数(count)。
  • ptr - 指针(pointer)的缩写。
  • len - 表示长度(length)。
  • idx - 索引(index)。
  • tmp - 临时变量(temporary)。
  • cnt - 计数(count)。
  • buf - 缓冲区(buffer)。
  • str - 字符串(string)。
  • ch - 字符(character)。
  • val - 值(value)。
  • num - 数字(number)。
  • max, min - 最大值和最小值。
  • avg - 平均值(average)。
  • sum - 求和(sum)。
  • res - 结果(result)。
  • flg - 标志位(flag)。
  • arg - 参数(argument)。
  • err - 错误(error)。
  • src, dest - 来源和目标(source, destination)

补充知识点4:监测调试的方法

  • 通过F10(step over)进入调试模式下“逐过程”执行代码,每次按下F10,程序就会执行下一步,需要注意的是,左侧的箭头是指程序下一步执行的语句,而不是已经执行完的语句。 
  • F10会自动跳过函数内部的执行细节,想要查看函数的运行,需要在箭头指向函数时,按下F11(step into),使执行跳转到函数内部。

补充知识点5:指针与地址

1.*代表解引用操作

  • 作用:解引用一个指针,访问指针指向的变量的值。
  • 使用场景:当你想要访问或修改指针所指向的内存位置上的值时,使用 * 操作符。

2.&代表取地址操作

  • 定义& 是取地址操作符,用于获取变量的内存地址。
  • 作用:它将返回一个指向该变量的指针,即该变量在内存中的位置。
  • 使用场景:常用于指针初始化、传递参数给需要指针的函数等。

3.区分 * 的不同作用

  • 声明指针时的 *:在 int *ptr; 中,* 只是用来定义 ptr 是一个指针变量,而不是对 ptr 的解引用。即*用来表示ptr是一个指针变量
  • 解引用操作时的 *:当 * 用在已经声明的指针变量前时(如 *ptr),才表示对该指针的解引用,即访问指针指向的内存中的值。

4.字符数组

  • 在字符数组str[20]中,str是指向字符数组的首字符的指针。当对str执行str++;操作时,可以将指针指向下一个存储单元,也就是下一个字符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值