C和C++之间的关系是紧密且复杂的。C++最初是作为C语言的一个扩展开发的,目的是在不放弃C的强大功能和效率的同时,增加对象导向编程、泛型编程和其他一些特性。下面是C和C++之间主要的关系和区别:

  • 兼容性:C++在很大程度上是与C兼容的。这意味着许多C程序可以在C++编译器中编译并运行,尽管可能需要一些小的修改。
  • 面向对象编程(OOP):C++引入了面向对象编程。它允许使用类和对象,而C是一个过程性语言,不支持这些概念,或者说支持的不好,麻烦。
  • 模板:C++支持模板,这是一种允许程序员编写与数据类型无关的代码的功能。C没有这个功能。
  • 标准库:C++有一个更丰富的标准库,包括STL(标准模板库),这为数据结构和算法提供了广泛的支持。而C的标准库相对较小。
  • 类型检查:C++比C提供更严格的类型检查。这意味着某些在C中可行但可能导致错误的代码在C++中可能无法编译。
  • 异常处理:C++支持异常处理,这是一种处理程序运行时错误的机制。C没有内置的异常处理机制。
  • 命名空间:C++引入了命名空间,这有助于防止名称冲突。C没有这个概念。

一、命名空间

1、命名空间作用

        创建自己的命名空间是 C++ 中组织代码的一种好方法,特别是在开发大型项目或库时。命名空间可以帮助你避免名称冲突,并且清晰地组织代码。std 是 C++ 标准库的命名空间。它是一个定义在 C++ 标准库中的所有类、函数和变量的命名空间。新建一个QTCreator的C++工程,默认生成的代码。

#include <iostream>

using namespace std;

int main()
{
    cout << "Hello World!" << endl;
    return 0;
}

        在 C++ 中,如果你想使用标准库中的任何类、函数或对象,你通常有两种选择:使用 std:: 前缀:这是最常见的方式,它明确指定了你正在使用的是位于 std 命名空间中的元素。

std::cout << "Hello, world!" << std::endl;

        使用 using namespace std; :这允许你在不显式指定 std:: 的情况下使用 std 命名空间中的所有元素。

using namespace std;
cout << "Hello, world!" << endl;

std包含的内容:std 命名空间包含了许多类、函数和对象,例如:

  • 输入输出库(如 std::cout , std::cin , std::endl )
  • 容器类(如 std::vector , std::map , std::set )
  • 字符串类( std::string )
  • 异常类( std::exception 和相关子类)
  • 算法(如 std::sort , std::find )
  • 实用工具(如 std::pair , std::tuple )
  • 其他许多功能

【使用建议】对于小型代码或示例代码,使用 using namespace std; 通常是安全的。对于大型项目或库,建议显式地使用 std:: 前缀,以避免潜在的名称冲突,并提高代码的可读性和可维护性。

        std 命名空间是 C++ 编程的基础部分,理解和正确使用它对于编写健壮和高效的 C++ 代码至关重要。

2、自定义命名空间

        首先创建一个C++非QT类的项目,如下图所示。

        输入工程名称,如下图所示,也可以更改创建路径,之后一直点击“下一步”即可。

        右键工程名称,点击“添加新文件...”,

        按照下图所示的选择,最后点击“选择...”。

        输入文件名称后点击“下一步”,最后点击“完成即可”。

        就会得到如下图所示的空文件。

        编写如下所示的代码,之后对其进行使用。

#ifndef CIR_H
#define CIR_H

namespace cir {

    double PI = 3.141592653;
    //获取圆形周长的函数
    double getLengthOfCircle(double radius){
        return 2*PI*radius;
    }
    
    //获取圆形面积的函数
    double getAifCircle(double radius){
        return PI*radius*radius;
    }

}

#endif // CIR_H

        在main.cpp中编写下面代码

#include <iostream>
#include <stdio.h>
#include "cir.h"

using namespace std;

int main()
{
    double myRadius = 5;
    cout << "Hello World!" << endl;
    printf("length:%lf, are:%lf\n",cir::getLengthOfCircle(myRadius), cir::getAifCircle(myRadius));
    return 0;
}

        运行后在下面的输出如下图所示

        当然也可以采用另一种方式进行命名空间的引入,main.cpp中代码如下所示。

#include <iostream>
#include <stdio.h>
#include "cir.h"

using namespace std;
using namespace cir;

