本文主要是介绍GESP四级 - 第一章 - 第2节 - 形参与实参,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. 形参与实参
1.1 什么是形参
形参(Formal Parameter)是在函数定义中声明的变量,用于接收调用函数时传递的实际参数值。形参定义了函数可以接受的数据类型和数量,它们在函数被调用时才会被创建,并在函数执行完毕后被销毁。
形参的声明语法如下:
返回值类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...) {// 函数体
}
例如,以下函数有两个形参 a
和 b
,它们的类型都是 int
:
int add(int a, int b) {return a + b;
}
在函数定义中,形参的名称可以自由选择,但应该具有描述性,以便于理解其含义。形参的类型可以是任何有效的 C++ 数据类型,包括内置类型(如 int
、double
、char
等)和用户自定义类型(如结构体、类等)。
形参在函数内部作为局部变量使用,它们的初始值由调用函数时传递的实际参数确定。在函数执行期间,可以像使用普通变量一样使用形参,对其进行读取、修改等操作。
需要注意的是,形参是函数定义的一部分,它们只在函数内部可见,而不能在函数外部访问。此外,形参是按值传递的,即在函数调用时,实际参数的值被复制给形参,函数内部对形参的修改不会影响实际参数。如果需要在函数内部修改实际参数的值,可以使用引用传递或指针传递。
总之,形参是函数定义中的一种特殊变量,用于接收调用函数时传递的实际参数值,并在函数内部使用。理解形参的概念和使用对于编写和调用函数非常重要。
1.2 什么是实参
实参(Actual Parameter)是在调用函数时传递给函数的实际值或表达式,它们对应于函数定义中的形参。实参提供了函数执行所需的具体数据,它们可以是变量、常量、表达式或其他函数的返回值。
在函数调用时,实参的值会被复制或传递给相应的形参,函数内部通过形参来访问和操作这些值。实参的数量、类型和顺序必须与函数定义中的形参相匹配,否则会导致编译错误或运行时错误。
函数调用时实参的传递语法如下:
函数名(实参1, 实参2, ...);
例如,对于以下函数定义:
int add(int a, int b) {return a + b;
}
我们可以使用以下代码调用该函数并传递实参:
int result = add(10, 20);
在这个例子中,10
和 20
是传递给 add
函数的实参,它们分别对应于函数定义中的形参 a
和 b
。函数内部通过 a
和 b
来访问实参的值,并执行相应的操作。
实参可以是各种类型的值或表达式,包括:
1 . 字面量:如整数、浮点数、字符等。
int result = add(10, 20);
2 . 变量:传递变量的值给函数。
int x = 10, y = 20;
int result = add(x, y);
3 . 表达式:传递表达式的计算结果给函数。
int result = add(5 + 3, 2 * 4);
4 . 函数调用:传递其他函数的返回值给函数。
int square(int x) {return x * x;
}
int result = add(square(3), square(4));
实参是函数调用的一部分,它们提供了函数执行所需的具体数据。通过传递适当的实参,我们可以控制函数的行为和结果。理解实参的概念和使用对于正确调用函数和传递数据非常重要。
1.3 形参与实参的关系
形参和实参是函数定义和函数调用中的两个重要概念,它们之间存在着密切的关系。下面我们来详细探讨形参和实参之间的关系:
1 . 对应关系:
- 函数调用时,实参的数量、类型和顺序必须与函数定义中的形参相匹配。
- 每个实参对应一个形参,按照顺序一一对应。
- 实参的类型必须与对应的形参类型兼容,或者能够隐式转换为形参的类型。
2 . 值传递:
- 默认情况下,实参是按值传递给形参的。
- 在函数调用时,实参的值被复制给对应的形参,函数内部操作的是形参的副本。
- 函数内部对形参的修改不会影响实参的值。
3 . 参数匹配:
- 实参的类型必须与对应的形参类型相同或兼容。
- 如果实参的类型与形参的类型不完全匹配,编译器会尝试进行隐式类型转换。
- 如果无法进行隐式类型转换,或者转换可能导致数据丢失,编译器会报错。
4 . 参数数量:
- 实参的数量必须与函数定义中的形参数量相同。
- 如果实参的数量多于或少于形参的数量,编译器会报错。
5 . 参数顺序:
- 实参的顺序必须与形参的顺序相同。
- 实参按照从左到右的顺序依次对应形参。
6 . 默认参数:
- 在 C++中,可以为形参指定默认值。
- 如果在函数调用时省略了某个实参,对应的形参将使用默认值。
- 默认参数必须从右向左连续指定,不能跳过中间的参数。
7 . 引用传递和指针传递:
- 除了按值传递,C++还支持按引用传递和按指针传递。
- 按引用传递时,形参作为实参的别名,函数内部对形参的修改会影响实参的值。
- 按指针传递时,形参是指向实参的指针,函数内部通过指针可以修改实参的值。
下面是一个示例,演示了形参和实参的关系:
// 函数定义
int add(int a, int b) {return a + b;
}// 函数调用
int main() {int x = 10, y = 20;int result = add(x, y); // 实参 x 和 y 对应形参 a 和 bcout << "Result: " << result << endl;return 0;
}
在这个例子中,add
函数有两个形参a
和b
,在main
函数中调用add
函数时,实参x
和y
分别对应形参a
和b
,并将它们的值传递给形参。函数内部通过形参a
和b
来访问实参的值,并执行相应的操作。
理解形参和实参的关系对于正确定义和调用函数非常重要。通过匹配实参和形参,我们可以将数据传递给函数,控制函数的行为和结果。同时,也要注意参数的类型、数量和顺序,以及传递方式的选择,以确保函数的正确性和可读性。
1.4 按值传递
按值传递是函数参数传递的默认方式,也是最常见的参数传递方式之一。在按值传递中,实参的值被复制给函数的形参,函数内部操作的是形参的副本,而不是实参本身。
按值传递的特点如下:
- 实参的值被复制给形参,函数内部使用的是形参的副本。
- 函数内部对形参的修改不会影响实参的值。
- 实参和形参是独立的存储空间,它们之间没有直接的关联。
按值传递的语法如下:
返回值类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...) {// 函数体
}
下面是一个按值传递的示例:
void swapValues(int a, int b) {int temp = a;a = b;b = temp;cout << "Inside function: a = " << a << ", b = " << b << endl;
}int main() {int x = 10, y = 20;cout << "Before function call: x = " << x << ", y = " << y << endl;swapValues(x, y);cout << "After function call: x = " << x << ", y = " << y << endl;return 0;
}
输出结果:
Before function call: x = 10, y = 20
Inside function: a = 20, b = 10
After function call: x = 10, y = 20
在这个示例中,swapValues
函数接受两个整型参数a
和b
,函数内部交换了a
和b
的值。但是,由于是按值传递,函数内部操作的是a
和b
的副本,而不是实参x
和y
。因此,在函数调用后,实参x
和y
的值并没有发生改变。
按值传递的优点是简单明了,函数内部对形参的修改不会影响实参,提供了一定的安全性和隔离性。但是,当传递大型对象或数组时,按值传递会导致性能开销,因为需要复制整个对象或数组。在这种情况下,可以考虑使用引用传递或指针传递来提高效率。
总之,按值传递是函数参数传递的一种基本方式,它将实参的值复制给形参,函数内部操作的是形参的副本。理解按值传递的特点和适用场景,可以帮助我们合理选择参数传递方式,编写正确高效的函数。
1.5 按引用传递
按引用传递是 C++ 中另一种常用的参数传递方式,它允许函数直接访问和修改实参的值。在按引用传递中,形参作为实参的别名(引用),对形参的任何操作都会直接影响实参。
按引用传递的特点如下:
- 形参是实参的引用(别名),它们指向同一个内存位置。
- 通过形参可以直接访问和修改实参的值。
- 函数内部对形参的修改会影响实参的值。
- 按引用传递可以避免大型对象或数组的复制,提高性能。
按引用传递的语法如下:
返回值类型 函数名(参数类型1& 参数名1, 参数类型2& 参数名2, ...) {// 函数体
}
注意,在形参的类型后面添加了 &
符号,表示该形参是一个引用。
下面是一个按引用传递的示例:
void swapValues(int& a, int& b) {int temp = a;a = b;b = temp;cout << "Inside function: a = " << a << ", b = " << b << endl;
}int main() {int x = 10, y = 20;cout << "Before function call: x = " << x << ", y = " << y << endl;swapValues(x, y);cout << "After function call: x = " << x << ", y = " << y << endl;return 0;
}
输出结果:
Before function call: x = 10, y = 20
Inside function: a = 20, b = 10
After function call: x = 20, y = 10
在这个示例中,swapValues
函数的参数 a
和 b
都是引用类型,它们分别绑定到实参 x
和 y
。在函数内部,通过修改 a
和 b
的值,实际上就是直接修改 x
和 y
的值。因此,在函数调用后,实参 x
和 y
的值发生了交换。
按引用传递的优点是可以直接修改实参的值,避免了大型对象或数组的复制,提高了性能。但是,由于函数内部可以修改实参的值,使用时需要格外小心,确保引用参数的使用是安全和正确的。
在使用按引用传递时,需要注意以下几点:
- 引用参数必须是一个左值(可以取地址的表达式),不能是常量或字面量。
- 引用参数的类型必须与实参的类型匹配或兼容。
- 在函数内部,不能将引用参数重新绑定到其他对象上。
总之,按引用传递是 C++ 中一种强大的参数传递方式,它允许函数直接访问和修改实参的值,提高了性能和灵活性。合理使用按引用传递可以使代码更加高效和简洁,但同时也需要注意引用参数的正确性和安全性。
好的,下面是5个按引用传递的正确示例:
好的,以下是按照给定格式的5个按引用传递的示例:
示例1: 交换两个整数的值
#include <iostream>
using namespace std;void swap(int& a, int& b) {int temp = a;a = b;b = temp;
}int main() {int x = 10, y = 20;cout << "交换前: x = " << x << ", y = " << y << endl;swap(x, y);cout << "交换后: x = " << x << ", y = " << y << endl;return 0;
}
示例2: 修改字符串的内容
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;void toUpperCase(string& str) {for (char& c : str) {c = toupper(c);}
}int main() {string message = "Hello, world!";cout << "转换前: " << message << endl;toUpperCase(message);cout << "转换后: " << message << endl;return 0;
}
示例3: 计算数组元素的和
#include <iostream>
using namespace std;void sumArray(int arr[], int size, int& sum) {sum = 0;for (int i = 0; i < size; i++) {sum += arr[i];}
}int main() {int numbers[] = {1, 2, 3, 4, 5};int size = sizeof(numbers) / sizeof(numbers[0]);int sum = 0;sumArray(numbers, size, sum);cout << "数组元素的和: " << sum << endl;return 0;
}
示例4: 修改结构体成员的值
#include <iostream>
#include <string>
using namespace std;struct Person {string name;int age;
};void increaseAge(Person& person) {person.age++;
}int main() {Person john = {"John", 30};cout << "修改前: " << john.name << " 的年龄是 " << john.age << " 岁." << endl;increaseAge(john);cout << "修改后: " << john.name << " 的年龄是 " << john.age << " 岁." << endl;return 0;
}
示例5: 返回多个值
#include <iostream>
using namespace std;void getMinMax(int arr[], int size, int& min, int& max) {min = max = arr[0];for (int i = 1; i < size; i++) {if (arr[i] < min) {min = arr[i];}if (arr[i] > max) {max = arr[i];}}
}int main() {int numbers[] = {10, 5, 8, 20, 3};int size = sizeof(numbers) / sizeof(numbers[0]);int min, max;getMinMax(numbers, size, min, max);cout << "最小值: " << min << endl;cout << "最大值: " << max << endl;return 0;
}
这些示例按照给定的格式展示了按引用传递在不同场景下的应用。每个示例都包含了完整的代码,并使用中文进行了输出和注释。希望这些示例能够清晰地展示按引用传递的用法和效果。
1.6 数组作为函数参数
在 C++ 中,数组可以作为函数的参数进行传递。当数组作为函数参数时,实际上传递的是数组的首地址,而不是整个数组的副本。这意味着在函数内部对数组元素的修改会直接影响原始数组。
将数组作为函数参数传递的语法如下:
返回值类型 函数名(数组类型 数组名[],int 数组大小)
{// 函数体
}
其中,数组类型
是数组元素的类型,数组名
是形参的名称,数组大小
是数组的大小(元素个数)。注意,数组作为函数参数时,不需要指定数组的大小,因为数组大小可以通过另一个参数或其他方式传递。
下面是一个将数组作为函数参数的示例:
示例: 计算数组元素的平均值
#include <iostream>
using namespace std;double calculateAverage(int arr[], int size) {double sum = 0;for (int i = 0; i < size; i++) {sum += arr[i];}return sum / size;
}int main() {int numbers[] = {10, 20, 30, 40, 50};int size = sizeof(numbers) / sizeof(numbers[0]);double average = calculateAverage(numbers, size);cout << "数组元素的平均值: " << average << endl;return 0;
}
在这个示例中,calculateAverage
函数接受一个整型数组arr
和数组的大小size
作为参数。函数内部通过循环遍历数组元素,计算元素的总和,然后除以数组的大小,得到平均值并返回。
在main
函数中,我们定义了一个整型数组numbers
,并使用sizeof
运算符计算数组的大小。然后,将数组numbers
和大小size
作为参数传递给calculateAverage
函数,得到数组元素的平均值,并输出结果。
需要注意的是,当数组作为函数参数传递时,实际上传递的是数组的首地址。因此,在函数内部对数组元素的修改会直接影响原始数组。这种行为称为"按引用传递"。
另外,在函数参数中,我们也可以使用指针来表示数组,语法如下:
返回值类型 函数名(数组类型* 指针名,int 数组大小)
{// 函数体
}
使用指针作为函数参数可以更明确地表示传递的是数组的地址,但功能上与直接使用数组名是等价的。
总之,将数组作为函数参数传递是 C++ 中常见的操作,它允许函数直接访问和修改原始数组的元素。通过将数组的地址传递给函数,可以避免复制整个数组,提高了效率。但同时也需要注意,在函数内部对数组元素的修改会影响原始数组,使用时要谨慎。
示例1: 查找数组中的最大元素
#include <iostream>
using namespace std;int findMax(int arr[], int size) {int max = arr[0];for (int i = 1; i < size; i++) {if (arr[i] > max) {max = arr[i];}}return max;
}int main() {int numbers[] = {10, 5, 8, 20, 3};int size = sizeof(numbers) / sizeof(numbers[0]);int maxElement = findMax(numbers, size);cout << "数组中的最大元素: " << maxElement << endl;return 0;
}
在这个示例中,findMax
函数接受一个整型数组arr
和数组的大小size
作为参数。函数内部通过循环遍历数组元素,找到最大的元素并返回。在main
函数中,将数组numbers
和大小size
传递给findMax
函数,得到数组中的最大元素并输出。
示例2: 反转数组中的元素
#include <iostream>
using namespace std;void reverseArray(int arr[], int size) {int start = 0;int end = size - 1;while (start < end) {int temp = arr[start];arr[start] = arr[end];arr[end] = temp;start++;end--;}
}int main() {int numbers[] = {1, 2, 3, 4, 5};int size = sizeof(numbers) / sizeof(numbers[0]);cout << "反转前: ";for (int i = 0; i < size; i++) {cout << numbers[i] << " ";}cout << endl;reverseArray(numbers, size);cout << "反转后: ";for (int i = 0; i < size; i++) {cout << numbers[i] << " ";}cout << endl;return 0;
}
在这个示例中,reverseArray
函数接受一个整型数组arr
和数组的大小size
作为参数。函数内部使用双指针的方法,从数组的两端开始交换元素,直到指针相遇。在main
函数中,将数组numbers
和大小size
传递给reverseArray
函数,实现数组元素的反转,并输出反转前后的数组。
示例3: 计算数组中正数的个数
#include <iostream>
using namespace std;int countPositives(int arr[], int size) {int count = 0;for (int i = 0; i < size; i++) {if (arr[i] > 0) {count++;}}return count;
}int main() {int numbers[] = {-2, 5, 0, -8, 10, 3};int size = sizeof(numbers) / sizeof(numbers[0]);int positiveCount = countPositives(numbers, size);cout << "数组中正数的个数: " << positiveCount << endl;return 0;
}
在这个示例中,countPositives
函数接受一个整型数组arr
和数组的大小size
作为参数。函数内部通过循环遍历数组元素,统计正数的个数并返回。在main
函数中,将数组numbers
和大小size
传递给countPositives
函数,得到数组中正数的个数并输出。
这些示例展示了将数组作为函数参数的不同应用场景,包括查找最大元素、反转数组和计算正数个数。通过将数组传递给函数,我们可以对数组进行各种操作和计算,使代码更加模块化和可重用。
1.7 指针作为函数参数
在 C++ 中,指针也可以作为函数的参数进行传递。通过将指针传递给函数,我们可以在函数内部直接访问和修改指针所指向的内存位置的值。这提供了一种高效且灵活的方式来操作数据。
将指针作为函数参数传递的语法如下:
返回值类型 函数名(指针类型* 指针名)
{// 函数体
}
其中,指针类型
是指针所指向的数据类型,指针名
是形参的名称。
下面是一个将指针作为函数参数的示例:
示例1: 交换两个整数的值
#include <iostream>
using namespace std;void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 10, y = 20;cout << "交换前: x = " << x << ", y = " << y << endl;swap(&x, &y);cout << "交换后: x = " << x << ", y = " << y << endl;return 0;
}
在这个示例中,swap
函数接受两个整型指针a
和b
作为参数。函数内部通过解引用操作符*
来访问指针所指向的内存位置,并交换它们的值。
在main
函数中,我们定义了两个整型变量x
和y
,并将它们的地址&x
和&y
作为参数传递给swap
函数。在函数内部,通过指针来交换x
和y
的值。最后,输出交换前后的x
和y
的值。
示例2: 修改字符串的内容
#include <iostream>
#include <cstring>
using namespace std;void toUpperCase(char* str) {int length = strlen(str);for (int i = 0; i < length; i++) {if (str[i] >= 'a' && str[i] <= 'z') {str[i] = str[i] - 'a' + 'A';}}
}int main() {char message[] = "Hello, world!";cout << "转换前: " << message << endl;toUpperCase(message);cout << "转换后: " << message << endl;return 0;
}
在这个示例中,toUpperCase
函数接受一个字符指针str
作为参数。函数内部通过指针来访问字符串的每个字符,并将小写字母转换为大写字母。
在main
函数中,我们定义了一个字符数组message
,并将其作为参数传递给toUpperCase
函数。函数内部通过指针来修改字符串的内容,将其转换为大写。最后,输出转换前后的字符串。
示例3: 动态分配内存
#include <iostream>
using namespace std;void allocateArray(int** arr, int size) {*arr = new int[size];for (int i = 0; i < size; i++) {(*arr)[i] = i + 1;}
}int main() {int* numbers = nullptr;int size = 5;allocateArray(&numbers, size);cout << "动态分配的数组: ";for (int i = 0; i < size; i++) {cout << numbers[i] << " ";}cout << endl;delete[] numbers;return 0;
}
在这个示例中,allocateArray
函数接受一个指向整型指针的指针arr
和数组大小size
作为参数。函数内部使用new
运算符动态分配一个整型数组,并将其地址赋值给指针*arr
。然后,通过指针来初始化数组的元素。
在main
函数中,我们定义了一个整型指针numbers
和数组大小size
。将numbers
的地址&numbers
和size
作为参数传递给allocateArray
函数。函数内部动态分配一个数组,并将其地址赋值给numbers
。最后,输出动态分配的数组,并使用delete[]
运算符释放内存。
这些示例展示了将指针作为函数参数的不同应用场景,包括交换整数值、修改字符串内容和动态分配内存。通过将指针传递给函数,我们可以在函数内部直接访问和修改指针所指向的内存位置的值,提供了一种高效且灵活的方式来操作数据。但同时也需要注意指针的正确使用和内存管理,避免出现内存泄漏或非法访问的问题。
这篇关于GESP四级 - 第一章 - 第2节 - 形参与实参的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!