C++ Primer Plus(第6版):第二章 开始学习C++

请关注我!我将后续上传视频讲解!(保姆级程度)


一、C++程序的基本结构与核心元素

1.1 最小C++程序示例与组成

以经典 "输出消息" 程序(myfirst.cpp)为例,完整程序包含以下不可缺少的元素:

cpp 复制代码
#include <iostream>  // 预处理器编译指令
int main()           // 函数头:程序入口
{                    // 函数体开始
    using namespace std;  // 名称空间编译指令
    cout << "Come up and C++ me some time." << endl;  // 输出语句
    return 0;        // 返回语句:结束main()
}                    // 函数体结束

核心规则 :每个C++程序必须包含且仅包含一个main()函数,程序从main()开始执行;所有语句以分号;结尾,分号是语句的终止符(而非分隔符,不可省略)。

1.2 关键组成部分详解

(1)预处理器编译指令 #include

  • 功能: 在编译前,将指定头文件的内容"复制粘贴"到当前源代码中,为程序提供外部功能支持。

  • 示例: #include <iostream>引入iostream头文件,该文件定义了cout(输出)、cin(输入)等标准IO对象,是实现输入输出的基础。

  • 头文件分类(按命名风格):

    头文件类型 命名规则 示例 说明
    C++旧式风格 .h结尾 iostream.h C++早期版本使用,部分旧编译器兼容
    C旧式风格 .h结尾 math.h C/C++通用,提供C语言库函数原型
    C++新式风格 无扩展名 iostream C++标准风格,需配合namespace std
    转换后的C头文件 前缀c+无扩展名 cmath C++版本的C库头文件,支持C++特性

(2)main() 函数:程序入口

  • 函数头格式int main(),其中:
    • int:函数返回类型,表示main()执行结束后向操作系统返回一个整数值(通常0表示程序正常结束,非0表示异常)。
    • main():函数名,C++规定的程序入口函数名(大小写敏感,不可改为Main()MAIN())。
    • 空括号():表示main()不接受参数(C++中()(void)等效,后者更显式)。
  • 函数体 :包裹在{}内的语句集合,包含程序的核心逻辑;return 0;main()的隐含返回语句(若省略,编译器自动添加),其他函数无此特性。
  • 特殊情况 :动态链接库(DLL)、嵌入式程序等非独立程序可不包含main(),但常规独立C++程序必须有main()

(3)名称空间 namespace

  • 背景: 解决"同名标识符冲突"问题(如不同库中存在同名函数wanda()),将库组件封装在特定命名空间中,通过命名空间区分。
  • 标准库命名空间: C++标准库(如coutendl)位于std命名空间中,访问方式有3种:
    • 全局使用: using namespace std;,声明当前代码块可直接使用std中的所有名称(简单但大型项目可能引发冲突)。
    • 局部使用: using std::cout; using std::endl;,仅声明需要的特定名称,减少冲突风险。
    • 显式前缀: std::cout << "Hello" << std::endl;,不依赖using,最安全但需重复写std::