int main()
{
    double myRadius = 5;
    cout << "Hello World!" << endl;
    //printf("length:%lf, are:%lf\n",cir::getLengthOfCircle(myRadius), cir::getAifCircle(myRadius));
    printf("length:%lf, are:%lf\n",getLengthOfCircle(myRadius), getAifCircle(myRadius));
    return 0;
}

二、从C语言快速入门

1、输入输出

        C++ 中的输入和输出(I/O)主要是通过标准库中的输入输出流来实现的。最常用的是 iostream 库,它提供了用于输入和输出的基本流类,包括 cin 、cout 、cerr 和 clog 。

标准输出流 ( cout )

  • cout 代表标准输出流,通常用于向屏幕输出数据。
  • 使用操作符 << (插入操作符)向 cout 发送数据。
  • 例如, std::cout << "Hello, world!" << std::endl; 会在屏幕上打印 "Hello, world!" 并换行。

标准输入流 ( cin )

  • cin 代表标准输入流,用于从键盘接收数据。
  • 使用操作符 >> (提取操作符)从 cin 提取数据。
  • 例如, int x; std::cin >> x; 会从用户那里读取一个整数并存储在变量 x 中。

标准错误流 ( cerr ) 和标准日志流 ( clog )

  • cerr 用于输出错误消息。与 cout 不同, cerr 不是缓冲的,这意味着它会立即输出。
  • clog 类似于 cerr ,但它是缓冲的。它通常用于记录错误和日志信息。

        若想要在项目中做一些中文提示就需要修改字符编码,在工具-外部-配置...中设置下面的编码格式,否则在输出端会乱码。

        可以输入下面的代码进行测试,输出输入的结果

#include <iostream>
int main() {
    // 使用 cout 输出
    std::cout << "Enter a number: ";
    // 使用 cin 输入
    int num;
    std::cin >> num;
    // 输出结果
    std::cout << "You entered: " << num << std::endl;
    std::clog << "Logging: user entered a number." << std::endl;
    return 0;
}

2、基本变量类型

        C++ 基本数据类型整理成表格。以下是一个表格,展示了不同的基本数据类型及其一般用途和大小范围:和C语言类似。

数据类型 描述 大小(通常情况下) 用途
int 整型 至少16位 存储整数
short int 短整型 至少16位 存储较小的整数
long int 长整型 至少32位 存储较大的整数
long long int 更长的整型 至少64位 存储非常大的整数
unsigned int 无符号整型 同int 存储非负整数
float 单精度浮点类型 32位 存储小数,精度约为 6-7 位小数
double 双精度浮点类型 64位 存储小数,精度约为 15-16 位小数
long double 扩展精度浮点类型 80位或更多 存储小数,提供比 double 更高的精度
char 字符型 8位 存储单个字符或小整数
unsigned char 无符号字符型 8位 存储较大的字符或作为字节使用
signed char 有符号字符型 8位 明确作为带符号的字符或小整数使用
bool 布尔型 通常为8位 存储真值 true 或假值 false C语言C99以上支持
wchar_t 宽字符类型 通过为16位或32位 存储中文或者unicode
#include <iostream>
#include <locale>
#include <wchar.h>
int main() {
    // 设置本地化以支持宽字符
    std::setlocale(LC_ALL, "");
    // 使用 wchar_t 类型定义一个宽字符串
    wchar_t wstr[] = L"你好,世界!";
    // 在 C++ 中打印宽字符串
    std::wcout << wstr << std::endl;
    return 0;
}

        在 C++ 中, <climits> (或在 C 中是 <limits.h> )是一个标准头文件,提供了关于整型限制的信息。这个头文件中定义了各种整型数据类型的属性,如最大值、最小值等。使用这些信息可以帮助你了解在特定编译器和平台上各种数据类型的大小和范围。如何使用 <climits>,要使用 <climits> 中定义的常量,你首先需要包含这个头文件:

#include <climits>

        然后,你可以使用它提供的各种常量,例如:

  • INT_MAX : int 类型的最大值。
  • INT_MIN : int 类型的最小值。
  • UINT_MAX : unsigned int 类型的最大值。
  • LONG_MAX : long int 类型的最大值。
  • LONG_MIN : long int 类型的最小值。
  • LLONG_MAX : long long int 类型的最大值。
  • LLONG_MIN : long long int 类型的最小值。

        下面是一个简单的示例,展示了如何使用 <climits> 中的值,这个程序会输出 int 、unsigned int 和 long long int 类型的最大值和最小值。

