函数(2)

简介: 函数(2)

在讲之前再讲一下代码要规范:如下

//代码1
#include<stdio.h>
test()
{
  printf("hehe\n");
}
int main()
{
  int ret=test();
  printf("%d\n", ret);
  return 0;
}


我们可以看出test是有返回值的。

(1)C语言规定:函数的返回类型不写的时候,默认是返回的是int类型。

建议:真的不需要函数返回值的时候,明确写void。

(2)为什么返回的是5呢?(我们现在知道就行,不用深入了解)

①除main外,其余函数没有写return,取决于编译器的实现(返回的一般,是函数执行完的最后一条指令所产生的结果)

②main,没写return,默认返回0

(3)printf函数的返回值是打印在屏幕上字符的个数。

//代码2
#include<stdio.h>
void test()
{
  printf("hehe\n");
}
int main()
{
  test(100);
  return 0;
}

如上:虽可运行,但不严谨

C的不严谨:不需要传参时,应写void;否则完全可能传参,只是函数没有接收。

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

函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的


5.1  嵌套调用

函数的嵌套调用,即在一个被调函数内部,又调用了其他的函数。

1、代码演示:

//嵌套调用
#include<stdio.h>
void new_line(void)
{
  printf("hehe\n");
}
void three_line(void)
{
  int i = 0;
  for (i = 0; i < 3; i++)
  {
    new_line();//调用new_line三次
  }
}
int main()
{
  three_line();//调用three_line
  return 0;
}


2、图示如下:

注:函数可以嵌套调用,但是不能嵌套定义


5.2  链式访问

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

例子:

//代码1
#include<stdio.h>
#include<string.h>
int main()
{
  char arr[20] = "hello";
  int ret = strlen(arr);//计算字符串长度,注统计‘\0’之前的字符个数
  printf("%d\n", ret);
  printf("%d\n", strlen(arr));//strlen的返回值作为printf的参数
  return 0;
}


如上,我们应该能体会到什么是链式访问了。

我们再举一个链式访问的经典例子:

//代码2
#include<stdio.h>
int main()
{
  printf("%d", printf("%d", printf("%d", 43)));
  //printf的返回值是打印在屏幕上字符的个数
  return 0;
}

tip:printf函数的返回值是打印在屏幕上字符的个数。

程序输出:4321

6.  函数的声明和定义

6.1  函数的声明

1、告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。(声明只是告诉你有,但是真的有没有取决于定义)

声明的一般形式如下:

          ①返回类型   函数名(形参列表); 如:int  Add(int x,int y);

          ②返回类型   函数名(形参类型列表); 如:int  Add(int ,int );

好的风格:建议使用①;  

注:函数的声明以“;”结束,不能省略。

2、函数的声明一般出现在函数的使用之前,要满足先声明后使用。

3、函数的声明一般放在头文件中的

6.2  函数的定义

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


说明:函数为什么要声明?

代码在编译的时候,要进行代码的扫描,是顺序从前往后扫描的。

1、当函数定义出现在函数调用之后时,在主调函数前,采用函数原型对被调用函数进行声明。

当不声明,编译器会警告,如下:

2、函数定义出现在函数调用之前,可不用进行函数声明。(函数的定义也是一种特殊的声明)

#include<stdio.h>
//函数的声明
int Add(int x, int y);
int main()
{
  int a = 0;
  int b = 0;
  scanf("%d %d", &a, &b);
  int ret = Add(a, b);
  printf("%d", ret);
  return 0;
}
//函数的定义
int Add(int x, int y)
{
  return x + y;
}

这就学会了函数的定义和声明吗?


函数的声明和定义,不是这样用的,以上只是它的一种运用场景,只是它的语法展示,真正在工程中,函数的定义和声明,我们是怎么写的呢?

头文件:.h——放置函数的声明

源文件:.c——放置函数的实现(定义)

如要写一个函数实现求两个整数的和:

1、创建一个源文件:add.c——放置函数的实现(定义)


2、创建一个头文件:add.h——放置函数的声明


3、测试——再创建一个源文件:test.c


在工程中想要使用(调用)Add函数,也是如库函数一样要打招呼。

库函数:使用库函数,必须包含 #include 对应的头文件。

自定义函数:也如库一样,必须包含#include对应的头文件。

如上截图:库函数的头文件名一般用<>引用,自定义函数的头文件名一般用“”引用。

我们本可以在一个.c文件写的,为什么分成三个文件呢?好处是什么呢?


1、模块化开发(分工)

