跳转至

前置知识

在 Win32 程序中使用了许多在 OI 中很难涉及的东西,因此需要补充前置知识。

指针

指针的 const 修饰

const 可以修饰数据类型,也可以修饰指针变量。

常量指针(修饰数据类型)

const 修饰数据类型时,指针指向的地址可以改变,但指针指向的地址所对应的内容不可以改变。

1
2
3
4
int a = 0, b = 0;
const int *p = &a;
*p = 1; // 错误
p = &b; // 正确

指针常量(修饰指针变量)

const 修饰指针变量时,指针指向的地址不可以改变,但指针指向的地址所对应的内容可以改变。

1
2
3
4
int a = 0, b = 0;
int *const p = &a;
*p = 1; // 正确
p = &b; // 错误

Tip

修饰指针变量时,*const 只作用于后面的变量,如果有 int *const p = &a, c = 0;,那么 c 只是一个 int 型的变量;修饰数据类型时,const 作用于数据类型,可以作用于同一个语句中定义的所有变量,即 const int *p = &a, c = 0;c 的数据类型为 const int

值得注意的是,const intint const 等价,即 int const a = 0, b = 0;ab 都是 const int 类型。

指针的 typedef

指针的 typedef 写作 typedef int *Pint;,在声明变量时,Pint p; 就和 int *p; 等价了。同样,若 typedef const int *Pint;,则 Pint p;const int *p; 等价;若 typedef int *const Pint;,则 Pint p;int *const p; 等价。值得注意的是,若 typedef int *Pint;,则 const Pint p;Pint *const p; 等价。

至于 const 的作用范围,typedef const int *Pint, tni;const 修饰 int,即 tniconst int 类型;typedef int *const Pint, tni;*const 修饰 Pint,即 tniint 类型。

const_cast

当你写下这样的语句:

1
2
typedef char* STR;
STR str = "!!!";

你会发现在 G++ 中有这样的警告:ISO C++ forbids converting a string constant to 'STR' {aka 'char*'},而在 MSVC 中过不了编译。这是因为我们将一个字符串常量赋值给了一个字符串变量。正确的赋值方法是这样:

1
2
typedef char* STR;
STR str = const_cast<STR>("!!!");

switch 语句

你可能会问,这有什么好讲的呢?

switch 语句实际上相当于一个 goto,会从一个符合条件的 case 标记后运行。这也就解释了需要 break 的原因,因为 case 就相当于是一个 goto 的标记,程序是跳转到 case 后并一直向后运行的,因此如果不 break 就会运行到后面不应该运行的代码。

值得注意的是,如果 goto 到了一个变量的作用域中,这个程序非良构,switch 也是同理,例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
switch (n) {
case 1:
    int x = 1;
    break;

case 2:
    break;

default:
    break;
}

在这个例子中,变量 x 的作用域是整个 switch 语句,但如果 n 的值不是 \(1\),就会跳过 x 的定义。此时 g++ 会给你一个警告,但 MSVC 甚至不会让你通过编译。所以在使用 switch 语句时,一定要注意限制定义在 switch 语句内变量的作用域,就像这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
switch (n) {
case 1: {
    int x = 1;
    break;
}

case 2:
    break;

default:
    break;
}