#include <iostream>
#include <climits>
int main() {
    std::cout << "The range of int is from " << INT_MIN << " to " << INT_MAX <<
    std::endl;
    std::cout << "The maximum value of unsigned int is " << UINT_MAX <<
    std::endl;
    std::cout << "The range of long long is from " << LLONG_MIN << " to " <<
    LLONG_MAX << std::endl;
    return 0;
}
  • <climits> 提供的是编译时确定的常量,这意味着这些值在编译时就已经固定,根据编译器和平台的不同而可能有所不同。
  • 使用这些限制值可以帮助你编写更可移植和安全的代码,特别是在处理可能超出数据类型范围的操作时。

3、流程控制

        在 C++ 中,流程控制语句用于根据不同条件控制程序的执行流程。它们是编程中的基本构建块,允许程序根据条件执行不同的代码段,重复执行某些操作,或者根据特定情况跳过某些代码段。下面是 C++ 中最常见的流程控制语句:

1. if 语句:基于条件的基本控制结构。如果条件为真,则执行代码块。

if (condition) {
    // 条件为真时执行的代码
}

else 语句:与 if 语句配合使用,当 if 的条件为假时执行。

if (condition) {
    // 条件为真时执行的代码
} else {
    // 条件为假时执行的代码
}

else if 语句:用于测试多个条件。

if (condition1) {
    // 第一个条件为真时执行的代码
} else if (condition2) {
    // 第二个条件为真时执行的代码
} else {
    // 所有条件为假时执行的代码
}

switch 语句:基于变量的值选择执行不同代码块的方法。

switch (expression) {
    case value1:
    // expression 等于 value1 时执行的代码
    break;
    case value2:
    // expression 等于 value2 时执行的代码
    break;
    default:
    // 没有匹配的 case 时执行的代码
}

for 循环:当知道循环应该执行的次数时使用。

for (initialization; condition; increment) {
    // 循环体
}

while 循环:当条件为真时,重复执行代码块。

while (condition) {
    // 循环体
}

do-while 循环:至少执行一次循环体,然后再检查条件。

do {
    // 循环体
} while (condition);

1. break 语句:用于立即跳出最近的 switch 或循环( for 、while 、do-while )。
2. continue 语句:跳过循环的当前迭代,并继续下一次迭代。
3. goto 语句:直接跳转到程序中的另一个点。使用 goto 通常不推荐,因为它可以使代码难以阅读
和维护。

        流程控制语句是编程中非常重要的部分,允许开发者编写可以根据不同情况改变行为的灵活且强大的程序。在使用这些语句时,应该确保逻辑清晰,以便代码易于理解和维护。

4、函数

        在 C++ 中,函数是一段执行特定任务的代码块,它可以带有参数,并且可能返回一个值。函数的使用使得代码更加模块化和可重用,有助于降低代码的复杂性,并提高可维护性。函数的基本结构,C++ 函数的基本结构包括返回类型、函数名、参数列表和函数体:

返回类型 函数名(参数列表) {
    // 函数体
    // 返回语句(如果有返回值的话)
}

        以下是一个 C++ 函数的简单示例:

#include <iostream>
using namespace std;

// 函数声明
int add(int x, int y);

int main() {
    int result = add(5, 3);
    cout << "Result: " << result << endl;
    return 0;
}

// 函数定义
int add(int x, int y) {
    return x + y;
}

        在这个示例中, add 函数接收两个整数参数,并返回它们的和。函数的组成部分,返回类型:指定函数返回的数据类型。如果函数不返回任何值,则使用 void 。函数名:函数的标识符,用于调用函数。参数列表:括号内的变量列表,用于从函数的调用者那里接收值。如果函数不接收任何参数,则此列表为空。函数体:大括号 {} 内的一系列语句,定义了函数的执行操作。