例:要实现一个计算机

      加法——a(程序员做)——add.c  add.h

      减法——b——sub.c  sub.h

      乘法——c——mul.c  mul.h

      除法——d——div.c   div.h

如果不分开,模式化开发,在一个.c文件a、b、c、d四个人怎么同时写了?,还会使代码变得混乱。  

分开,模式化开发每个人都可以同时写,写完后再组成一个.c文件就完成了计算机了。


2、代码的隐藏(可以使用,但不知道源代码)

(1)具体步骤:项目名——属性——配置属性——常规——配置类型——改成静态库——应用——确定——ctrl+f7——在文件中生成xx.lib文件——用记事本查看——显示乱码(2)在另一个项目使用:需要导入xx.lib和xx.h文件

      还需要在主调函数前:#pragma  comment(lib,"xx.lib"),就可使用了

现在知道不再一个.c文件写有隐藏代码的好处就行了,不用深入理解,后期我会在博客中写的。

总结:

函数的声明我们一般放置在头文件中

函数的实现我们都是放置在源文件中

7.  函数的递归

7.1  什么是递归

 程序调用自身的编码技巧称为递归(recursion)。

  递归做为一种算法在程序设计语言中广泛应用。一个函数(或过程)在其定义(或说明)中 有直接或间接调用自身 的一种方法。

    它通常把一个 大型复杂 的问题 层层转化 为一个与原问题 相似 的规模较小的问题来求解。

    递归策略 , 只需少量 的程序就可 描述出解题过程 所需要的 多次重复计算 ,大大地 减少 了程序的代码量。

    递归的主要思考方式在于:把大事化小

最简单的递归:

#include<stdio.h>
int main()
{
  printf("hehe\n");
  main();//递归:在函数内自己调用自己
  return 0;
}

f10调试:


7.2  递归的两个必要条件

1、存在限制条件,当满足这个限制条件的时候,递归便不继续(递归出口)

2、每次递归调用之后越来越接近这个限制条件


7.2.1  练习1

接受一个整型值(无符号),按照顺序打印它的每一位。

例如:

输入:1234,输出1 2 3 4

void print(unsigned int n)
{
  if (n > 9)//限制条件
  {
    print(n / 10);//递归调整,接近限制条件
  }
  printf("%d ", n % 10);
}
int main()
{
  unsigned int num = 0;
  scanf("%d", &num);//1234
  //写一个函数打印num的每一位
  print(num);
  return 0;
}


递归的理解

递——递推

归——回归

先递推后回归。


7.2.2  练习2

编写函数不允许创建临时变量,求字符串的长度。

#include<stdio.h>
int my_strlen(char* str)
{
  if (*str != '\0')
  {
    return 1 + my_strlen(str + 1);//str+1,字符指针+1,向后跳一个字符
  }
  else
  {
    return 0;
  }
}
int main()
{
  char arr[] = "bit";
  int ret = my_strlen(arr);//数组名其实是首元素地址
  printf("%d\n", ret);
  return 0;
}

(1)数组名其实是首元素的地址

(2)字符指针+1,向后跳一个字符。(那整形指针+1,向后跳四个字符)


总结:递归一般都要有两个必要条件(一般与if搭配)

1、有限制条件

2、每一次递推越来越接近限制条件

相关文章
|
3月前
|
C++
c++常见函数及技巧
C++编程中的一些常见函数和技巧,包括生成随机数的方法、制表技巧、获取数字的个位、十位、百位数的方法、字符串命名技巧、避免代码修改错误的技巧、暂停和等待用户信号的技巧、清屏命令、以及避免编译错误和逻辑错误的建议。
33 6
|
5月前
函数\judgeprime
函数\judgeprime
46 5
|
6月前
|
Java 测试技术 Python
为什么要用函数
在编程中,函数是一种重要的抽象工具,它使我们能够组织和复用代码,提高代码的可读性、可维护性和效率。函数允许我们将一段代码块封装起来,给它一个名字,并通过参数和返回值来与外部世界交互。下面,我们将深入探讨为什么要使用函数,并附上相应的代码示例。
68 1
|
6月前
|
存储 编译器 Serverless
C++系列十:函数
C++系列十:函数
|
数据库 索引
pginspect几个函数
pginspect几个函数
81 0
|
6月前
|
开发工具 Windows
GetMessage()函数使用时的注意
GetMessage()函数使用时的注意
79 0
|
编译器
函函函函函函函函函函函数——two
函函函函函函函函函函函数——two
92 0
函函函函函函函函函函函数——two