接上篇 [C++ 笔记] C 语法扩展, 内容太多就分成两篇了。(顺带可以多水一篇文章

# 内存四区

  • 栈 Stack:编译器自动分配释放
  • 堆 Heap:程序员手动分配释放,结束时 OS 回收未释放的部分
  • 全局区 / 静态区 Global / Static:全局 / 静态变量,程序结束时释放
  • 常量区 Const:不可修改

# 常量与指针

# 常量

声明: const Type const_name = value 其中 const 与 Type 可互换位置。

ex: const char* STR = "Hello"; 不加 const 会报错 *(试出来是 warning?)*,因为 "Hello" 存放在常量区,指针要指向常量区。(可以看下面 qwq)

# 指针

开始念咒.... 常量指针,指针常量,常量指针常量... 阿巴阿巴 (º﹃º)

其实就是 const 离谁近修饰谁

// 指针
int x = 5;
int *p = &x;
// 常量指针 (常指针)
const int x = 5;
const int* p = &x; //const 修饰 int*
// 指针常量
int x = 5;
int* const p = &x; //const 修饰 p
// 常量指针常量
const int x = 5; // 似乎不写 const 也可
const int* const p = &x; // 不能通过 * p 修改 x 的值,且不能修改 p 的值
int x = 2;
auto p1 = &x; //p1 类型 int*
auto p2 = "qwq"; //p2 类型 const char*
auto const p3 = "owo"; //p3 类型 const char* const

# 各种宏定义

  • #define: 仅用于替换 #define macro_name sth.

  • typedef: 创建代替类型名的别名 Typedef Type NewTypeName

  • using 替代 typedef: using identifier = type-id

    只能用于类型, using in = std::cin 报错,因为 cin 是类。

    实例:

    using ull = unsigned long long;
    ull x = 233u;
    using Fptr = void(*)(int, int); // 函数指针
    void example(int, int){...};
    Fptr fp = example;

    定义模板的别名,只能使用 using

# 变量作用域

# 局部作用域

文件作用域、函数作用域以及函数内部的块作用域。

就近原则:作用域不同的同名变量,优先使用作用域小的。

实例:

#include <iostream>
using namespace std;
int a = 3;
int main()
{
    int a = 2;
    cout << a << endl; // 2
    return 0;
}

# 一元作用域解析运算符

局部变量与全局变量同名时,使用 :: 访问全局变量

实例:

#include <iostream>
using namespace std;
int a = 3;
int main()
{
    int a = 2;
    cout << a << ' ' << ::a << endl; // 2, 3
    return 0;
}

# 函数相关

# 重载函数 Overloading Funcitons

假设已定义函数 int mx(int, int) 再定义 double mx(double, double) (一个同名不同参的函数),调用函数 mx(v1, v2) 时:

编译器仅通过参数来匹配重载函数的调用,优先级:

  1. 参数个数
  2. 参数类型
  3. 不同类型参数顺序

实例:

#include <iostream>
using namespace std;
int mx(int num1, int num2)
{
    return num1 > num2 ? num1 : num2;
}
double mx(double num1, double num2)
{
    return num1 < num2 ? num1 : num2;
}
int main()
{
    cout << mx(2, 3) << endl; //3
    cout << mx(2.0, 3.0) << endl; //2
    cout << mx(2.0, 3) << endl; // 报错
    return 0;
}

二义调用会导致编译错误,例如 int fun(int, double)double fun(double, int) ,调用 fun(1, 2) 时会报错。又例如同时声明 int fun(int, int)void fun(int, int) 编译器报错。

# 带有默认参数值的函数

Type Fun(v1, v2, v3 = , v4 = ) 之类的写法。例如左边,调用时可传递 2 ~ 4 个参数,未接收实参的形参有默认值。

需要注意的是带有默认值的参数在右边传递实参时依次传给左边

实例:

#include <iostream>
using namespace std;
int mx(int a, int b = 3)
{
    return a > b ? a : b;
}
int main()
{
    cout << mx(2) << endl; // 3
    cout << mx(2, 4) << endl; // 4
    return 0;
}

# 默认参数与重载

函数重载时,不允许重定义默认参数

以下实例均为错误:

double area(double r = 1){...}
double area(int r = 2){...}
----
int add(int x, int y = 3)
{
	return x + y;
}
int add(int x)
{
    return x + 3;
}
add(x);

反正一般编译器搞不定的这种问题都会报错 qwq

# 内联函数 inline

一句话:用空间换取时间。

声明方法: inline Fun(...){...} , 内联函数定义与声明一般不分开。

仅适用于频繁调用的短函数,是对编译器的建议,并不一定都会进行内联编译 (循环,递归,静态变量等)。

# 函数后加 const

引用一段话:原文链接

我们定义的类的成员函数中,常常有一些成员函数不改变类的数据成员,也就是说,这些函数是 "只读" 函数,而有一些函数要修改类数据成员的值。如果把不改变数据成员的函数都加上 const 关键字进行标识,显然,可提高程序的可读性。其实,它还能提高程序的可靠性,已定义成 const 的成员函数,一旦企图修改数据成员的值,则编译器按错误处理。

# 基于范围的 for 循环

python 党狂喜 文明进化的象征!😆😆😆

语法: for (元素名变量 : 广义集合) {循环体}

广义集合例子:

auto a1[]{1, 3, 5, 7}; // 不再推荐使用原始数组
std::array <int, 4> a2{2, 4, 6, 8};
std::vector <int> v = {2, 3, 3};
std::vector <std::string> s{"qwq", "owo"};

要对广义集合里的元素进行操作,需要使用引用。

实例:打印数组 a 元素并将其翻倍。

int a[]{2, 3, 3}; // 写 auto 会报错 qwq
for (auto i : a)
    cout << a << endl;
for (auto& i : a)
    i *= 2;

# 带有初始化器的 if 和 switch [C++17]

熟悉的初始化器: for (initializer; condition ; increment)

然后 ifswitch 也能用: if (initializer; condition) switch(initializer; condition)

实例:

int main()
{
    // 比起原先在外面定义 x,改变了作用域
    if (auto x =  fun(233); x > 123)
    {
        //do something with x
    }
    else
    {
        //do something with x
    }
    auto x = 233; // 此处变量名 x 可重用
}

# 常量表达式

编译期就可以计算值的表达式,由编译器计算。

const 修饰的对象未必是编译期常量,例如: const int MAXN = n;

使用 constexpr 关键字声明常量表达式。(C++11)

声明数组时,大小必须是常量表达式。

区别:

constconstexpr
告知程序员 被修饰变量不能修改,避免 bug。修饰的表达式可以在编译期计算得到值,用于性能优化。

# 断言与静态断言

# 断言

检测假设成立与否的语句,不成立时提出警告信息。

assert 关键字:C 语言的宏,运行时检测。(不是函数,下 static_assert 同)

  • #include <cassert>调试模式编译程序。
  • assert(bool_expr) 表达式为假则中断程序,报错。
  • 帮助解决逻辑错误。 (GDB 不香吗 qwq -> assert 可以在写程序时,在潜在的问题上写一下 assert)

例如: assert((i > 0) && "i must be positive");

# 静态断言

static_assert:几乎用不上,为写库的开发带师准备。 编译时断言检查。

用法: static_assert (bool_constexpr, message) 可转为 bool 的编译期常量表达式,报错信息。

大学四年真的会用到这东西吗 QwQ?

更新于