5、内联函数

        内联函数(Inline Function)是C++中一种特殊的函数,其定义直接在每个调用点展开。这意味着编译器会尝试将函数调用替换为函数本身的代码,这样可以减少函数调用的开销,尤其是在小型函数中。

  • 减少函数调用开销:内联函数通常用于优化小型、频繁调用的函数,因为它避免了函数调用的常规开销(如参数传递、栈操作等)。
  • 编译器决策:即使函数被声明为内联,编译器也可能决定不进行内联,特别是对于复杂或递归函数。
  • 适用于小型函数:通常只有简单的、执行时间短的函数适合做内联。
  • 定义在每个使用点:内联函数的定义(而非仅仅是声明)必须对每个使用它的文件都可见,通常意味着将内联函数定义在头文件中。

        使用方法:通过在函数声明前添加关键字 inline 来指示编译器该函数适合内联:

inline int max(int x, int y) {
    return x > y ? x : y;
}
#include <iostream>

inline int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(5, 3); // 编译器可能会将此替换为:int result = 5 + 3;
    std::cout << "Result: " << result << std::endl;
    return 0;
}

        在这个示例中,函数 add 被定义为内联函数。当它被调用时,编译器可能会将函数调用替换为函数体内的代码。注意事项

  • 过度使用的风险:不应滥用内联函数,因为这可能会增加最终程序的大小(代码膨胀)。对于大型函数或递归函数,内联可能导致性能下降。
  • 编译器的决定:最终是否将函数内联是由编译器决定的,即使函数被标记为 inline 。
  • 适用场景:最适合内联的是小型函数和在性能要求高的代码中频繁调用的函数。

        内联函数是一种用于优化程序性能的工具,但需要合理使用,以确保代码的可维护性和性能的平衡。

6、Lambda 表达式

        Lambda 表达式是 C++11 引入的一种匿名函数的方式,它允许你在需要函数的地方内联地定义函数,而无需单独命名函数,Lambda 表达式的基本语法如下:

[capture clause](parameters) -> return_type {
    // 函数体
    // 可以使用捕获列表中的变量
    return expression; // 可选的返回语句
}

        Lambda 表达式由以下部分组成:

  • 捕获列表(Capture clause):用于捕获外部变量,在 Lambda 表达式中可以访问这些变量。捕获列表可以为空,也可以包含变量列表 [var1, var2, ...] 。
  • 参数列表(Parameters):与普通函数的参数列表类似,可以为空或包含参数列表 (param1,param2, ...) 。
  • 返回类型(Return type):Lambda 表达式可以自动推断返回类型auto,也可以显式指定返回类型 -> return_type 。如果函数体只有一条返回语句,可以省略返回类型。
  • 函数体(Body):Lambda 表达式的函数体,包含需要执行的代码。

        Lambda 表达式最简单的案例是在需要一个小型函数或临时函数时直接使用它。以下是一个非常简单的例子,其中使用 Lambda 表达式来定义一个加法操作,并立即使用它来计算两个数的和。

#include <iostream>
int main() {
    // 定义一个简单的 Lambda 表达式进行加法
    auto add = [](int a, int b) {
    return a + b;
    };

    // 使用 Lambda 表达式计算两个数的和
    int sum = add(10, 20);
    std::cout << "Sum is: " << sum << std::endl;
    return 0;
}

        在这个例子中:定义了一个名为 add 的 Lambda 表达式,它接受两个整数参数,并返回它们的和。然后,我们使用这个 Lambda 表达式来计算两个数字(10 和 20)的和,并将结果存储在变量 sum中。最后,我们打印出这个和。这个例子展示了 Lambda 表达式的基本用法:作为一种简洁而快速的方式来定义小型函数。

        可以写一个例子,其中使用一个函数来找出两个数中的较大数,这个函数将接受一个 lambda 函数作为回调来比较这两个数。Lambda 函数将直接在函数调用时定义,完全是匿名的。

#include <iostream>
// 函数,接受两个整数和一个比较的 lambda 函数
bool myCompare(int a, int b){
    return a > b;
}
int getMax(int a, int b, bool(*compare)(int, int)) {
    if (compare(a, b)) {
        return a;
    } else {
        return b;
    }
}

int main() {
    int x = 10;
    int y = 20;
    // 回调函数
    int max = getMax(x, y, myCompare);
    std::cout << "The larger number is: " << max << std::endl;
    return 0;
}

        下面使用匿名 Lambda 函数来返回两个数中的较大数,在这个例子中,getMax 函数接受两个整数 a 和 b ,以及一个比较函数 compare 。这个比较函数是一个指向函数的指针,它接受两个整数并返回一个布尔值。在 main 函数中,我们调用 getMax ,并直接在调用点定义了一个匿名的 lambda 函数。这个lambda 函数接受两个整数并返回一个表示第一个整数是否大于第二个整数的布尔值。这个 lambda 函数在 getMax 中被用作比较两个数的逻辑。根据 lambda 函数的返回值, getMax返回较大的数。

