声明:以下文字仅自己个人总结并手打!!!不存在抄袭!!!
1.函数的声明与定义
1.1什么是函数的声明和定义?
函数的声明和定义是函数在使用前必须进行的两个步骤。 函数的声明是告诉编译器有一个函数的存在,它将在后面定义或实现。它包括函数的名称、返回类型和参数列表。例如,函数声明可以是 "int add(int a, int b)",告诉编译器有一个名为add的函数,它接受两个整数作为参数,并返回一个整数。 函数的定义则是函数的实际实现,它包括函数的功能代码和返回值。例如,函数定义可以是 "int add(int a, int b) { return a + b; }",实现了add函数的功能,并返回了两个参数的和。 需要注意的是,函数的声明和定义通常是分开的。在调用函数之前,必须先声明它,然后才能在需要的地方定义它。
如下;
#include <stdio.h>
//函数的定义
void success()
{
printf("we will succeed");
}
int main() {
success(); //调用success()
return 0;
}
void success() { printf("we will succeed"); } 函数的定义
注:如果函数的定义放在main函数的下面,需要在main函数提前声明,避免编译器出现警告!
#include <stdio.h>
void success();
int main() {
success(); //调用success()
return 0;
}
//函数的定义
void success()
{
printf("we will succeed");
}
void success();对函数声明
两者输出结果:
1.2函数的嵌套调用
新建strive.c 和 strive.h
在头文件中定义 #include <stdio.h> 原因是main.c和strive.c 同时使用到了strive.h 这样在多个使用同一个头文件时,更加的方便。
可直接在main.c 和strive.c 直接调用strive.h
疑问点:为什么这里的编译预处理命令(#include "strive.h")为什么是"" 而不是<>???
<>的意思是在c语言的系统文件中寻找,找不到报错
而" "表示先从自己的目录寻找后在系统文件寻找,找不到报错
2.在头文件中声明void success()
我们可以看出下方代码不用在main上方提前声明 也不会出现编译器警告现象!
原因是 我们在头文件中声明了,之后在strive.c中添加了编译预处理命令(#include "strive.h")表明已经声明。
运行结果:
在头文件(strive.h)中 添加
int strive_succeed(int i); //对strive_succed函数声明,有形参有返回值 返回值类型是int
之后在strive.c里面进行嵌套调用
//
// Created by HP on 2023/9/27.
//
#include "strive.h"
int strive_succeed(int i)
{
printf("*******************\n");
printf("strive_succeed %d\n",i);
}
//在这里调用 strive_succeed 就是嵌套调用
void success()
{
printf("we will succeed\n");
strive_succeed(6);
}
void success() { printf("we will succeed\n"); strive_succeed(6); } 这里就是嵌套调用
嵌套调用图解: main调用了strive.c 和strivr.h strive.c是调用了strive.h中的语句
1.3 C语言的编译和执行特点:
1. 分别编译:多个C文件可以分别进行编译,提高编译效率。由于是分别编译,每个C文件都可以独立进行编译,而不会影响其他文件。
2. 头文件拷贝:头文件包含在每个C文件中,在编译时直接拷贝到每个C文件中。头文件不参与编译,只是包含在C文件中。
3. 执行过程:程序从main函数开始执行,当main函数结束时,整个程序也就结束了。
1.4 嵌套调用定义
嵌套调用是程序中一个函数调用另一个函数的情况。在这种情况下,被调用的函数可以再调用其他函数,形成一层一层的调用关系,就像穿袜子一样,一层一层地套上。这种调用方式在程序中是允许的,但要注意,函数之间是互相平行的,不能在一个函数内部再定义另一个函数,这是不允许的。
1.5 函数声明与定义的差异
函数的定义是指函数功能的确立,包括函数名、函数值类型(返回值类型)、形参及其类型和函数体。(下面对函数定义做出解释)例如,在C语言中,函数定义需要明确函数的功能、输入参数类型、返回值类型以及函数体中的具体实现。
差异:而函数声明则是不需要包含函数体的。它主要声明了函数返回值类型、函数名以及形参及其类型。在C语言中,函数声明只需要说明函数的返回值类型、函数名以及输入参数的类型即可,不需要写出函数的具体实现代码。 总之,函数声明与定义的主要区别在于是否包含函数体。函数定义包含了函数体,而函数声明则只是声明的函数的返回值类型、函数名以及输入参数的类型。

int(函数值类型) strive_succeed(函数名)(int(形参的类型) i)
{ } 形参体
1.6 什么是无参函数有参函数?
无参函数和有参函数是函数定义中的两种基本类型,它们的主要区别在于函数是否接受参数。
无参函数是指在主调函数调用被调函数时,主调函数不向被调函数传递数据。无参函数通常用于执行特定的任务,如输出信息、获取系统时间等,也可以有返回值,但一般以没有返回值居多。无参函数的调用方式相对简单,只需要函数名和一对圆括号即可。

void sayHello()
{
printf("Hello World!\n");
}
有参函数则是指在主调函数调用被调函数时,主调函数通过参数向被调函数传递数据。在一般情况下,有参函数在执行被调函数时会得到一个值并返回给主调函数使用。有参函数的使用需要注意在定义函数时,必须要指定形参的类型,同时实参与形参的类型要相同或赋值兼容。有参函数的调用方式需要在函数名后面的圆括号内传递参数,参数可以是常量、变量或表达式。
举个栗子:
int search(int arr[], int n, int key)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == key)
{
return i; //找到的元素在数组中的索引
}
}
return -1; // 如果没有找到元素则返回-1表示失败
}
2.函数递归调用
2.1为什么要使用递归?
使用递归的意义在于降低算法的难度,使得初学者也能够理解和实现。在快速排序等算法中,使用递归可以让代码更加简洁易懂。递归能够将问题分解成更小的子问题,降低问题的复杂度,使算法的实现更加直观和易于理解。
2.2递归例题演示(经典楼梯问题)
假如有n给台阶,一次只能上1个或者2个台阶,走到第n个台阶有几种走法?代码如下:
#include <stdio.h>
int main() {
int n;
scanf("%d",&n);
printf("step(%d)=%d",n,step(n));
return 0;
}
int step(int n){
if(2==n || 1==n)
{
return n;
}
return step(n-2)+step(n-1);
}
解析代码:n表示楼梯数 step表示一次走几步 #include <stdio.h> int main() { int n; scanf("%d",&n); //scanf输入n(楼梯数) printf("step(%d)=%d",n,step(n)); //输出 return 0; } int step(int n){ //设置类型 if(2==n || 1==n) //当n等于2或1时 输出n的值 即n=1 n=2 { return n; //输出n值 } return step(n-2)+step(n-1); //题目规则一次只能走一步或两步 }
2.3递归楼梯问题的核心(同递归的核心)
找公式
具体来说,要找到给定台阶数n和前一个台阶数n-1之间的关系。在这个例子中,通过递归的方式,将问题不断拆分成更小的子问题,直到到达基础情况(也就是结束条件)。 在实现递归时,首先要确定递归公式,即n*f(n-1)的关系。然后使用这个公式来实现递归函数。当传递到结束条件时,递归结束,然后返回结果。
3.全局变量和局部变量
3.1全局变量
3.1.1全局变量的定义
全局变量是在函数外部定义的变量,也被称为全称变量,它们在整个程序中都有效,从定义位置到文件尾部有效。
全局变量代码演示:通过代码可以看出succe_c和main函数同时使用了i 并成功运行了i的结果
#include <stdio.h>
int i=10; //i是全局变量
void succeed_c(int c)
{
printf("succeed_c=%d\n",i);
}
int main() {
printf("main=%d\n",i);
succeed_c(4); //调用succeed_c
return 0;
}
运行结果:
3.1.2不建议使用全局变量的原因
1. 全局变量在程序执行过程中会一直占用内存单元,不会释放掉。这会导致内存的浪费,特别是在程序执行结束后,这些全局变量仍然会占用内存空间。
2. 当局部变量与全局变量重名时,编译器会采用就近原则(看下图),即访问和修改的是局部变量的值,而非全局变量的值。这可能会导致程序的逻辑出错,影响代码的正确性。 因此,为了提高程序的可读性和可维护性,避免不必要的错误和内存浪费,不建议使用全局变量。
main函数下光标处 的int i=5根据就近原则 使得结果输出main=5
3.2局部变量
3.2.1局部变量的定义
局部变量是在函数内部定义的变量,也被称为内部变量,它们只在其所在的函数内有效。这些变量只在该函数内部使用,在其他函数或主函数中无法直接使用。 形参也是局部变量的一种,它们在函数内部定义,并且只在该函数内部使用。形参的作用范围仅限于其所在的函数中,在函数外部无法直接使用。 需要注意的是,局部变量名不能和形参同名,否则会导致编译错误。同时,不同函数中可以定义相同的变量,但这些变量的作用范围仅限于各自所在的函数中,不会互相干扰。
3.2.2局部变量常见错误
1.局部变量时只能在同给括号使用,否则会出现报错!!!
这里只是举了一个基本例子还有比如for(),while()循环在()内命名的,在括号外不能使用。
2.形参也可做为局部变量,同就近原则。
3.2.3实参和形参是什么?他们的区别是什么?
1.实参是调用函数时提供的参数,用于在函数内部使用。实参可以是常量、变量、表达式等。
2.形参是定义函数时声明的参数,用于接收调用函数时传递的参数。形参必须指定类型,并且可以有多个。在函数内部,形参可以作为局部变量使用,也可以作为返回值返回给调用函数。 总之,实参和形参的主要区别在于它们的作用时间、作用范围和传递方式不同。
3.3全局变量和局部变量的区别
全局变量和局部变量的区别主要体现在作用域和存储位置。
全局变量在整个程序中都可用,而局部变量仅在定义它的函数或循环等范围内可用。全局变量存储在全局数据区中,而局部变量存储在栈区。编译器在设计时规定,如果局部变量与全局变量重名,那么将采用就近原则,即实际获取和修改的都是局部变量的值。因此,不建议使用全局变量,以避免可能出现的逻辑错误。
(以上均个人理解)