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
================================================
相关推荐
醇氧5 小时前
springAI学习 (二) 模型
java·学习·spring·ai·ai编程
雾岛听蓝5 小时前
C++ 类和对象(二):默认成员函数详解
开发语言·c++
爱吃大芒果5 小时前
Flutter 动画实战:隐式动画、显式动画与自定义动画控制器
开发语言·javascript·flutter·ecmascript·gitcode
郝学胜-神的一滴5 小时前
OpenGL中的glDrawArrays函数详解:从基础到实践
开发语言·c++·程序人生·算法·游戏程序·图形渲染
李白你好5 小时前
Bypass_Webshell webshell编码工具 支持 jsp net php asp编码免杀
开发语言·php
feifeigo1235 小时前
C#中实现控件拖动功能
开发语言·c#
找方案5 小时前
hello-agents 学习笔记:从概念到落地,初识智能体的奇妙世界
人工智能·笔记·学习·大模型
●VON5 小时前
小V健身助手开发手记(五):基于 RDB 的历史记录系统设计与实现
学习·openharmony·开源鸿蒙·von
曹牧5 小时前
C#:List<string>类型的集合转换成用逗号分隔的字符串
开发语言·c#·list