C++中的一些困惑(长期更新中)

C++中的一些困惑

文章目录

  • C++中的一些困惑
    • [1. using std::具体命名与using namespace std;](#1. using std::具体命名与using namespace std;)
    • [2. 【int \*p[10] 】与 【int (\*p)[10]】](#2. 【int *p[10] 】与 【int (*p)[10]】)
    • [3. main()函数可带参,参从何来?](#3. main()函数可带参,参从何来?)
    • [4. constexpr函数的返回值可不为常量,那这时constexpr关键字作用是什么?](#4. constexpr函数的返回值可不为常量,那这时constexpr关键字作用是什么?)
    • [5.为什么C++ STL不提供任何"树"容器?](#5.为什么C++ STL不提供任何“树”容器?)
    • [6. 函数参数后面的`const`](#6. 函数参数后面的const)

这是个人笔记,记录一些学习过程中没有理解以及容易混淆的问题与解答

1. using std::具体命名与using namespace std;

在C++中,使用 usingusing namespace 都是用来简化代码中命名空间的写法,但它们有不同的影响和使用场景,各有优劣:

  1. using std::具体命名

    • 优势:精确导入了命名空间中的特定名称,可以避免命名冲突,提高代码的可读性和可维护性。
    • 劣势:需要逐个导入每个需要使用的名称,可能会显得冗长,尤其是当需要导入多个名称时。

    cppCopy codeusing std::vector;
    using std::cout;
    using std::endl;

    int main() {
    vector<int> nums = {1, 2, 3};
    cout << "Hello, world!" << endl;
    return 0;
    }

  2. using namespace std;

    • 优势:一次性导入了整个 std 命名空间中的所有名称,可以方便地使用标准库中的各种功能,节省了代码中重复写命名空间的时间和空间。
    • 劣势:可能会引入命名冲突,尤其是当在代码中使用了其他命名空间或自定义了相同名称的变量或函数时,容易导致代码混乱和不可预测的行为。

    cppCopy codeusing namespace std;

    int main() {
    vector<int> nums = {1, 2, 3};
    cout << "Hello, world!" << endl;
    return 0;
    }

总体来说:推荐使用 using std::具体的类型 的方式来导入特定的名称,因为它可以明确指定要导入的内容,避免了潜在的命名冲突问题,同时保持了代码的清晰性和可维护性。而在大型项目或者有多个命名空间交叉的情况下,最好避免使用 using namespace std; 这样的全局命名空间导入方式,以免引起不必要的麻烦。

2. 【int *p[10] 】与 【int (*p)[10]】

  1. int *p[10]
    • 这表示 p 是一个数组,包含了 10 个元素。
    • 每个元素都是一个指向 int 类型的指针。
    • 可以直接通过索引来访问数组中的指针,如 p[0] 表示数组的第一个指针。
cpp 复制代码
int *p[10];  // p 是一个数组,包含了 10 个指向 int 的指针
  1. int (*p)[10]
    • 这表示 p 是一个指针,指向一个包含 10 个整数的数组。
    • p 指向的整个数组是一个单独的对象,而不是一个指向指针的数组。
    • 需要通过解引用来访问指针指向的数组元素,如 (*p)[0] 表示指针 p 所指向数组的第一个元素。
cpp 复制代码
int (*p)[10];  // p 是一个指针,指向一个包含 10 个整数的数组

举个例子来比较两者的使用:

cpp 复制代码
int main() {
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    int *p1[10];  // 数组,包含 10 个指向 int 的指针
    p1[0] = arr;  // 将数组 arr 的首地址赋给 p1 的第一个指针

    int (*p2)[10];  // 指针,指向包含 10 个整数的数组
    p2 = &arr;  // 将数组 arr 的地址赋给 p2

    // 使用 p1 访问数组元素
    for (int i = 0; i < 10; ++i) {
        std::cout << *(p1[0] + i) << " ";  // 输出数组元素
    }

    std::cout << std::endl;

    // 使用 p2 访问数组元素
    for (int i = 0; i < 10; ++i) {
        std::cout << (*p2)[i] << " ";  // 输出数组元素
    }

    return 0;
}

在上面的例子中,p1 是一个数组,包含了 10 个指向 int 的指针,而 p2 是一个指针,指向一个包含 10 个整数的数组。这两者的使用方式略有不同,因为 p1 中的每个元素都是指针,而 p2 指向的是整个数组对象。

3. main()函数可带参,参从何来?

在 C++ 中,main 函数可以具有带参数的形式,这些参数通常用于接收命令行参数。这些参数是由操作系统在程序启动时传递给程序的,并且可以在 main 函数的参数列表中接收到。

标准的 main 函数的声明有两种形式:

cpp 复制代码
int main()

或者

cpp 复制代码
int main(int argc, char* argv[])

第一种形式是不带参数的,程序启动时不会接收任何命令行参数。第二种形式是带参数的,其中 argc 表示命令行参数的数量,argv 是一个指向字符指针数组的指针,每个指针指向一个命令行参数的字符串。

  • argc(argument count)表示命令行参数的数量,包括程序名称在内。
  • argv(argument vector)是一个指针数组,每个元素指向一个命令行参数的字符串,其中 argv[0] 通常是程序的名称,argv[1]argv[2] 等依次是传递给程序的其他命令行参数。

例如,以下是一个简单的示例:

cpp 复制代码
#include <iostream>
#include <string>

// 编写一个带实参的main函数并运行
int main(int argc, char* argv[]) {
    // 确保有足够的实参
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " <arg1> <arg2>" << std::endl;
        return 1;  // 返回非零值表示错误退出
    }

    // 将实参连接成一个字符串
    std::string result = std::string(argv[1]) + " " + std::string(argv[2]);

    // 输出连接后的字符串
    std::cout << "Concatenated string: " << result << std::endl;

    return 0;
}

在VS code中编译运行:

  1. 打开Terminal,使用命令行编译源文件

    g++ -o  生成的程序名(如:myprogram)  源文件.cpp
    
  2. 编译器会生成一个名为myprogram的可执行文件

  3. 在终端运行程序并传参

    ./myprogram hello world
    

执行过程及结果:

4. constexpr函数的返回值可不为常量,那这时constexpr关键字作用是什么?

虽然constexpr函数的返回值并非总是常量,但使用constexpr关键字可以告诉编译器,希望在可能的情况下在编译期间进行求值和优化 。这样可以使代码更加灵活并提高性能,特别是在一些需要进行编译期间计算的场景下,constexpr函数非常有用。

进一步解释:

  • 某些场景下,函数的返回值仍然可以再编译期间确定。(通常是因为函数的输入参数是常量表达式,或者函数内部只包含了可以在编译期间计算的操作),如:
cpp 复制代码
#include <iostream>

// constexpr函数,参数是常量表达式
constexpr int add(int a, int b) {
    return a + b;
}

int main() {
    // 在编译期间就可以计算出结果
    // 因为输入参数是常量表达式 
    constexpr int result = add(10, 20);

    std::cout << "Result: " << result << std::endl;
    return 0;
}

5.为什么C++ STL不提供任何"树"容器?

一个讨论:https://www.codenong.com/205945/

6. 函数参数后面的const

cpp 复制代码
void func() const {};

是常量成员函数,即在函数内部不会修改对象的成员变量。

endl;

return 0;

}

## 5.为什么C++ STL不提供任何"树"容器?

一个讨论:https://www.codenong.com/205945/

## 6. 函数参数后面的`const`

```cpp
void func() const {};

是常量成员函数,即在函数内部不会修改对象的成员变量。

相关推荐
蒟蒻的贤40 分钟前
vue11.22
开发语言·前端·javascript
程序员与背包客_CoderZ1 小时前
C++设计模式——Abstract Factory Pattern抽象工厂模式
c语言·开发语言·c++·设计模式·抽象工厂模式
Mike_188702783511 小时前
深入探索Golang的GMP调度机制:源码解析与实现原理
开发语言·后端·golang
SoraLuna1 小时前
「Mac玩转仓颉内测版32」基础篇12 - Cangjie中的变量操作与类型管理
开发语言·算法·macos·cangjie
2402_839708051 小时前
第十章:作业
开发语言·前端·javascript
东方巴黎~Sunsiny1 小时前
给定数字 [3, 30, 34, 5, 9] 拼接成的最大数字,使用java实现
java·开发语言
焦糖酒1 小时前
JS精进之Hoisting(提升)
开发语言·前端·javascript
daiyang123...1 小时前
Java 复习 【知识改变命运】第九章
java·开发语言·算法
fancc椰1 小时前
C++基础入门篇
开发语言·c++
不7夜宵1 小时前
Golang 反射
开发语言·后端·golang