当前位置: 首页 > news >正文

C语言基础:弟11天笔记


内容提要


函数
函数的调用
调用方式
①函数语句:

 test();//对于没有返回值的函数,直接调用
 int res =max(2,4)  //对于有返回值的函数,一般需要在主调函数中接收被调函数的返回值
②函数表达式:

 4  + max(2,4);
 scanf("%d",&num)!=1;
 (c=getcahr())!='\0'
③函数参数:

 printf("%d",max(2,4));//将有返回值的函数作为实参
 printf("%d",(int)fabs(num));
在一个函数中调用另一个函数具备以下条件:


 int b()
 {
     
     
 }
 ​
 int a()
 {
     b();
 }
函数的声明
函数调用时,往往要遵循先定义后使用,但如果我们对函数的调用操作出现在函数定义之前,则需要对函数进行声明。

完整的函数分为三部分:

定义:

 int max(int x,int y);//指明参数名称
 int max(int ,int,double);//省略参数名称


 int max(int x,int y,double z)//函数定义,不能省略参数的数据类型,参数个数,位置要和函数声明完全一致
 {
     return x>y?x:y>z?y;(int)z;  
 }


 int main()
 {
     printf("%d\n",max(4,5,6));
     
 }
函数声明的作用:


函数声明的使用
错误演示:被调函数写在主调函数之后

 //主调函数
 int main()
 {
     printf("%d\n",add(12,13));//此时编译会报编译错误,因为函数没有经过声明,编译系统无法检查函数调用的合法性
 }
 ​
 //被调函数
 int add(int x,int y)
 {
     return x+y;
 }
正确演示:被调函数写在主调函数之前

 ​
 //被调函数
 int add(int x,int y)
 {
     return x+y;
 }
 ​
 //主调函数
 int main()
 {
     printf("%d\n",add(12,13));//
 }
注意:如果函数的调用比较简单,并且被调函数写在主调函数之前,此时是可以省略函数声明的。

正确演示:被调函数黑主调函数无法区分前后,需要增加被调函数的函数声明

 //函数声明
 int add(int x, int y);//写法一
 ​
 int add(int,int);//写法二
 ​
 ​
 //被调函数
 int add(int x,int y)
 {
     return x+y;
 }
 ​
 //主调函数
 int main()
 {
     printf("%d\n",add(12,13));//
 }
注意:如果涉及函数的相互嵌套作用,或者复杂嵌套调用,此时无法区分函数的前后,这就需要函数的声明。

 int add(int a,int b)
 {
 ​
 }

 int add(int ,int)
函数的嵌套使用
定义
函数不允许嵌套定义,允许嵌套调用


 void(....){.....}
 ​
 void b()
 {
     a();
 }

 void a()
 {
     void b()
     {
         
     }
 }
嵌套调用:在被调函数内主动去调用其他函数,这样的函数调用形式,称为嵌套使用。

案例:
案例1

 /*************************************************************************
   > File Name:    1.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 10时26分46秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 /**
  *定义一个函数,求素数
  *param n :需要校验素数的整数
  *
  *
  * */
  
  
  int is_prime(int n)
 {
     int k,i,flag=1;
     //过滤素数:2~n-1
     for(i=2;i<n-1/*n/2*/;i++)//在2~n-1,出现了能被正除的情况,就跳出,因为他已经是非素数
     {
         if(n%i==0)
         {
             flag=0;
             break;
         }   
     }
     return flag;
 ​
 }
 ​
 ​
 int main(int argc,char *argv[])
 {
     for(int i=3;i<=100;i++)
     {
         if(is_prime(i))
             printf("%-4d",i);
     }
     printf("\n");
     return 0;
 }
案例2


 /*************************************************************************
   > File Name:    2.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 10时45分14秒
  ************************************************************************/
 ​
 #include <stdio.h>
 int max_2(int,int);
 int max_4(int,int,int,int);
 ​
 int max_2(int a,int b)
 {
     return a>b?a:b;
 }
 ​
 int max_4(int a,int b,int c,int d)
 {
     //写法1
   /*  int max;
     max=max_2(a,b);
     max=max_2(max,c);
     max=max_2(max,d);*/
 ​
     //写法2
     return max_2(a,b)>max_2(c,d)?max_2(a,b):max_2(c,d);
 }
 ​
 ​
 int main(int argc,char *argv[])
 {
     
     int a,b,c,d;
     printf("请输入4个整数:\n");
     
         scanf("%d%d%d%d",&a,&b,&c,&d);
 ​
         //接收最大值
         int max=max_4(a,b,c,d);
 ​
         printf("%d,%d,%d,%d中的最大值为%d\n",a,b,c,d,max);
     
     return 0;
 }