(4)注释:代码说明

  • 作用: 为程序员提供代码解释,编译器忽略注释内容,不影响程序执行。
  • 两种风格:
    • C++风格: // 注释内容,注释范围从//到行尾,可单独成行或跟在代码后(推荐使用,避免配对错误)。
    • C风格: /* 注释内容 */,注释范围从/**/,可跨多行,但需注意正确配对(如/* 注释1 /* 注释2 */会报错,因/*未闭合)。

二、C++输入与输出:coutcin

2.1 输出工具cout

cout(console output)是ostream类的对象,默认关联屏幕输出流,通过<<(插入运算符)向输出流写入数据,支持字符串、变量、表达式等多种输出内容。

(1)核心用法

  • 基础输出: 字符串与变量

    • 语法: cout << 输出项1 << 输出项2 << ...;

    • 输出项支持: 字符串常量(双引号包裹)、变量(任意基本类型)、算术/逻辑表达式(直接输出结果)。

    • 示例

      cpp 复制代码
      #include <iostream>
      using namespace std;
      
      int main() {
          int a = 10, b = 20;
          double pi = 3.14159;
          cout << "a = " << a << ", b = " << b << endl;  // 变量输出
          cout << "a + b = " << a + b << endl;          // 表达式输出
          cout << "pi = " << pi << "\n";               // 字符串+变量混合输出
          return 0;
      }
  • 拼接输出与格式灵活调整

    • 连续<<拼接: 无需分多条语句,可直接串联多个输出项(包括不同类型)。

    • 换行控制: 支持在字符串中嵌入\n,或使用endl控制换行(二者区别见下表)。

    • 示例

      cpp 复制代码
      // 多行输出合并为一条语句,换行符嵌入字符串
      cout << "Line 1\nLine 2\nLine 3";
      // 混合使用\n和endl
      cout << "Hello" << endl << "World\n";

(2)关键特性与控制工具

  • endl\n对比

    特性 endl \n
    核心功能 换行 + 刷新输出缓冲区 仅换行,不刷新缓冲区
    适用场景 需即时显示输出(如交互提示、调试) 普通换行(效率更高,无刷新开销)
    依赖头文件/命名空间 #include <iostream>+std 无额外依赖(C++内置转义字符)
    示例 cout << "Done!" << endl; cout << "Done!\n";
  • 转义字符(控制输出格式)

    转义字符是嵌入字符串中的特殊字符,以\开头,用于控制输出格式(如换行、制表符),无需依赖额外头文件。

    转义字符 功能描述 示例 输出效果
    \n 换行(光标移至下一行开头) cout << "a\nb"; a b
    \t 水平制表符(类似Tab键) cout << "a\tb"; a b(间隔约8个字符)
    \b 退格(光标左移一位) cout << "abc\bd"; abd(c被退格删除)
    \\ 输出反斜杠\ cout << "a\\b"; a\b
    \" 输出双引号" cout << "He said \"Hi\""; He said "Hi"
    \' 输出单引号' cout << 'a' << '\''; a'
    \a 蜂鸣提示(部分系统支持) cout << "\a"; 发出蜂鸣音
  • 格式化输出(指定精度、对齐等)
    cout支持通过成员函数或控制符调整输出格式(如浮点数精度、整数进制、字段宽度),需结合iomanip头文件(部分功能)。

    格式化需求 实现方式 示例代码 输出效果
    浮点数保留2位小数 fixed + setprecision(n)(需iomanip cout << fixed << setprecision(2) << 3.1415; 3.14
    整数以十六进制输出 hex控制符 cout << hex << 255; ff(小写)
    整数以八进制输出 oct控制符 cout << oct << 8; 10
    字段宽度对齐(右对齐) setw(n)(需iomanip cout << setw(5) << 123; 123(占5个字符)
    填充空白字符 setfill(ch)(需iomanip cout << setw(5) << setfill('0') << 123; 00123
  • 示例

    格式化输出浮点数与整数。

    cpp 复制代码
    #include <iostream>
    #include <iomanip>  // 用于setprecision、setw等
    using namespace std;
    
    int main() {
        double pi = 3.1415926535;
        int num = 255;
        // 浮点数保留4位小数
        cout << fixed << setprecision(4) << "pi = " << pi << endl;
        // 整数分别以十进制、十六进制、八进制输出
        cout << "十进制:" << dec << num << endl;
        cout << "十六进制:" << hex << num << endl;
        cout << "八进制:" << oct << num << endl;
        return 0;
    }

(3)cout的高级用法

  • 输出char数组与string对象: 直接输出(string需包含<string>头文件)。

    cpp 复制代码
    #include <string>
    string name = "Alice";
    char city[] = "Beijing";
    cout << "Name: " << name << ", City: " << city << endl;
  • 成员函数cout.put() 专门输出单个字符(支持字符常量或ASCII码)。

    cpp 复制代码
    cout.put('A');          // 输出字符'A'
    cout.put(66);           // 输出ASCII码66对应的字符'B'

2.2 输入工具cin

cin(console input)是istream类的对象,默认关联键盘输入流,通过>>(抽取运算符)从输入流读取数据并赋值给变量,支持自动类型转换和多种输入模式。

(1)核心用法

  • 基础输入: 读取单个变量

    • 语法: cin >> 变量1 >> 变量2 >> ...;

    • 自动类型适配: 输入的字符流会自动转换为变量的声明类型(如输入"3.14"double变量,输入"123"int变量)。

    • 跳过空白符: 读取时自动忽略输入中的空格、制表符、换行符(多个变量可连续输入,用空白符分隔)。

    • 示例

      cpp 复制代码
       #include <iostream>
       using namespace std;
      
       int main() {
           int age;
           double height;
           cout << "Enter age and height: ";
           cin >> age >> height;  // 输入格式:18 1.75(空格分隔)
           cout << "Age: " << age << ", Height: " << height << endl;
           return 0;
       }
       ```
  • 读取字符串(char数组与string对象)

    • 读取char数组: cin >> 数组名;,自动忽略前导空白符,遇到空白符(空格、换行)停止读取,末尾自动添加\0(字符串结束符)。

    • 读取string对象: 需包含<string>头文件,用法与char数组一致,但无需指定数组长度(自动扩容)。

    • 示例

      cpp 复制代码
       #include <iostream>
       #include <string>
       using namespace std;
      
       int main() {
           char arr[20];
           string str;
           cout << "Enter a word (char array): ";
           cin >> arr;  // 输入:Hello World → 仅读取"Hello"
           cout << "char array: " << arr << endl;
           cout << "Enter a word (string): ";
           cin >> str;  // 输入:C++ → 读取完整字符串
           cout << "string: " << str << endl;
           return 0;
       }
       ```

(2)常见问题与解决方案

  • 混合输入(数字+字符串)的残留换行问题

    • 问题: 先读取数字(cin >> num;)后,用户按下的换行符会留在输入队列中,后续若用getline()读取整行字符串,会直接读取到空行。

    • 原因: >>读取数字时忽略空白符,但换行符未被消费,残留于输入缓冲区。

    • 解决方案:

      • 方案1:cin.get();读取并丢弃残留的换行符(适用于单个残留字符)。
      • 方案2:cin.ignore(n, ch);忽略指定字符前的n个字符(更通用)。
    • 示例

      cpp 复制代码
       #include <iostream>
       #include <string>
       using namespace std;
      
       int main() {
           int age;
           string name;
           cout << "Enter age: ";
           cin >> age;
           // 解决方案1:读取残留换行符
           cin.get();  
           // 解决方案2:忽略最多100个字符,直到遇到换行符(更稳妥)
           // cin.ignore(100, '\n');
           cout << "Enter name: ";
           getline(cin, name);  // 正常读取整行姓名
           cout << "Age: " << age << ", Name: " << name << endl;
           return 0;
       }
       ```
  • 读取整行输入(含空格)

    • 场景: 需读取包含空格的字符串(如姓名"Zhang San"、地址"Beijing China")。

      • 方法1: cin.getline(数组名, 最大长度);(适用于char数组)
        cin.getline(char* arr, int max_len);,读取到换行符或max_len-1个字符后停止,末尾自动添加\0
      • 方法2: getline(cin, string对象);(适用于string对象,推荐)
        无需指定长度,自动读取整行(包括空格),换行符被丢弃。
    • 示例

      cpp 复制代码
       // char数组读取整行
       char address[50];
       cout << "Enter address: ";
       cin.getline(address, 50);  // 输入:No.100 Main Street → 完整读取
      
       // string对象读取整行
       string intro;
       cout << "Enter introduction: ";
       getline(cin, intro);  // 输入:I like C++ → 完整读取
       ```

(3)cin的扩展用法与输入控制

  • 成员函数cin.get()的多场景使用

    函数原型 功能描述 示例
    cin.get(char& ch) 读取单个字符(包括空格、换行),赋值给ch char c; cin.get(c);(读取空格/换行)
    cin.get() 读取单个字符,返回该字符的ASCII码(可丢弃) cin.get();(丢弃残留换行符)
    cin.get(char* arr, int n) 读取最多n-1个字符到数组,遇换行/空格停止 cin.get(arr, 20);
  • 输入验证与错误处理

    • 报错: 当输入类型与变量类型不匹配时(如给int变量输入"abc"),cin会进入错误状态,后续输入失效。

    • 解决方案: 清空错误状态+丢弃无效输入。

    • 示例

      cpp 复制代码
       #include <iostream>
       using namespace std;
      
       int main() {
           int num;
           cout << "Enter an integer: ";
           while (!(cin >> num)) {  // 输入非整数时进入循环
               cin.clear();         // 清空错误状态
               cin.ignore(100, '\n');  // 丢弃输入缓冲区中的无效字符
               cout << "Invalid input! Enter again: ";
           }
           cout << "You entered: " << num << endl;
           return 0;
       }
       ```

三、变量与数据类型基础

3.1 变量声明与初始化

  • 声明语法数据类型 变量名;,作用是告诉编译器"变量的类型"和"名称",编译器为变量分配内存。例如,int apples; double price; char grade;

  • 核心规则:C++要求"变量使用前必须声明",未声明直接使用会触发编译错误(避免拼写错误导致的隐式创建变量问题,如BASIC语言)。

  • 初始化 :声明时直接赋值,避免变量值"不确定"(未初始化的局部变量值为内存残留值),常见方式:

    cpp 复制代码
    int a = 10;    // 传统初始化(C风格)
    int b(20);     // C++风格初始化
    int c{30};     // C++11列表初始化(推荐,禁止缩窄转换)
    int d = {40};  // C++11列表初始化的兼容写法

3.2 基本数据类型预览

本章暂介绍常用基础类型,后续第三章详细展开。

  • 整型int(默认整型,长度随系统,通常4字节)、short(短整型,至少2字节)、long(长整型,至少4字节),用于存储无小数的整数。
  • 浮点型double(双精度浮点型,通常8字节),用于存储带小数的数字(如3.140.001)。
  • 字符型char(字符型,1字节),用于存储单个字符(如'A''5'),本质是存储字符的ASCII编码(如'A'对应ASCII码65)。

四、函数基础

4.1 函数的核心概念

函数是完成特定任务的代码块,需明确 "输入(参数)""处理(函数体)""输出(返回值)" 三要素,编译器通过函数原型确认函数调用规则,避免类型不匹配等错误。

(1)函数三要素详解

要素 定义与作用 示例(计算两数之和的函数add
返回类型 函数执行后返回值的类型,无返回值时用void;返回值需与类型一致(或可隐式转换)。 函数返回int类型的和,故返回类型为int
函数名 标识函数的唯一名称,需符合C++命名规则(字母/数字/下划线,首字符非数字,区分大小写)。 命名为add,直观体现"加法"功能。
参数列表 函数接收的输入数据,格式为"类型1 形参1, 类型2 形参2,...";无参数时可写void或空括号。 参数列表为int a, int bab为"形式参数"(简称形参),接收调用时传入的"实际参数"(简称实参)。

(2)函数分类与示例

根据是否返回值,函数可分为两类,核心区别在于返回类型和return语句的使用。

  • 有返回值函数

    • 语法结构: 执行后返回一个值,需在函数体中用return语句返回结果,返回值可赋值给变量或直接参与表达式运算。

    • 示例: 自定义add函数计算两数之和,调用时接收结果并打印。

      cpp 复制代码
      #include <iostream>
      using namespace std;
      
      // 函数原型:声明返回类型int,参数为两个int
      int add(int a, int b);
      
      int main() {
          int x = 5, y = 3;
          // 调用add函数,传入实参x和y,返回值赋值给result
          int result = add(x, y);
          cout << x << " + " << y << " = " << result << endl;  // 输出:5 + 3 = 8
      
          // 直接用返回值参与表达式运算
          cout << "10 + 20 = " << add(10, 20) << endl;  // 输出:10 + 20 = 30
          return 0;
      }
      
      // 函数定义:实现加法逻辑
      int add(int a, int b) {
          int sum = a + b;
          return sum;  // 返回计算结果,类型与函数返回类型int一致
      }
  • 无返回值函数

    • 语法结构: 仅执行操作(如打印、修改外部变量等),不返回值,返回类型为void,函数体中可省略return(或写return;提前结束函数)。

    • 示例: 自定义printWelcome函数打印欢迎消息,printStars函数打印指定数量的星号。

      cpp 复制代码
      #include <iostream>
      using namespace std;
      
      // 函数原型:无返回值(void),无参数(空括号)
      void printWelcome();
      // 函数原型:无返回值,参数为int类型(打印星号的数量)
      void printStars(int count);
      
      int main() {
          printWelcome();  // 调用无参数无返回值函数
          printStars(5);   // 调用带参数无返回值函数,传入实参5
          printStars(3);   // 再次调用,传入实参3
          return 0;
      }
      
      // 函数定义:打印欢迎消息
      void printWelcome() {
          cout << "=============================" << endl;
          cout << "   Welcome to C++ Function!   " << endl;
          cout << "=============================" << endl;
          // 无return语句,函数执行完自动结束
      }
      
      // 函数定义:打印count个星号
      void printStars(int count) {
          if (count <= 0) {  // 处理非法输入(count为负数或0时)
              cout << "Error: count must be positive!" << endl;
              return;  // 提前结束函数,无返回值
          }
          for (int i = 0; i < count; i++) {
              cout << "*";
          }
          cout << endl;
      }

      输出结果

      复制代码
      =============================
         Welcome to C++ Function!   
      =============================
      *****
      ***

(3)函数原型的作用与示例

函数原型是函数的"接口说明",仅声明函数的返回类型和参数类型,不包含函数体,需在函数调用前 声明(通常放在main()前或头文件中),编译器通过原型检查调用的合法性(如参数数量、类型是否匹配)。

  • 原型的语法与示例

    • 语法: 返回类型 函数名(参数类型列表);(参数名可省略,仅需类型)。
    • 示例: int add(int, int);(省略参数名ab,仅保留类型,原型仍合法)。
  • 原型的核心作用(避免错误)

    • 报错: 若缺少原型或原型与调用不匹配,编译器会报错或产生未定义行为。

    • 反例: 未声明原型直接调用函数,编译器无法识别,报错"未定义标识符multiply"。

      cpp 复制代码
       #include <iostream>
       using namespace std;
      
       int main() {
           // 错误:未声明multiply函数的原型,编译器不知道该函数的存在
           int result = multiply(4, 5);  
           cout << result << endl;
           return 0;
       }
      
       // 函数定义在调用后,且无原型,编译失败
       int multiply(int a, int b) {
           return a * b;
       }
       ```
      **修正方案**:添加函数原型,编译通过:
       ```cpp
       #include <iostream>
       using namespace std;
      
       // 正确:在调用前声明函数原型
       int multiply(int a, int b);
      
       int main() {
           int result = multiply(4, 5);  // 编译器通过原型确认调用合法
           cout << "4 * 5 = " << result << endl;  // 输出:4 * 5 = 20
           return 0;
       }
      
       int multiply(int a, int b) {
           return a * b;
       }
       ```

4.2 库函数的使用

(1)使用步骤详解

  • 步骤1: 确定头文件

    不同功能的库函数对应不同的头文件(如数学函数在cmath中,字符串函数在cstring中),需用#include包含。

  • 步骤2: 调用函数

    按函数原型传入正确类型的参数,接收返回值(若有)。

(2)常用库函数示例

  • 数学函数(cmath头文件)

    函数名 功能 原型 示例 结果
    sqrt 计算平方根 double sqrt(double) sqrt(6.25) 2.5
    pow 计算base^exp double pow(double, double) pow(2, 3) 8.0
    abs 计算整数绝对值 int abs(int) abs(-10) 10
    fabs 计算浮点数绝对值 double fabs(double) fabs(-3.14) 3.14
  • 示例: 使用sqrtpow计算圆的面积和球体体积。

    cpp 复制代码
    #include <iostream>
    #include <cmath>  // 包含数学函数的原型
    using namespace std;
    
    int main() {
        const double PI = 3.14159;  // 圆周率常量
        double radius;
        cout << "Enter the radius of the circle: ";
        cin >> radius;
    
        // 调用sqrt计算半径的平方根(示例:假设需求是"半径的平方根")
        double radius_sqrt = sqrt(radius);
        cout << "Square root of radius: " << radius_sqrt << endl;
    
        // 调用pow计算半径的平方(pow(radius, 2)),再计算圆面积
        double circle_area = PI * pow(radius, 2);
        cout << "Area of the circle: " << circle_area << endl;
    
        // 调用pow计算半径的立方(pow(radius, 3)),再计算球体体积
        double sphere_volume = (4.0 / 3.0) * PI * pow(radius, 3);
        cout << "Volume of the sphere: " << sphere_volume << endl;
        return 0;
    }

    输入输出示例

    复制代码
    Enter the radius of the circle: 5
    Square root of radius: 2.23607
    Area of the circle: 78.5397
    Volume of the sphere: 523.598
  • 字符串函数(cstring头文件)

    函数名 功能 原型 示例 结果
    strlen 计算字符串长度(不含\0 size_t strlen(const char*) strlen("Hello") 5
    strcpy 复制字符串到目标数组 char* strcpy(char*, const char*) strcpy(dest, "World") dest变为"World"
    strcmp 比较两个字符串(按ASCII码) int strcmp(const char*, const char*) strcmp("Apple", "Banana") -1(前者小于后者)

    示例: 使用strlenstrcpy处理C风格字符串。

    cpp 复制代码
    #include <iostream>
    #include <cstring>  // 包含字符串函数的原型
    using namespace std;
    
    int main() {
        char str1[20] = "Hello";
        char str2[20];
    
        // 调用strlen计算str1的长度
        cout << "Length of str1: " << strlen(str1) << endl;  // 输出:
    
        // 调用strcpy将str1复制到str2
        strcpy(str2, str1);
        cout << "str2 after copy: " << str2 << endl;  // 输出:Hello
    
        // 拼接字符串(先复制str1到str2,再追加" World")
        strcpy(str2, str1);
        strcat(str2, " World");  // strcat:追加字符串
        cout << "str2 after concatenation: " << str2 << endl;  // 输出:Hello World
        cout << "New length of str2: " << strlen(str2) << endl;  // 输出:11
        return 0;
    }

(3)注意事项

  • 链接库文件 :部分编译器(如GNU g++)使用数学库函数(如sqrtpow)时,需在编译命令后加-lm(链接数学库),例如:
    g++ program.cpp -o program -lm
    若省略-lm,可能报错"undefined reference to sqrt"。
  • 参数类型匹配 :库函数对参数类型要求严格,如sqrt仅接收double类型,若传入int,编译器会隐式转换为double(但建议显式转换,避免精度损失)。

4.3 自定义函数

自定义函数是实现个性化功能的核心,需遵循"原型声明→函数定义→函数调用"的流程,同时注意参数传递、返回值处理等细节。

(1)自定义函数的完整流程

以"计算矩形面积和周长"为例,演示从原型到调用的全流程:

  • 步骤1:main()前声明函数原型

    • int calculateArea(int width, int height):计算面积,返回int
    • void calculatePerimeter(int width, int height):计算周长,无返回值。
  • 步骤2: 定义函数体

    实现函数的具体逻辑,注意参数和返回值的类型匹配。

  • 步骤3: 调用函数

    main()中传入实参,执行函数。

  • 示例

    cpp 复制代码
    #include <iostream>
    using namespace std;
    
    // 步骤1:声明函数原型
    int calculateArea(int width, int height);  // 有返回值(面积)
    void calculatePerimeter(int width, int height);  // 无返回值(打印周长)
    
    int main() {
        int w, h;
        cout << "Enter width of the rectangle: ";
        cin >> w;
        cout << "Enter height of the rectangle: ";
        cin >> h;
    
        // 步骤3:调用函数
        int area = calculateArea(w, h);  // 调用有返回值函数,接收结果
        cout << "Area of the rectangle: " << area << endl;
    
        calculatePerimeter(w, h);  // 调用无返回值函数,直接执行操作
        return 0;
    }
    
    // 步骤2:定义函数(计算面积)
    int calculateArea(int width, int height) {
        if (width <= 0 || height <= 0) {  // 合法性检查
            cout << "Error: width and height must be positive!" << endl;
            return 0;  // 非法输入时返回0
        }
        return width * height;  // 返回面积(int类型,与函数返回类型一致)
    }
    
    // 步骤2:定义函数(计算并打印周长)
    void calculatePerimeter(int width, int height) {
        if (width <= 0 || height <= 0) {
            cout << "Error: width and height must be positive!" << endl;
            return;  // 非法输入时提前结束函数
        }
        int perimeter = 2 * (width + height);
        cout << "Perimeter of the rectangle: " << perimeter << endl;
    }

    输入输出示例1(合法输入):

    复制代码
    Enter width of the rectangle: 4
    Enter height of the rectangle: 5
    Area of the rectangle: 20
    Perimeter of the rectangle: 18

    输入输出示例2(非法输入):

    复制代码
    Enter width of the rectangle: -3
    Enter height of the rectangle: 5
    Error: width and height must be positive!
    Area of the rectangle: 0
    Error: width and height must be positive!

(2)关键规则与示例解析

  • 参数传递: 按值传递

    • 默认情况下,函数参数采用"按值传递",即函数接收的是实参的副本,修改形参不会影响原实参。

    • 自定义addOne函数,试图修改形参,但原实参不变。

      cpp 复制代码
      #include <iostream>
      using namespace std;
      
      // 函数原型:按值传递int参数
      void addOne(int x);
      
      int main() {
          int num = 10;
          cout << "Before call: num = " << num << endl;  // 输出:10
          addOne(num);  // 传入num的副本,形参x初始化为10
          cout << "After call: num = " << num << endl;   // 输出:10(原实参未变)
          return 0;
      }
      
      void addOne(int x) {
          x = x + 1;  // 修改的是副本x,与原实参num无关
          cout << "In function: x = " << x << endl;  // 输出:11
      }
    • 结论:按值传递适合"仅使用参数值,不修改原变量"的场景(如计算、打印);若需修改原变量,需使用"按引用传递"。

  • 函数原型的位置: 原型必须在调用前声明,否则编译器无法识别,常见的声明位置有两种。

    • 全局作用域: 放在main()前,所有函数均可调用(推荐)。

    • 局部作用域: 放在某个函数内部,仅该函数可调用(不推荐,限制复用)。

    • 示例

      cpp 复制代码
      #include <iostream>
      using namespace std;
      
      // 全局原型:main()和printDouble()均可调用
      int doubleNum(int x);
      
      void printDouble(int x) {
          // 调用doubleNum函数,原型在全局作用域,故合法
          cout << "Double of " << x << " is " << doubleNum(x) << endl;
      }
      
      int main() {
          int a = 5;
          printDouble(a);  // 输出:Double of 5 is 10
          return 0;
      }
      
      int doubleNum(int x) {
          return 2 * x;
      }
  • 多函数程序的using指令: using namespace std;(或using std::cout;等)用于访问std命名空间中的组件(如coutcin),可根据使用范围选择声明位置。

    • 全局声明 :放在所有函数前,所有函数均可直接使用cout,无需加std::(简化代码,适合小型程序)。

    • 局部声明 :放在某个函数内部,仅该函数可直接使用cout(减少命名冲突,适合大型程序)。

    • 示例: 全局与局部using的对比。

      cpp 复制代码
      #include <iostream>
      
      // 全局using:所有函数均可直接使用cout
      using namespace std;
      
      void func1() {
          cout << "func1: Using global 'using'." << endl;
      }
      
      void func2() {
          // 局部using:仅func2可直接使用cout(若全局无using,其他函数需加std::)
          // using namespace std;
          cout << "func2: Using global 'using' too." << endl;
      }
      
      int main() {
          func1();
          func2();
          return 0;
      }

      输出:

      复制代码
      func1: Using global 'using'.
      func2: Using global 'using' too.

4.4 自定义函数进阶示例(多函数协作)

实际程序中,函数常需协作完成复杂任务,例如"计算学生平均分→判断是否及格→打印结果",通过多个函数分工实现模块化。

cpp 复制代码
#include <iostream>
using namespace std;

// 函数原型
// 1. 计算n个成绩的平均分
double calculateAverage(int scores[], int n);
// 2. 判断平均分是否及格(60分及以上为及格)
bool isPass(double average);
// 3. 打印学生成绩信息(姓名、平均分、是否及格)
void printResult(const char* name, double average, bool pass);

int main() {
    // 学生信息
    char name[] = "Zhang San";
    int scores[] = {85, 92, 78, 65, 70};
    int numScores = sizeof(scores) / sizeof(scores[0]);  // 计算成绩个数(5)

    // 函数协作
    double avg = calculateAverage(scores, numScores);  // 计算平均分
    bool pass = isPass(avg);                           // 判断是否及格
    printResult(name, avg, pass);                      // 打印结果

    return 0;
}

// 1. 计算平均分:接收成绩数组和个数,返回double类型的平均分
double calculateAverage(int scores[], int n) {
    if (n <= 0) {
        cout << "Error: No scores to calculate!" << endl;
        return 0.0;
    }
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += scores[i];
    }
    return static_cast<double>(sum) / n;  // 强制转换为double,避免整数除法
}

// 2. 判断是否及格:接收平均分,返回bool类型(true=及格,false=不及格)
bool isPass(double average) {
    return average >= 60.0;  // 表达式结果直接作为返回值
}

// 3. 打印结果:接收姓名、平均分、及格状态,无返回值
void printResult(const char* name, double average, bool pass) {
    cout << "================ Student Result ================" << endl;
    cout << "Name: " << name << endl;
    cout << "Average Score: " << average << endl;
    cout << "Pass Status: " << (pass ? "Pass" : "Fail") << endl;  // 三目运算符
    cout << "================================================" << endl;
}

输出结果

复制代码
================ Student Result ================
Name: Zhang San
Average Score: 78
Pass Status: Pass
================================================
相关推荐
2401_8414956410 小时前
【操作系统】进程同步与互斥实验报告
c++·算法·操作系统·进程·并发·同步·互斥
fqbqrr10 小时前
2607C++,soui与安卓
c++·soui
码智社10 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海10 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖11 小时前
JDK 26 新特性详解
java·开发语言
马优晨12 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a11177613 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao13 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
fqbqrr13 小时前
2607C++,使用微软detours勾挂工具
c++
人邮异步社区13 小时前
怎么把C语言学到精通?
c语言·开发语言