#include <iostream>
// 函数,接受两个整数和一个比较的 lambda 函数
int getMax(int a, int b, bool(*compare)(int, int)) {
    if (compare(a, b)) {
        return a;
    } else {
        return b;
    }
}

int main() {
    int x = 10;
    int y = 20;
    // 直接在函数调用中定义匿名 lambda 函数
    int max = getMax(x, y, [](int a, int b) -> bool {
        return a > b;
    });
    std::cout << "The larger number is: " << max << std::endl;
    return 0;
}

        这个例子展示了如何直接在函数调用中使用匿名 lambda 函数,使代码更加简洁和直接。这种方法在需要临时函数逻辑的场合非常有用,尤其是在比较、条件检查或小型回调中。在 Lambda 表达式中,参数捕获是指 Lambda 表达式从其定义的上下文中捕获变量的能力。这使得Lambda 可以使用并操作在其外部定义的变量。捕获可以按值(拷贝)或按引用进行。在这个例子中,第一个 Lambda 表达式 sum 按值捕获了 x 和 y (即它们的副本)。这意味着 sum 内的 x 和 y是在 Lambda 定义时的值的拷贝。第二个 Lambda 表达式 multiply 使用 [=] 捕获列表,这表示它按值捕获所有外部变量。第三个 Lambda 表达式 modifyAndSum 使用 [&] 捕获列表,这表示它按引用捕获所有外部变量。因此,它可以修改 x 和 y 的原始值。这个示例展示了如何使用不同类型的捕获列表(按值和按引用)来控制 Lambda 表达式对外部变量的访问和修改。按值捕获是安全的,但不允许修改原始变量,而按引用捕获允许修改原始变量,但需要注意引用的有效性和生命周期问题。

#include <iostream>
int main() {
    int x = 10;
    int y = 20;
    // 捕获 x 和 y 以便在 Lambda 内部使用
    // 这里的捕获列表 [x, y] 表示 x 和 y 被按值捕获
    auto sum = [x, y]() {
        // x++;
        // y++; 按值捕获,关注的是值本身,无法修改
        return x + y;
    };
    std::cout << "Sum is: " << sum() << std::endl;
    std::cout << "x is now: " << x << ", y is now: " << y << std::endl;
    // [=]捕获所有外部变量按值捕获(拷贝)
    int z = 30;
    auto multiply = [=]() {
        // x++;
        // y++; 按值捕获,关注的是值本身,无法修改
        return x * y * z;
    };
    count << x << "," << y << endl;
    std::cout << "Product is: " << multiply() << std::endl;
    std::cout << "x is now: " << x << ", y is now: " << y << std::endl;
    // 捕获所有外部变量按引用捕获,类似指针,进行地址访问
    auto modifyAndSum = [&]() {
        x = 15; // 修改 x 的实际值
        y = 25; // 修改 y 的实际值, 引用捕获可以修改
        return x + y;
    };
    std::cout << "Modified Sum is: " << modifyAndSum() << std::endl;
    std::cout << "x is now: " << x << ", y is now: " << y << std::endl;
    return 0;
}

        以下是一个表格,概述了 Lambda 函数和内联函数在 C++ 中的相似之处和区别:

特性 Lambda 函数 内联函数
定义 一种匿名函数,通常用于定义在需要它们的地方。 一种常规函数,通过 inline 关键字定义。
用途 提供一种快捷方式来定义临时的、小型的函数。 用于优化小型函数,减少函数调用的开销。
语法 使用 [capture](params) { body }的形式定义。 使用常规函数定义语法,但在前面加上inline 关键字。
生命周期 在定义它们的作用域内有效 在整个程序执行期间有效。
捕获外变量 可以捕获外部作用域中的变量(按值或按引用)。 不能直接捕获外部变量,只能通过参数传递。
调用方式 作为函数对象,可直接调用 像普通函数一样调用。
优化 可以被编译器自动内联化,但这取决于编译器优化策略。 明确请求编译器尝试内联,但实际内联化也取决于编译器。
可见性 通常只在定义它们的局部作用域内可见 可以在定义它的任何作用域内可见。
使用场景 适合于一次性使用的场景,如作为回调、在算法中使用等。 适合于频繁调用的小型函数。

        请注意,虽然 Lambda 函数和内联函数在某些方面有相似之处,如它们都可以被编译器优化以减少调用开销,但它们在设计和用途上有明显的不同。Lambda 函数的核心优势在于它们的匿名性和对外部变量的捕获能力,而内联函数则主要关注于提高小型函数的性能。

