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

C++中的一些困惑

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

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

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

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

int main() {
    vector<int> nums = {1, 2, 3};
    cout << "Hello, world!" << endl;
    return 0;
}
  1. using namespace std;
    • 优势:一次性导入了整个 std 命名空间中的所有名称,可以方便地使用标准库中的各种功能,节省了代码中重复写命名空间的时间和空间。
    • 劣势:可能会引入命名冲突,尤其是当在代码中使用了其他命名空间或自定义了相同名称的变量或函数时,容易导致代码混乱和不可预测的行为。
using 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] 表示数组的第一个指针。
int *p[10];  // p 是一个数组,包含了 10 个指向 int 的指针
  1. int (*p)[10]
    • 这表示 p 是一个指针,指向一个包含 10 个整数的数组。
    • p 指向的整个数组是一个单独的对象,而不是一个指向指针的数组。
    • 需要通过解引用来访问指针指向的数组元素,如 (*p)[0] 表示指针 p 所指向数组的第一个元素。
int (*p)[10];  // p 是一个指针,指向一个包含 10 个整数的数组

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

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 函数的声明有两种形式:

int main()

或者

int main(int argc, char* argv[])

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

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

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

#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
    

执行过程及结果:

image-20240313204143778

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

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

进一步解释:

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

void func() const {};

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

  • 33
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值