首页 > 其他分享 >C语言函数详解

C语言函数详解

时间:2024-07-12 17:27:47浏览次数:18  
标签:return 函数 int ret C语言 详解 printf 库函数

文章目录

函数的概念

数学中我们其实就⻅过函数的概念,⽐如:⼀次函数 y=kx+b ,k和b都是常数,给⼀个任意的x,就得到⼀个y值。
其实在C语⾔也引⼊函数(function)的概念,有些翻译为:⼦程序,⼦程序这种翻译更加准确⼀些。C语⾔中的函数就是⼀个完成某项特定的任务的⼀⼩段代码。这段代码是有特殊的写法和调⽤⽅法的。C语⾔的程序其实是由⽆数个⼩的函数组合⽽成的,也可以说:⼀个⼤的计算任务可以分解成若⼲个较⼩的函数(对应较⼩的任务)完成。同时⼀个函数如果能完成某项特定任务的话,这个函数也是可以复⽤的,提升了开发软件的效率。

库函数

C语⾔标准中规定了C语⾔的各种语法规则,C语⾔并不提供库函数;C语⾔的国际标准ANSIC规定了⼀些常⽤的函数的标准,被称为标准库,那不同的编译器⼚商根据ANSI提供的C语⾔标准就给出了⼀系列函数的实现。这些函数就被称为库函数。
printf 、 scanf 都是库函数,库函数的也是函数,不过这些函数已经是现成的,我们只要学会就能直接使⽤了。有了库函数,⼀些常⻅的功能就不需要程序员⾃⼰实现了,⼀定程度提升了效率;同时库函数的质量和执⾏效率上都更有保证。
库函数相关头⽂件:https://zh.cppreference.com/w/c/header
库函数介绍网站https://legacy.cplusplus.com/reference/clibrary/

库函数的使⽤⽅法

库函数是在标准库中对应的头⽂件中声明的,所以库函数的使⽤,务必包含对应的头⽂件,不包含是可能会出现⼀些问题的。
例如:

#include <stdio.h>
#include<math.h>//sqrt函数的头文件
int main()
{
 double d = 16.0;
 double r = sqrt(d);//sqrt函数求d的算术平方根
 printf("%lf\n", r);
 return 0;
}

⾃定义函数

其实⾃定义函数和库函数是⼀样的,形式如下:
ret_type fun_name(形式参数)
{
}
1、ret_type 是⽤来表⽰函数计算结果的类型,有时候返回类型可以是 void ,表⽰什么都不返回
2、fun_name 是为了⽅便使⽤函数;就像⼈的名字⼀样,有了名字⽅便称呼,函数有了名字⽅便调⽤,所以函数名尽量要根据函数的功能起的有意义。
3、 函数的参数就相当于,⼯⼚中送进去的原材料,函数的参数也可以是 void ,明确表⽰函数没有参数。如果有参数,要交代清楚参数的类型和名字,以及参数个数。
4、 {}括起来的部分被称为函数体,函数体就是完成计算的过程。
举个例子:

#include <stdio.h>
int Add(int x, int y)//int表示返回类型是int型的 
{
 int z = 0;
 z = x+y;
 return z;
}
int main()
{
 int a = 0;
 int b = 0;
 //输入a和b 
 scanf("%d %d", &a, &b);
 //调用加法函数,完成a和b的相加 
 //求和的结果放在r中 
 int r = Add(a, b);
 //输出 
 printf("%d\n", r);
 return 0;
}

注意如果自定义函数写在了主函数的后面就需要对函数进行声明。
例如

#include <stdio.h>
int Add(int x, int y); 
int main()
{
 int a = 0;
 int b = 0;
 //输入a和b 
 scanf("%d %d", &a, &b);
 //调用加法函数,完成a和b的相加 
 //求和的结果放在r中 
 int r = Add(a, b);
 //输出 
 printf("%d\n", r);
 return 0;
}
int Add(int x, int y)//int表示返回类型是int型的 
{
 int z = 0;
 z = x+y;
 return z;
}

int Add(int x, int y); 这就是函数的声明,如果函数不事先进行声明的话,程序就会报错。

形参和实参

Add(a, b);传给Add的参数a,b,称为实际参数,简称实参,实际参数就是真实传递给函数的参数。
Add(int x, int y)在函数名 Add 后的括号中写的 x 和 y ,称为形式参数,简称形参。

实参和形参的关系
在这里插入图片描述
我们在调试的可以观察到,x和y确实得到了a和b的值,但是x和y的地址和a和b的地址是不⼀样的,所以我们可以理解为形参是实参的⼀份临时拷⻉.

接下来通过函数的传值调用和传址调用充分观察一下形参和实参的区别。
传值调用