函数的递归调用
定义
递归调用的含义:在一个函数中,直接或者间接调用函数自身,就称之为函数的递归调用。本质上还是函数的嵌套调用。

 //直接调用
 a() →a()
     
 // 间接调用
 a()---->b()---->c()
     
 a()---->b().....a();
递归调用的本质:

是一种循环结构,他不同于我们之前学的while、for、do....while循环结构,这些循环结构是借助于循环变量;而递归调用时利用函数自身实现循环结构,如果不加以控制,很容易产生死循环。

递归调用的注意事项:

①递归调用必须要有出口,一定要想办法终止递归(否则就会产生死循环)

②对终止条件的判断一定要放在函数递归之前(先判断,在执行)

③进行函数递归调用

④函数递归的同时一定要将函数调用向出口逼近。

案例
案例1


 /*************************************************************************
   > File Name:    3.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 11时18分03秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 /**
  *定义一个函数,求年龄
  *param n:第n个人
  *return 第n个人年龄
  */
 ​
 int get_age(int n)
 {
     //创建一个变量,存储函数返回值,返回的是年龄
     int age ;
     //出口设置
     if(n==1)    //第一个人
         age=10;
     else if(n>1)
         age=get_age(n-1)+2;//当前这个人的年龄=上一个人的年龄+2
     return age;
 ​
 ​
 }
 ​
 int main(int argc,char *argv[])
 {
     printf("%d\n",get_age(5));
     return 0;
 }
案例2

 /*************************************************************************
   > File Name:    4.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 14时11分42秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 /**
  *定义一个函数,求n的阶乘
  *@param n上限
  *@return 阶乘运算结果
  * */
 ​
 size_t fac(int n)
 {
     size_t f;//定义一个变量。用作阶乘结果的接收
     
     //出口校验
     if(n<0)
     {
         printf("n的范围不能是0以下的数\n");
         return -1;
     }
     else if(n==0||n==1)
     {
         f=1;//出口
     }
     else   //n>1递归
         f=fac(n-1)*n;
 }
 ​
 int main(int argc,char *argv[])
 {
     size_t n;
     printf("请输入一个整数:\n");
     scanf("%lu",&n);
     printf("%lu的阶乘为%lu\n",n,fac(n));
     return 0;
 }
排序算法:快速排序
快速排序(Quick Sort)是一种高效的排序算法,采用分治法(Divide and Conquer)策略。它的核心思想是通过选取一个”基准值”(pivot),将数组分为两部分:一部分比基准值小,另一部分比基准值大,然后递归地对这两部分进行排序。

快速排序的基本步骤

1.选择基准值:


2.分区(Partition):


3.递归排序:


4.合并结果:


分析:


总结:

快速排序,实际上就是通过一个基准值不断拆分数组,一直拆到不能再拆为止(最后只剩一个元素)

代码:

 /*************************************************************************
   > File Name:    5.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 15时06分31秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 /**
  * 定义一个函数,实现快速排序
  *@param arr:待排序数组
  *@param n 出口
  */
 ​
 void QSort(int arr[],int n)
 {
     if(n<2)   //递归终止条件
         return;
 ​
     int i=0,j=n-1;//定义两个指针,i是从左往右,j是从右往左
 ​
     int pivot =arr[0];// 选择第一个元素 作为基准值
 ​
     while(i<j)
     {
         while(arr[j]>pivot&&i<j)
             j--;
         while(arr[i]<=pivot&&i<j)
             i++;
         //交换找到两个元素
         int temp =arr[i];
         arr[i]=arr[j];
         arr[j]=temp;
     
     }
     //i==j相遇,分区结束,基准值归位
     int temp=arr[0];
     arr[0]=arr[i];
     arr[i]=temp;
 ​
     //递归排序左半部分  <= 基准
     QSort(arr,i);
     //递归排序右半部分 >基准
     QSort(arr+i+1,n-1-i);
 }
 ​
 int main(int argc,char *argv[])
 {
     int arr[]={23,45,56,24,14,78,22,19};
     //排序
     QSort(arr,sizeof(arr)/sizeof(arr[0]));
 ​
     for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
     {
         printf("%-4d",arr[i]);
     }
     printf("\n");
     return 0;
 }
数组做函数参数
定义
当用数组做函数的实参时,则形参应该也要用数组或者指针变量来接收(函数实参是数组,形参一定是数组或者指针),注意的是,此次传递的并不代表传递了数组中所有元素数据,而是传递了第一个元素的内存地址(数组首地址),形参接收到这个地址后,则形参和实参就代表了同一个内存空间,则形参的数据修改会改变实参。这种数据传递方式称为地址传递


