
🔥个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录
🍉学习方向:C/C++方向
⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平
**前言:**本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓"万丈高楼平地起"嘛,我们话不多说,继续进行C++阶段的学习。本文我们不讲C++主线的内容,我们来拓展一下或者说整理一下我们学习时C/C++时经常会提到的一些专有名词,例如形参、实参,显式类型转换和隐式类型转换类型转换,内置类型等等。

C++的两个参考文档:
老朋友(非官方文档):cplusplus
官方文档(同步更新):cppreference
目录
[形参(Formal Parameter)](#形参(Formal Parameter))
[实参(Actual Argument)](#实参(Actual Argument))
[1. 值传递(Pass by Value)](#1. 值传递(Pass by Value))
[2. 指针传递(Pass by Pointer)](#2. 指针传递(Pass by Pointer))
[3. 引用传递(Pass by Reference)](#3. 引用传递(Pass by Reference))
注意:
1、形参和实参的类型必须兼容,否则可能发生隐式转换或编译错误;
2、数组作为参数时会退化为指针;
3、函数参数求值顺序在C/C++中未定义;
4、C++中引用参数不能为NULL,比指针更安全;
5、大型对象建议使用引用或指针传递以避免拷贝开销。
正文
博主之前写过形参和实参相关的内容,只不过那是在C语言函数部分介绍的,比较简略:
掌握函数(一):库函数与自定义函数、形参与实参、return语句
一、形参的概念
C语言中形参和实参的概念------
形参(Formal Parameter)
-
定义在函数声明和函数定义中的参数
-
是函数接收外部数据的接口
-
属于函数的局部变量,只在函数内部有效
二、实参的概念
实参(Actual Argument)
-
调用函数时实际传入的参数
-
可以是常量、变量或表达式
-
必须与形参在类型、数量和顺序上匹配
三、参数传递方式
1. 值传递(Pass by Value)
-
将实参的值复制给形参
-
函数内对形参的修改不影响实参
-
C/C++默认的参数传递方式
cpp
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap(x, y); // x和y的值不会改变
}
2. 指针传递(Pass by Pointer)
-
传递变量的地址
-
函数内可以通过指针间接修改实参的值
-
C语言常用的参数传递方式
cpp
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 1, y = 2;
swap(&x, &y); // x和y的值被交换
}
3. 引用传递(Pass by Reference)
-
C++特有
-
形参是实参的别名
-
函数内对形参的修改直接影响实参
cpp
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap(x, y); // x和y的值被交换
}
四、数组作为参数
(一)一维数组
cpp
// 三种等效的声明方式
void func(int arr[]);
void func(int arr[10]); // 10会被忽略
void func(int *arr);
(二)多维数组
cpp
// 第二维必须指定大小
void func(int arr[][10]);
void func(int (*arr)[10]); // 指针数组
五、默认参数(C++)
-
在函数声明中为形参指定默认值
-
默认参数必须从右向左连续定义
-
通常在头文件中声明默认值
cpp
void func(int a, int b = 10, int c = 20);
func(1); // 等同于 func(1, 10, 20)
func(1, 2); // 等同于 func(1, 2, 20)
六、函数重载(C++)
-
函数名相同但参数列表不同
-
参数类型、数量或顺序不同
-
返回值类型不同不构成重载
cpp
void print(int a);
void print(double a);
void print(const char* str);
七、可变参数
-
C语言使用
<stdarg.h>
-
C++11引入可变参数模板
cpp
#include <stdarg.h>
#include <stdio.h>
void printNumbers(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int num = va_arg(args, int);
printf("%d ", num);
}
va_end(args);
}
int main() {
printNumbers(3, 1, 2, 3);
}
八、形参(形式参数)与实参(实际参数)的对比
C语言形参和实参的关系------
(一)基本概念对比
特性 | 形参(Formal Parameter) | 实参(Actual Argument) |
---|---|---|
定义位置 | 函数声明和定义中 | 函数调用时传入 |
作用域 | 函数体内局部有效 | 函数调用前已存在的变量或表达式 |
生命周期 | 函数调用时创建,返回时销毁 | 取决于原变量/表达式的生命周期 |
必需性 | 函数签名必需部分 | 调用时必须提供(除非有默认参数) |
(二)内存关系对比
1、值传递情况
cpp
void func(int param) { // param是形参
param = 100;
}
int main() {
int arg = 10; // arg是实参
func(arg); // 创建param副本
// arg仍为10
}
-
形参获得实参的独立副本
-
修改形参不影响实参
2、指针传递情况
cpp
void func(int *param) { // param是形参指针
*param = 100;
}
int main() {
int arg = 10; // arg是实参
func(&arg); // 传递地址
// arg变为100
}
-
形参获得实参的地址副本
-
通过指针可修改原实参
3、引用传递情况(C++)
cpp
void func(int ¶m) { // param是形参引用
param = 100;
}
int main() {
int arg = 10; // arg是实参
func(arg); // param是arg的别名
// arg变为100
}
-
形参是实参的别名
-
修改形参直接修改实参
(三)典型差异(附带示例)
1、数组参数的特殊性
cpp
void arrayFunc(int arr[]) { // 形参arr实际是指针
sizeof(arr); // 指针大小(如8字节)
}
int main() {
int actualArr[10];
sizeof(actualArr); // 数组大小(如40字节)
arrayFunc(actualArr); // 数组退化为指针
}
-
数组作为形参时会退化为指针
-
实参仍保持数组特性
2、默认参数处理
cpp
void func(int a = 10); // 默认值在声明中指定
int main() {
func(); // 使用默认实参10
func(20); // 提供显式实参
}
-
默认值属于形参声明部分
-
调用时可省略对应实参
3、函数重载解析
cpp
void print(int a); // 重载版本1
void print(double a); // 重载版本2
int main() {
print(10); // 根据实参类型选择版本1
print(10.0); // 根据实参类型选择版本2
}
- 重载决策基于实参与形参的匹配程度
(四)总结两者的关键区别
1、创建时机
-
形参:函数调用时创建
-
实参:调用前已存在
2、内存关系
-
值传递:完全独立
-
指针传递:共享同一内存地址
-
引用传递:完全共享内存
3、类型处理
- 实参到形参可能发生隐式类型转换
cpp
void func(double d);
func(10); // int实参转换为double形参
4、数组处理
-
形参中的数组总是退化为指针
-
实参保持原始数组类型(除非已退化为指针)
5、C++特有的特性
-
引用参数
-
默认参数
-
函数重载
-
右值引用(C++11)
九、C/C++形参和实参的对比
基本概念对比
特性 | C语言 | C++ |
---|---|---|
形参定义 | 函数声明和定义中的参数 | 同C语言,但支持更多特性 |
实参传递 | 值、指针 | 值、指针、引用 |
默认参数 | 不支持 | 支持 |
引用参数 | 不支持 | 支持 |
函数重载 | 不支持 | 支持 |
参数传递方式对比
1、值传递(两者相同)
cpp
// C
void func(int a) { a = 10; }
// C++
void func(int a) { a = 10; }
2、指针传递(两者相同)
cpp
// C
void func(int *a) { *a = 10; }
// C++
void func(int *a) { *a = 10; }
3、引用传递(仅C++)
cpp
// 仅C++
void func(int &a) { a = 10; }
默认参数对比
C语言(不支持)
cpp
// 错误!C不支持默认参数
void func(int a = 10);
C++(支持)
cpp
// C++支持
void func(int a = 10);
int main() {
func(); // 等同于func(10)
}
函数重载对比
C语言(不支持)
cpp
// 错误!C不支持函数重载
void print(int a);
void print(double a); // 冲突
C++(支持)
cpp
// C++支持
void print(int a);
void print(double a); // 合法重载
可变参数对比
C语言(使用stdarg.h)
cpp
#include <stdarg.h>
void printArgs(int count, ...) {
va_list args;
va_start(args, count);
// ...
va_end(args);
}
C++(支持C方式,也提供模板方式)
cpp
// 方式1:兼容C
#include <cstdarg>
void printArgs(int count, ...);
// 方式2:可变参数模板(C++11)
template<typename... Args>
void printArgs(Args... args);
重要区别总结
1、引用传递:C++特有,C语言只能用指针模拟;
2、默认参数:C++特有,C语言不支持;
3、函数重载:C++特有,C语言不支持;
4、const引用:C++可以使用const引用避免拷贝;
cpp
void func(const std::string &s); // C++高效传递大对象
5、右值引用:C++11新增(C++特有);
cpp
void func(std::string &&s); // 移动语义
实践建议
-
C语言:
-
使用指针实现"引用"效果;
-
大型结构体通过指针传递避免拷贝;
-
明确文档说明参数用途。
-
-
C++:
-
优先使用const引用传递大对象;
-
简单内置类型可用值传递;
-
需要修改的参数使用普通引用;
-
利用函数重载提高接口可用性;
-
C++11后考虑使用移动语义优化大对象传递。
-
结尾
往期回顾(本文涉及的一些往期博客)
【日常问题解决方案】VS2022不小心解决方案资源管理器把关掉了怎么办
**结语:**本文内容到这里就全部结束了。本文我们重新整理了形参、实参相关内容。