7、数组

        在 C++ 中,数组是一种存储固定大小的相同类型元素的序列。数组的所有元素都存储在连续的内存位置上。这种数据结构非常适合于存储具有固定数量和相同数据类型的元素集合。声明数组的基本语法如下:

数据类型 数组名[数组大小];

        例如,声明一个类型为 int 的数组,包含 10 个元素:

int myArray[10];

        【初始化数组】在声明数组时,您可以同时初始化数组:

int myArray[5] = {10, 20, 30, 40, 50};

        如果您在初始化数组时没有指定所有元素的值,未初始化的元素将被自动设置为该数据类型的默认值(对于基本数据类型通常是 0):

int myArray[5] = {10, 20}; // 其余元素将被初始化为 0

        【访问数组元素】您可以通过指定索引来访问数组中的元素。数组索引是从 0 开始的,所以数组的第一个元素是 数组名[0] ,第二个元素是 数组名[1] ,依此类推:

int value = myArray[2]; // 访问第三个元素
#include <iostream>

using namespace std;

int main() {
    int myArray[5] = {10, 20, 30, 40, 50};
    // 输出所有数组元素的值
    for(int i = 0; i < 5; ++i) {
        cout << "Element at index " << i << ": " << myArray[i] << endl;
    }
    return 0;
}
  • 数组的大小必须在编译时已知,且不能更改。
  • 数组索引越界是常见的错误,可能会导致未定义的行为。
  • 对于更复杂的用例,您可能需要使用 C++ 的标准模板库(STL)中的容器,如 std::vector ,它提供了可以动态改变大小的数组。
  • 数组的元素存储在连续的内存位置上,这使得访问数组元素非常快。

8、指针

        C++完全兼容C语言指针,多出一个this指针,在面向对象中再讲解。

#include <iostream>
using namespace std;

void swap(int *pa, int *pb)
{
    int tmp;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}

int main() {
    int a = 10;
    int b = 20;
    cout << a << endl;
    cout << b << endl;
    cout << "after chage:" << endl;
    swap(&a,&b);
    cout << a << endl;
    cout << b << endl;
}

9、字符串string类型

        C语言中对字符串的表示通常用指针,新手会面临内存泄漏或者段错误等众多问题。在 C++ 中, string 类是标准库的一部分,用于表示和操作字符串。它是对传统的 C 风格字符串(以空字符 '\0' 结尾的字符数组)的一个更安全、更方便的封装。string 类是在 <string> 头文件中定义的,并且位于 std 命名空间中。string 类提供了许多有用的功能和特性,包括:

  • 动态大小:与 C 风格的字符串不同, string 对象可以动态改变大小,这意味着你可以在运行时添加或移除字符,而不需要担心分配和释放内存。
  • 安全性:由于 string 管理其自己的内存,因此减少了内存泄漏和缓冲区溢出的风险。
  • 方便的成员函数: string 类提供了各种操作字符串的方法,如 append() (添加)、insert()(插入)、erase() (删除)、substr() (获取子字符串)等。
  • 操作符重载: string 类重载了多个操作符,使得字符串比较、连接和赋值更加直观。例如,你可以使用 + 操作符来连接两个字符串,或者使用 == 操作符来比较两个字符串是否相等。
  • 迭代器支持:像其他标准库容器一样, string 类也支持迭代器,使得你可以使用迭代器来遍历字符串中的字符。
  • 与 C 风格字符串的兼容性: string 类提供了与 C 风格字符串互操作的功能,例如,你可以使用c_str() 方法来获取一个与 C 风格字符串兼容的、以 null 结尾的字符数组。

        下面是一个简单的 string 类的使用示例,在这个示例中,我们创建了一个 string 对象 str ,然后使用不同的方法对其进行操作。这展示了string 类的灵活性和强大功能。

#include <iostream>
#include <string>

