程序设计笔记循环和函数
函数
形参😦调用结束会释放内存
在函数定义中,形参(formal parameter)是指函数签名中声明的变量,
用于接收函数调用时传入的实参(actual parameter)。
形参只在函数内部有效,其作用域只限于函数体内。
形参的作用是将函数的输入参数传递给函数体内的代码进行处理,从而实现函数的功能。函数可以有多个形参,每个形参可以有不同的类型和默认值。
在函数调用时,需要提供与函数签名中形参类型和数量相匹配的实参,实参的值将被传递给对应的形参。
例如,以下代码定义了一个名为add
的函数,它接受两个整数作为参数,并返回它们的和:
public static int add(int a, int b) {
return a + b;
}
在这个函数中,a
和b
是形参,它们的类型为int
。当函数被调用时,需要传递两个int
类型的实参,例如:
int x = 1;
int y = 2;
int z = add(x, y); // z的值为3
在这个例子中,x
和y
是实参,它们的值分别为1和2。当函数add
被调用时,实参1和2会被分别传递给形参a
和b
,函数的返回值为3,最后将返回值赋给变量z
。
实参😃就是有定义值的函数
在函数调用中,实参(actual parameter)是指传递给函数的值或变量。实参是函数调用中的实际输入值,它们的值将被传递给函数的形参进行处理。
例如,以下代码定义了一个名为add
的函数,它接受两个整数作为参数,并返回它们的和:
public static int add(int a, int b) {
return a + b;
}
在这个函数中,a
和b
是形参,它们的类型为int
。当函数被调用时,需要传递两个int
类型的实参,例如:
int x = 1;
int y = 2;
int z = add(x, y); // z的值为3
在这个例子中,x
和y
是实参,它们的值分别为1和2。当函数add
被调用时,实参1和2会被分别传递给形参a
和b
,函数的返回值为3,最后将返回值赋给变量z
。
实参可以是常量、变量、表达式或函数调用的结果,它们的类型和数量必须与函数定义中的形参类型和数量相匹配。
函数声明种类
int add(int a,int b);
int add(int ,int ); ???
声明函数调用类型就可以
短路法:
像这样
for(i=2;judge&&i<k;i++)
在逻辑运算中,短路(short-circuit)指的是在进行逻辑运算时,根据前面的条件判断结果,决定是否继续执行后面的条件判断。
在Java中,逻辑运算符&&
(逻辑与)和||
(逻辑或)都具有短路的特性。
对于逻辑与运算符&&
,如果第一个条件为false
,则不会执行后面的条件判断,因为无论后面的条件是true
还是false
,整个逻辑表达式的结果都将是false
。这种情况下,后面的条件判断将被短路,不会执行。
对于逻辑或运算符||
,如果第一个条件为true
,则不会执行后面的条件判断,因为无论后面的条件是true
还是false
,整个逻辑表达式的结果都将是true
。这种情况下,后面的条件判断将被短路,不会执行。
短路的特性可以用于提高代码的效率和减少不必要的计算。例如,当我们在进行条件判断时,如果某个条件的计算代价较高,而前面的条件已经可以确定整个逻辑表达式的结果时,可以使用短路运算符来避免不必要的计算。
以下是一个简单的示例,展示了逻辑运算符的短路特性:
int a = 5;
int b = 0;
if (b != 0 && a / b > 2) {
// 这里的条件判断不会执行,因为b != 0为false,短路发生
System.out.println("条件满足");
}
if (b == 0 || a / b > 2) {
// 这里的条件判断会执行,因为b == 0为true,短路发生
System.out.println("条件满足");
}
在第一个if
语句中,由于b != 0
为false
,短路发生,后面的条件判断a / b > 2
不会执行,因此不会抛出除以零的异常。
在第二个if
语句中,由于b == 0
为true
,短路发生,后面的条件判断a / b > 2
不会执行,因此也不会抛出除以零的异常。
递归
递归(recursion)是指在一个函数的定义中调用自身的过程。递归是一种常见的解决问题的方法,特别适用于问题可以被分解成相同类型的子问题的情况。
在递归过程中,函数会通过不断调用自身来解决问题,每次调用时传入不同的参数。递归函数必须包含一个或多个终止条件,用于结束递归过程,否则递归将无限进行下去。
递归的思想可以用一个简单的例子来说明:计算一个正整数的阶乘。阶乘的定义是n! = n * (n-1) * (n-2) * … * 1。可以使用递归来计算阶乘,如下所示:
public static int factorial(int n) {
if (n == 0) {
return 1; // 终止条件:0的阶乘为1
} else {
return n * factorial(n - 1); // 递归调用:n的阶乘为n乘以(n-1)的阶乘
}
}
在这个例子中,函数factorial
接受一个整数参数n
,并返回n
的阶乘。当n
为0时,函数返回1,这是递归的终止条件。当n
不为0时,函数通过调用自身来计算n
的阶乘,即n
乘以(n-1)
的阶乘。这样,问题就被分解成了更小的子问题,直到达到终止条件。
例如,计算5的阶乘可以使用递归函数factorial(5)
,它会调用factorial(4)
,然后factorial(3)
,以此类推,直到factorial(0)
,最终得到结果120。
递归可以使代码更简洁、可读性更好,但需要注意递归深度过大可能导致栈溢出的问题,而且在某些情况下,迭代(循环)可能比递归更高效。因此,在使用递归解决问题时,需要仔细考虑终止条件和递归调用的条件,确保递归过程能够正确结束。
递归分类
直接递归 :A->A
直接递归(direct recursion)是指一个函数在其定义中直接调用自身的递归形式。在直接递归中,函数在执行过程中会多次调用自身,直到满足某个终止条件才停止递归。
以下是一个简单的示例,展示了直接递归的使用:
public static void countDown(int n) {
if (n == 0) {
System.out.println("结束");
} else {
System.out.println(n);
countDown(n - 1); // 直接调用自身
}
}
在这个例子中,函数countDown
接受一个整数参数n
,并在每次调用时打印出当前的值。当n
为0时,函数打印出"结束",这是递归的终止条件。当n
不为0时,函数打印出当前的值,并通过直接调用countDown(n - 1)
来递归地继续倒计时。
例如,调用countDown(5)
会输出以下结果:
5
4
3
2
1
结束
在每次递归调用中,函数的参数值不断减小,直到达到终止条件。这样,问题就被分解成了更小的子问题,直到最终结束递归。
需要注意的是,在使用直接递归时,需要确保递归调用能够最终达到终止条件,否则递归将无限进行下去,导致栈溢出的问题。此外,递归的性能可能不如迭代(循环),因此在某些情况下,可以考虑使用迭代来替代递归。
下面是一个使用C++实现直接递归的示例代码:
#include <iostream>
void countDown(int n) {
if (n == 0) {
std::cout << "结束" << std::endl;
} else {
std::cout << n << std::endl;
countDown(n - 1); // 直接调用自身
}
}
int main() {
countDown(5);
return 0;
}
在这个例子中,countDown
函数接受一个整数参数n
,并在每次调用时打印出当前的值。当n
为0时,函数打印出"结束",这是递归的终止条件。当n
不为0时,函数打印出当前的值,并通过直接调用countDown(n - 1)
来递归地继续倒计时。
在main
函数中,我们调用countDown(5)
来开始倒计时。
运行上述代码,会输出以下结果:
5
4
3
2
1
结束
这个C++实现与之前提到的Java实现非常相似。C++中使用std::cout
代替了Java中的System.out.println
来打印输出。此外,C++中使用std::endl
代替了Java中的换行符\n
来结束每行输出。
需要注意的是,无论是使用Java还是C++,直接递归的原理和使用方法都是相同的。只是在具体的语法和语言特性上会有些许差异。
间接递归:A->B->A
间接递归(indirect recursion)是指多个函数之间通过调用其他函数来实现递归的过程。
在间接递归中,函数之间形成一个循环调用的链条,使得递归能够在这些函数之间进行。
以下是一个示例,展示了间接递归的使用:
void functionA(int n);
void functionB(int n) {
if (n > 0) {
std::cout << "B: " << n << std::endl;
functionA(n - 1); // 间接调用functionA
}
}
void functionA(int n) {
if (n > 0) {
std::cout << "A: " << n << std::endl;
functionB(n - 1); // 间接调用functionB
}
}
int main() {
functionA(5);
return 0;
}
在这个例子中,我们有两个函数functionA
和functionB
,它们之间通过互相调用来实现间接递归。当n
大于0时,functionA
会打印出"A: "和当前的值,并通过调用functionB(n - 1)
来间接调用functionB
。同样地,当n
大于0时,functionB
会打印出"B: "和当前的值,并通过调用functionA(n - 1)
来间接调用functionA
。
在main
函数中,我们调用functionA(5)
来开始间接递归。
运行上述代码,会输出以下结果:
A: 5
B: 4
A: 3
B: 2
A: 1
在这个例子中,functionA
和functionB
形成了一个循环调用的链条,使得递归能够在它们之间进行。这种循环调用的链条可以是任意长度的,只要满足递归的条件即可。
需要注意的是,间接递归也需要注意终止条件,以避免无限循环调用导致栈溢出的问题。在上述例子中,终止条件是n
大于0。当n
为0时,递归结束,不再进行调用。
变量的生命周期(函数位置)
可以在main函数外面定义变量吗?\
可以哟!!!
#define 定义常量神器
全局变量
全局变量(global variable)是在程序的任何地方都可以访问的变量,它的作用域(scope)覆盖整个程序。
全局变量与局部变量(local variable)相对,局部变量只在定义它的特定代码块内可见。
在C++中,可以在函数外部定义全局变量。全局变量可以在程序的任何地方被访问和修改,包括函数内部和函数之外。
以下是一个示例,展示了全局变量的使用:
#include <iostream>
int globalVariable = 10; // 全局变量
void function() {
std::cout << "全局变量的值为: " << globalVariable << std::endl;
}
int main() {
std::cout << "全局变量的初始值为: " << globalVariable << std::endl;
globalVariable = 20; // 修改全局变量的值
function(); // 调用函数
return 0;
}
在这个例子中,我们在函数外部定义了一个全局变量globalVariable
并初始化为10。在main
函数中,我们首先打印出全局变量的初始值,然后修改全局变量的值为20。接着,我们调用function
函数,该函数打印出全局变量的值。
运行上述代码,会输出以下结果:
全局变量的初始值为: 10
全局变量的值为: 20
可以看到,全局变量的值可以在函数内部和函数之外进行访问和修改。这使得全局变量在整个程序中共享数据变得方便,但也需要注意全局变量的使用。过多地使用全局变量可能导致代码的可读性和可维护性下降,因为全局变量的作用域很广,很难跟踪和控制它们的修改。因此,在编写程序时应慎重使用全局变量,并考虑使用局部变量和函数参数来限制变量的作用范围。
局部变量
局部变量(local variable)是在特定代码块内定义的变量,它的作用域仅限于该代码块内部。局部变量与全局变量(global variable)相对,全局变量可以在整个程序中访问,而局部变量只能在定义它的代码块内部访问。
在C++中,可以在函数、循环、条件语句等代码块内定义局部变量。局部变量在其所在的代码块执行期间存在,并在代码块执行结束后被销毁。
以下是一个示例,展示了局部变量的使用:
#include <iostream>
void function() {
int localVariable = 10; // 局部变量
std::cout << "局部变量的值为: " << localVariable << std::endl;
}
int main() {
int localVariable = 5; // 局部变量
std::cout << "局部变量的值为: " << localVariable << std::endl;
function(); // 调用函数
return 0;
}
在这个例子中,我们在main
函数内部和function
函数内部分别定义了一个名为localVariable
的局部变量,并分别初始化为5和10。在main
函数中,我们首先打印出main
函数内部的局部变量的值,然后调用function
函数。在function
函数内部,我们打印出function
函数内部的局部变量的值。
运行上述代码,会输出以下结果:
局部变量的值为: 5
局部变量的值为: 10
可以看到,局部变量的作用域仅限于定义它的代码块内部。在函数内部定义的局部变量只能在该函数内部访问,而在循环或条件语句内部定义的局部变量只能在该循环或条件语句内部访问。这种作用域的限制使得局部变量具有更小的可见范围,有助于提高代码的可读性和可维护性。此外,局部变量的生命周期也比全局变量短,可以更有效地利用内存空间。
块局部变量
块局部变量(block local variable)是在代码块内部定义的局部变量,它的作用域仅限于该代码块内部。块局部变量与函数内部定义的局部变量类似,但其作用范围更小,仅限于定义它的代码块。
在C++中,可以在任何代码块内部定义块局部变量,包括函数、循环、条件语句等。块局部变量在其所在的代码块执行期间存在,并在代码块执行结束后被销毁。
以下是一个示例,展示了块局部变量的使用:
#include <iostream>
void function() {
int globalVariable = 10; // 全局变量
{
int blockLocalVariable = 5; // 块局部变量
std::cout << "块局部变量的值为: " << blockLocalVariable << std::endl;
std::cout << "全局变量的值为: " << globalVariable << std::endl;
}
// 在此处无法访问块局部变量blockLocalVariable
// 在此处仍然可以访问全局变量globalVariable
std::cout << "全局变量的值为: " << globalVariable << std::endl;
}
int main() {
function(); // 调用函数
return 0;
}
在这个例子中,我们在function
函数内部的代码块中定义了一个名为blockLocalVariable
的块局部变量,并初始化为5。在这个代码块中,我们可以访问块局部变量和函数内部定义的全局变量globalVariable
。但当代码块结束后,块局部变量blockLocalVariable
就会被销毁,无法在代码块外部访问。
运行上述代码,会输出以下结果:
块局部变量的值为: 5
全局变量的值为: 10
全局变量的值为: 10
可以看到,块局部变量的作用范围仅限于定义它的代码块内部。在代码块内部定义的块局部变量只能在该代码块内部访问,而在代码块外部无法访问。块局部变量的作用范围更小,有助于提高代码的可读性和可维护性,并且可以更有效地利用内存空间。
变量范围在内{ ... }
变量类型
在C++中,变量可以分为以下几种类型:
-
基本数据类型(Primitive Data Types):包括整型、浮点型、字符型和布尔型等。例如,
int
表示整数类型,float
表示单精度浮点数类型,char
表示字符类型,bool
表示布尔类型。 -
数组(Array):是一种可以存储多个相同类型元素的数据结构。数组的元素可以通过索引访问,索引从0开始。例如,
int numbers[5]
定义了一个包含5个整数的数组。 -
字符串(String):是一种表示文本的数据类型,由一系列字符组成。在C++中,字符串可以使用字符数组或
std::string
类来表示和操作。 -
结构体(Struct):是一种自定义的数据类型,可以包含多个不同类型的成员变量。结构体可以用来组织和存储相关的数据。
-
枚举(Enumeration):是一种自定义的数据类型,用于定义一组具名的常量值。枚举类型可以用于表示一组相关的选项或状态。
-
指针(Pointer):是一种特殊的数据类型,用于存储变量的内存地址。指针可以用来间接访问和修改变量的值,还可以用于动态内存分配和函数参数传递等。
-
引用(Reference):是一种别名,用于为变量提供一个替代名称。引用可以用来简化变量的使用和传递,但不能改变引用的目标。
-
类(Class):是一种自定义的数据类型,用于封装数据和相关的操作。类可以包含成员变量和成员函数,用于描述对象的属性和行为。
以上是C++中常见的变量类型。不同的变量类型有不同的特点和用途,选择适合的变量类型可以提高代码的可读性和可维护性,并且能够更有效地利用内存空间。
auto 自动变量
自动变量(auto variable)是指在程序中声明的变量,其生命周期与其所在的代码块或函数的执行周期相对应。当代码块或函数执行完毕时,自动变量会被自动销毁。
auto
是C++11引入的关键字,用于声明自动变量。自动变量是指编译器根据变量初始化表达式的类型推断出变量的类型,而无需显式指定变量类型。
使用auto
关键字可以简化变量的声明,尤其是在使用复杂类型或模板类型时。通过使用auto
,编译器会根据初始化表达式的类型自动推断变量的类型,从而减少了手动指定类型的工作量。
下面是一个使用auto
关键字声明自动变量的示例:
auto x = 10; // 推断x的类型为int
auto y = 3.14; // 推断y的类型为double
auto z = "Hello"; // 推断z的类型为const char*
在上述示例中,变量x
的类型被推断为int
,变量y
的类型被推断为double
,变量z
的类型被推断为const char*
。
需要注意的是,auto
关键字只能用于自动变量的声明,不能用于函数参数、类成员变量和全局变量的声明。此外,使用auto
关键字声明的变量必须进行初始化,以便编译器能够推断出变量的类型。
使用auto
关键字可以提高代码的可读性和可维护性,特别是在处理复杂类型和模板类型时。然而,过度使用auto
关键字可能会降低代码的可读性,因此需要在适当的情况下使用。
在C和C++中,当我们声明一个变量而没有显式指定其存储类别时,默认情况下该变量被认为是自动变量。可以使用关键字"auto"来显式声明自动变量,不过这是可选的,因为它是默认的存储类别。
以下是自动变量的一些特点:
- 自动变量的作用域限定在其声明所在的代码块或函数内部。
- 自动变量在每次进入其所在的代码块或函数时被创建,并在离开时被销毁。
- 自动变量的初始值通常是未定义的(垃圾值),除非显式地进行初始化。
- 自动变量在每次执行其所在的代码块或函数时都会重新创建,因此其值在不同的执行周期中是独立的。
- 自动变量存储在栈上,通过栈指针(stack pointer)进行管理。
需要注意的是,随着C++的发展,"auto"关键字的用法已经改变,现在它通常用于类型推导,而不是用来声明自动变量。在新的C++标准中,可以使用"auto"来让编译器推导变量的类型。所以,在现代C++中,我们不常使用"auto"关键字来声明自动变量,而是直接声明变量,由编译器根据上下文进行类型推导。
静态变量
静态变量(static variable)是一种存储类别,static 执行完后会保留到内存中再遇到时会跳过 ,用于在程序执行期间保持变量的持久性。在C语言和C++中,静态变量具有以下特点:
-
生命周期:静态变量的生命周期延长到整个程序的执行周期。它在程序开始运行时被创建,在程序结束时才被销毁,而不像自动变量那样在作用域结束时销毁。
-
作用域:静态变量可以具有局部作用域或全局作用域。在函数内部声明的静态变量称为静态局部变量,仅在所在函数内可见。而在函数外部声明的静态变量称为静态全局变量,仅在当前文件内可见。
-
初始化:静态变量通常具有静态初始化,在首次访问之前会被初始化为默认值。对于静态局部变量,默认初始化为0或NULL。静态全局变量如果没有显式初始化,编译器会将其初始化为0或者与全局变量相同的初始值。
-
存储位置:静态变量的存储位置通常是在全局数据区或静态数据区。静态局部变量存储在全局数据区的静态链表上,并且只能通过函数名和变量名进行访问。静态全局变量直接存储在全局数据区。
-
持久性:静态变量的持久性使得它们在函数调用间保持其值。无论函数被调用多少次,静态变量都会保持其值不变,直到程序结束。
静态变量的使用场景包括:
- 在函数内部使用静态局部变量,可以实现在函数调用间共享数据,并保持数据的持久性。
- 在多个函数之间共享数据时,可以使用静态全局变量,以避免使用全局变量对其他文件可见。
需要注意的是,在多线程环境下,访问静态变量可能会导致竞态条件和线程安全问题。为了保证线程安全,可以使用互斥锁或其他同步机制来对静态变量进行保护。
详细解释:
在函数内部声明的静态变量被称为静态局部变量。静态局部变量在函数第一次被调用时初始化,并且只在程序执行期间保持其值不变。与普通局部变量不同,静态局部变量的生命周期延长到整个程序的执行期间,而不是仅限于函数的执行范围。静态局部变量的作用域仍然限于声明它的函数内部。
以下是一个使用静态局部变量的示例:
#include <iostream>
void foo() {
static int count = 0; // 静态局部变量
count++;
std::cout << "Count: " << count << std::endl;
}
int main() {
foo(); // 输出 Count: 1
foo(); // 输出 Count: 2
foo(); // 输出 Count: 3
return 0;
}
在上述示例中,函数foo()
中的静态局部变量count
在每次函数调用时都会增加其值,并保持在整个程序执行期间。因此,每次调用foo()
时,都会输出递增的计数值。
在全局作用域或类中声明的静态变量被称为静态全局变量或静态成员变量。静态全局变量在整个程序的执行期间保持其值不变,而静态成员变量在类的所有对象之间共享。
静态变量的主要特点是其值在程序执行期间保持不变,可以用于记录某个值在程序的不同部分之间共享或保持状态。静态变量的使用需要谨慎,因为它们的生命周期可能会导致一些潜在的问题,如竞态条件和不可预测的行为。
extern 外部声明,即在函数体外部声明的变量,在内部也可以使用
ok这就是函数相关的内容了。
本文作者:2c237c6
本文链接:https://www.cnblogs.com/27dCnc/p/18568689
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步