#include <stdio.h>
void swap(int a,int b);
int main()
{
  int a=10,b=20;
  printf("交换前%d %d\n",a,b);
  swap(a,b);
  printf("交换后%d %d\n",a,b);
  return 0; 
}
void swap(int a,int b)
{
	int temp=a;
	a=b;
	b=temp;
}

在这里插入图片描述

传址调用

#include <stdio.h>
void swap(int* a,int* b);
int main()
{
  int a=10,b=20;
  printf("交换前%d %d\n",a,b);
  swap(&a,&b);
  printf("交换后%d %d\n",a,b);
  return 0; 
}
void swap(int* a,int* b)
{
	int temp=*a;
	*a=*b;
	*b=temp;
}

在这里插入图片描述

传值调用只是只是用形参改变了函数体里面X,Y的值,而没有真正改变实参a,b的值。所以说形参是实参的⼀份临时拷⻉。只有传址调用,传的是地址,真正意义上传的实参本身这样就可以达到我们想要的结果。

基本的传参类型

前面写了传值和传址的函数类型
下面写一些别的传参
涉及动态内存开辟,和二级指针传参,数组传参
这也是力扣上面四数之和一题的源代码。
如果对题目感兴趣的也可以看一下四数之和解题过程

int compare(void const *str1,void const *str2)
   {
   	return *((int*)str1)-*((int*)str2);
   }
void fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) 
 {
      qsort(nums,numsSize,sizeof(int),compare);
      int **ret=(int**)malloc(sizeof(int*)*numsSize*numsSize);
      *returnColumnSizes=(int*)malloc(numsSize*numsSize*sizeof(int));
      *returnSize=0;
      for(int i=0;i<numsSize;)
      {
 	 	for(int j=i+1;j<numsSize;)
 	 	{
 		 	int left=j+1;
 		 	int right=numsSize-1;
 		 	long aim=(long)target-nums[i]-nums[j];
 		 	while(left<right)
 		 	{
 		 		int sum=nums[left]+nums[right];
 			 	if(sum>aim) right--;
 				else if(sum<aim) left++;
 				else
 				{
                     (*returnColumnSizes)[*returnSize] = 4;
                     ret[*returnSize] = (int*)malloc(sizeof(int) * 4);
 					ret[*returnSize][0]=nums[i];
 					ret[*returnSize][1]=nums[j];
 					ret[*returnSize][2]=nums[left++];
 					ret[*returnSize][3]=nums[right--];
 					(*returnSize)++;
 					while(left<right&&nums[left]==nums[left-1]) left++;
 					while(left<right&&nums[right]==nums[right+1]) right--;
 				} 
 			 }
 			 j++;
 			 while(j<numsSize&&nums[j]==nums[j-1]) j++;
 	    }
 	    i++;
 	    while(i<numsSize&&nums[i]==nums[i-1]) i++;
 	 }
 	 for(int i=0;i<*returnSize;i++)
	   	{
	  	 for(int j=0;j<4;j++)
	  	 {
	  	 	printf("%d ",ret[i][j]);
	  	 }
		   printf("\n");	
	      }
 	  	//return ret;
 }
 int main()
 {
 	int nums[6]={-1,0,1,-2,0,2};
 	int row=0;
 	int* col=(int*)malloc(sizeof(int)*100);
 	fourSum(nums,6,0,&row,&col);
 	return 0;
 }

一维数组和二维数组的传参

void fun(int arr[2][3],int arr1[],int i,int j,int k)
 {
 	
 }
int main()
{
	int arr[2][3]={{1,2,3},{4,5,6}};
	int arrlenrow=sizeof(arr)/sizeof(arr[0]);//行 
	int arrlencol=sizeof(arr[0])/sizeof(int);//列 
	int arr1[]={1,2,3,4,5};
	int arr1len=sizeof(arr1)/sizeof(arr1[0]);
	fun(arr,arr1,arrlenrow,arrlencol,arr1len);
}

嵌套调⽤

嵌套调⽤就是函数之间的互相调⽤,每个函数就⾏⼀个乐⾼零件,正是因为多个乐⾼的零件互相⽆缝的配合才能搭建出精美的乐⾼玩具,也正是因为函数之间有效的互相调⽤,最后写出来了相对⼤型的程序。
假设我们计算某年某⽉有多少天?如果要函数实现,可以设计2个函数:
1、 is_leap_year():根据年份确定是否是闰年
2、get_days_of_month():调⽤is_leap_year确定是否是闰年后,再根据⽉计算这个⽉的天数

int is_leap_year(int y)
 {
  if(((y%4==0)&&(y%100!=0))||(y%400==0))
  return 1;
  else
  return 0;
 }
 int get_days_of_month(int y, int m)
 {
  int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  int day = days[m];
  if (is_leap_year(y) && m == 2)
  day += 1;
  return day;
 }