int main() {
    std::string str = "Hello, world!";
    std::cout << str << std::endl; // 输出字符串
    str += " I am a C++ string."; // 字符串连接
    std::cout << str << std::endl;
    std::string substr = str.substr(7, 5); // 获取子字符串
    std::cout << "Substring: " << substr << std::endl;
    return 0;
}

        下面是一个表格,展示了 C++ 中 std::string 类的一些常用成员函数及其功能和参数,这些函数是 std::string 类中常用的一部分,提供了强大且灵活的字符串操作能力。使用这些函数可以方便地处理和修改字符串数据。

函数名 功能 参数 返回值类型
length() 或 size() 返回字符串的长度 size_t
empty() 检查字符串是否为空 bool
append(const string& str) 向字符串末尾添加另一个字符串 要追加的字符串 string&
substr(size_t pos = 0, size_t len = npos) 返回一个子字符串 pos :子字符串的起始位置
len :子字符串的长度
string
find(const string& str, size_t pos = 0) 查找子字符串出现的位置 str :要查找的字符串
pos :搜索起始位置
size_t
compare(const string& str) 比较两个字符串 要比较的字符串 int
erase(size_t pos = 0, size_t len = npos) 删除字符串中的一部分 pos :起始位置
len :要删除的长度
string&
insert(size_t pos, const string& str) 在指定位置插入字符串 pos :插入位置
str :要插入的字符串
string&
replace(size_t pos, size_t len, const string& str) 替换字符串中的一部分 pos :起始位置
len :要替换的长度
str :替换的字
符串
string&
c_str() 返回 C 风格字符串表示 const char*
operator[] (size_t pos) 访问指定位置的字符 pos :字符位置 char&

三、小练习

1、计算器支持加减乘除

#include <iostream>
using namespace std;
int add(int a,int b)
{
    return a+b;
}
int min(int a,int b)
{
    return a-b;
}
int mul(int a,int b)
{
    return a*b;
}
float divRet(int a,int b)
{
    return (float)a/b;
}
int main() {
    int a;
    int b;
    char calWay;
    while(1){
        cout << "请输入两个数:"<< endl;
        cin >> a;
        cin >> b;
        cout<<"请输入运算符号:+ - * /" <<endl;
        cin >> calWay;
        switch(calWay){
            case '+':
                printf("两数之和是%d\n",add(a,b));
                break;
            case '-':
                printf("两数之差是%d\n",min(a,b));
                break;
            case '*':
                printf("两数之积是%d\n",mul(a,b));
                break;
            case '/':
                printf("两数之余是%f\n",divRet(a,b));
                break;
            default:
                printf("运算符输入错误,请重新输入\n");
        }
    }
}
#include <iostream>
using namespace std;

int calculator(int a, int b, int (*p)(int a, int b))
{
    cout << "开始计算" << endl;
}

int main()
{
    int a = 0;
    int b = 0;
    char cal;
    while(1){
        cout << "请输入两个数:" << endl;
        cin >> a;
        cin >> b;
        cout << "请输入运算符+,-,*,/" << endl;
        cin >> cal;
        switch(cal){
            case '+':
                cout << calculator(a,b,[](int a, int b){return a + b;}) << endl;
                break;
            case '-':
                cout << calculator(a,b,[](int a, int b){return a - b;}) << endl;
                break;
            case '*':
                cout << calculator(a,b,[](int a, int b){return a * b;}) << endl;
                break;
            case '/':
                cout << calculator(a,b,[](int a, int b){return a / b;}) << endl;
                break;
        }
    }
    return 0;
}

2、数组找最大值

#include <iostream>
using namespace std;

void initArry(int *arry, int len)
{
    for(int i=0; i< len; i++){
        cout << "请输入第" << i+1 << "个数" << endl;
        cin >> arry[i];
    }
}

void printArry(int *arry,int len)
{
    for(int i=0; i< len; i++){
        cout << arry[i] << endl;
    }
}
int getMaxFromArray(int *arry, int len )
{
    int maxTmp = arry[0];
    for(int i=0; i< len; i++){
        if(maxTmp < arry[i])
        maxTmp = arry[i];
    }
    return maxTmp;
}
int main() {
    int arry[5];
    int len = sizeof(arry)/sizeof(arry[0]);
    initArry(arry,len);
    printArry(arry,len);
    cout << "最大数是:" << getMaxFromArray(arry,len);
}

更多推荐