如果用数组作为函数的形参,那么我们提供另一个形参表示数组的元素个数。原因是数组形参代表的仅仅是实际数组的首地址。也就是说形参只获取到了实参数组的第一个元素的地址,并不确定传递了多少个数据。所以提供另一个形参表示数组元素的容量,可以防止在被调函数对实际数组访问时产生的下标越界。

 //定义一个函数,将数组作为参数
 void fun(int arr[],int len)//数组传参,形参只能接收到实参数组的首地址,并不是完整的数组
 {
     for(int i =0;i<len;i++)
     {
         printf("%-4d",arr[i]);
         
     }
     printf("\n");
 }
 ​
 void main()
 {
     int arr[]={11,22,33,44,55};
     inr len =sizeof(arr)/sizeof(arr[0]);
    
     fun(arr,len)
     
 }
但有一个例外,如果是用字符数字做形参,且实参数组中存放的是字符串数据(形参是字符串数组,实参是字符串常量)。则不用表示数组元素个数的形参,原因字符串本身自动会自动结束标志\n,举例:

 //定义一个函数,传递一个字符
 void fun(char arr[])
 {
     char c;
     int i=0;
     while((c=arr[i])!='\0')
     {
         printf("%c\n",c);
         i++;
     }
     printf("\n");
 }
 ​
 void main()
 {
     fun("hello");
 }
案例
案例1

 int a[10]={12,12,10,18,5};
 int b[10]={111,112,110,8,5};

 /*************************************************************************
   > File Name:    6.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 16时52分33秒
  ************************************************************************/
 ​
 #include <stdio.h>
 #define LEN 5
 ​
 ​
 /***
  *定义一个函数,实现两个数字的比较
  *@param x,y 参与比较的两个数字
  *@return 比较结果x>y返回1,x<y返回-1,x==y返回0
  *
  */
 ​
 ​
 int get_large(int x,int y)
 {
     int flag=0;
     if(x>y)
         flag=1;
     else if (x<y)
         flag=-1;
     return flag;
 ​
 }
 ​
 int main(int argc,char *argv[])
 {
     //定义两个数组,循环变量,最大,最小,相等
     int a[LEN]={12,12,10,18,5};
     int b[LEN]={111,112,110,8,5};
 ​
     int i ,max=0,min=0,k=0;
 ​
 ​
     //遍历循环,进行比较
     for(i=0;i<LEN;i++)
     {
         int res=get_large(a[i],b[i]);
         if(res==1)
             max++;
         else if(res==-1)
                 min++;
         else 
             k++;
     }
     printf("max=%d,min=%d,k=%d\n",max,min,k);
     return 0;
 }
案例2

 /*************************************************************************
   > File Name:    7.c
   > Author:       
   > Description:  
   > Created Time: 2025年03月17日 星期一 17时02分33秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 float get_avg(float score[],int len)
 {
     int i;
     float aver,sum=score[0];
 ​
     //遍历数组
     for (i=1;i<len;i++)
     {
         sum+=score[i];
     }
         aver =sum/len;
         return aver;
 }
 int main(int argc,char *argv[])
 {
     //准备两个测试数组
     float score1[]={66,78,86,56,46};
     float score2[]={77,88,98,87,67,65,55,45,67,78};
 ​
     printf("这个班的平均分:%6.2f\n",get_avg(score1,sizeof(score1)/sizeof(score1[0])));
     
     printf("这个班的平均分:%6.2f\n",get_avg(score2,sizeof(score2)/sizeof(score2[0])));
 ​
     return 0;
 }

相关文章:

  • ubuntu20.04 APT 安装MySQL Community Server 8
  • vue create 与 vue init webpack 的 区别
  • 游戏搭建云服务器配置推荐
  • PyTorch --torch.cat张量拼接原理
  • 前端er在Cursor使用MCP实现精选照片的快速上手教程
  • AISTATS 2025 | ChronosX:利用外生变量调整预训练时间序列模型
  • Fnos 飞牛Nas安装桌面环境 gnome和KDE桌面- All in One 笔记~1
  • Dubbo(25)如何配置Dubbo的协议和端口?
  • 【减小图片打包体积】image-webpack-loader
  • MySQL--数据备份
  • 实时数据流处理利器:Apache Storm 在大数据中的应用
  • .Net中对称加密的实现
  • cJSON类型及type值详解
  • ECharts系列: Vue 中使用 ECharts 折线图时,怎么配置来实现默认隐藏某些图例,并在用户点击图例时显示或隐藏对应的数据系列
  • MySQL的事务
  • Springboot3.x集成Spring Batch 5.2.1
  • 面试经典150题·LeetCode26·删除有序数组中的重复项·Java
  • 18.redis基本操作
  • 内积相似系数——内积度量相似系数
  • html 列表循环滚动,动态初始化字段数据
  • 手机网站开发+图库类/如何申请百度竞价排名
  • 443是端口网站建设/郑州百度推广代运营
  • 做攻略的网站好/百度竞价是什么工作
  • 用dw制作做网站需要钱吗/西安百度推广优化
  • php网站留言板模板/网络营销推广服务
  • 做网站遇到的问题及解决方法/搜索引擎网站有哪些