int main()
 {
  int y = 0;
  int m = 0;
  scanf("%d %d", &y, &m);
  int d = get_days_of_month(y, m);
  printf("%d\n", d);
  return 0;
 }

main 函数调⽤ scanf 、 printf 、 get_days_of_month
get_days_of_month 函数调⽤ is_leap_year

链式访问

所谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。

int add(int a,int b)
{
	return a+b;
}
 int main()
 {
 	int a=10,b=20,c=30;
 	int ret=add(add(a,b),c);
 	printf("%d",ret);
 	return 0;
 }

多个⽂件

代码可能⽐较多,不会将所有的代码都放在⼀个⽂件中;我们往往会根据程序的功能,将代码拆分放在多个⽂件中。
⼀般情况下,函数的声明、类型的声明放在头⽂件(.h)中,函数的实现是放在源⽂件(.c)⽂件中。

在这里插入图片描述
我们引用自己写的头文件时用""
感谢您的阅读,欢迎留言,点赞,收藏。

标签:return,函数,int,ret,C语言,详解,printf,库函数
From: https://blog.csdn.net/2403_82759827/article/details/140380185

相关文章

  • 【python】函数重构
    函数重构函数重构pycharm函数重构步骤函数重构练习函数重构函数重构是指对现有函数进行修改和优化的过程。重构的目的是改善代码的可读性、可维护性和灵活性,同时保持其功能不变。函数重构通常包括以下步骤:理解函数的功能和目的。了解函数的作用和期望结果,确定重构......
  • 嵌入式C语言概述
    什么是嵌入式系统?嵌入式系统是指一个集成了软件和硬件的专用计算机系统,通常用于执行特定的任务。与通用计算机系统不同,嵌入式系统具有以下特点:专用性:嵌入式系统通常执行单一或特定的任务。资源有限:嵌入式系统的硬件资源(如处理器速度、内存容量)通常有限。实时性:许多嵌入式系统......
  • AvalonMM接口PIO IP的介绍和PIO的读写操作详解
    一、PIO寄存器介绍Avalon®-MM主机外设(如CPU)通过四个32位寄存器控制并与PIO核通信,如下所示。该表假设PIO核的I/O端口被配置为n位宽度。以上截图来自IntelEmbeddedPeripheralsIPUserGuide。data寄存器如果将PIO硬件配置为输入或仅输入输出模式,则从数据读取将返回输入端......
  • Lua 中的可变长函数
    可变长函数Lua中的可变长函数的参数用...来表示(3个.)在函数内部有一个特殊的内置变量arg其格式如下arg={1,"Hello",true,n=3}--functionmakeVarStr(...)toseeprint_Table.luafunctionprintMultiArg(...) print("...="..makeVarStr(arg))end......
  • 前端web程序发布到windows服务器流程详解
    假定已完成前端程序开发并完成构建。#步骤1:准备服务器环境我们将使用IIS作为Web服务器。确保你的Windows系统已经安装了IIS。#步骤2:配置Web服务器1.打开"控制面板">“程序”>“启用或关闭Windows功能”。2.选中"InternetInformationServices",确保"Web服务器(IIS......
  • Java中的方法重写详解
    Java中的方法重写详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!1.方法重写的定义和特点方法重写(MethodOverriding)是指子类可以重写父类的同名方法,以便于子类根据自身特定的需求来实现方法的具体行为。重写方法必须具有相同的方法签名,即方法名、......
  • Java中的final关键字详解
    Java中的final关键字详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!1.final关键字的基本用法在Java中,final关键字可以用来修饰类、方法和变量,具有不同的含义和作用。下面我们逐一介绍其在各个方面的应用。2.final修饰类当一个类被final修饰时,表......
  • 适用于react、vue菜单格式化工具函数
    场景在一个动态菜单场景中,你向接口获取树形菜单,但最后拿到的树未能达到你的预期,这个时候就需要手写递归重新处理这颗树适用于react、vue菜单格式化工具函数包含功能1.当前路由是否存在返回按钮判断逻辑:只要存在左侧可点击的菜单都不具备返回按钮,其他则具有返回按钮2.错误......
  • Lua调用C的函数
    #include<iostream>#include<string>usingnamespacestd;extern"C"{#include"lua.h"#include"lualib.h"#include"lauxlib.h"}intmyTest(lua_State*L){//获得Lua函数的参数的数量intn......
  • 初识c语言-1
     1.主函数intmain(){return0;} 注:c语言规定main是函数的入口,且只能有一个。  2.数据类型  是用来创建变量的,创建变量的本质是用来向内存申请空间的。char字符数据类型1byetshort短整型2byetin整型4byetlong长整型4byetlonglong更长的整型  8byet f......