《C++ Prime Plus》(2)

不是所有的字符数组都叫字符串

 字符串以空字符'\0'结尾,而字符数组的最后一个字符不一定是空字符。因此不是所有的字符数组都能称为字符串。字符串以'\0'结尾,这一点很重要,因为许多涉及到字符串的操作都是读到空字符为止。

 在初始化字符数组时,若赋值长度小于数组长度,则后续字符会被默认填上空字符:

1
2
char str[5] = {'h', 'i'};
// str[] = {'h', 'i', '\0', '\0', '\0'};

 此外,在使用strlen()计算字符串长度时,空字符是不计入长度的。

 如果要将一个字符串型变量赋值给一个字符数组,最好不要用=直接赋值,而应该使用strcpy()strncpy()。因为,当字符串中字符长度大于字符数组长度时,多出来的字符会自动填充到字符数组后面的内存地址中,从而带来隐蔽的问题。当使用strncpy()时,可以指定第三个参数——长度参数来控制赋值长度以避免上述问题。

get()和getline():我们不一样

 简而言之,get()识别换行符,getline()将换行符自动丢弃。使用getline读入一行字符到换行符为止并丢弃换行符,而get读入一行后保留换行符。如果使用get读入连续的几行,则需要在中间额外使用一次无参的get()以消耗掉换行符。get()输入的优点是更加精细。

 当混合输入数字和字符串时会出现一种典型错误:

1
2
3
4
5
int m;
cin >> m;
string s;
getline(cin, s);
cout << s << endl; // s = '\n'

 这是由于在输入整数并换行时,换行符隐藏在输入流中,这样后续再次以字符串形式去读入时,就直接获得了缓冲区中的换行符,导致了错误。

指针变量和数组名常量

 C++认为数组名等同于数组地址,另一方面如果用指针指向一个数组,那么也可以按照数组名的用法来使用这个指针名。二者的区别是:当数组名作为数组地址时它表示的是一个地址常量,不可更改;而指针作为地址变量是可以更改的。

输出bool型变量的值

 对于一个bool型变量,用cout进行输出时通常会显示01。如果我们希望输出形式为truefalse,则应该先调用以下语句:

1
cout.setf(ios_base::boolalpha);

for语句中自增前缀&后缀的效率

 对于以下两条语句:

1
2
for(int i=0; i<maxn; i++);
for(int i=0; i<maxn; ++i);

 其执行结果完全一样,但是后者——也即前缀版本在某些情况下执行速度更快。对于有用户定义且有用户定义的自增自减操作符的类型而言,前缀类型直接将值加一返回;后缀类型先复制一份拷贝,将其加一,再返回复制的拷贝。这种情况下前缀类型效率较高。除此之外,对于内置的类型,不存在这种差别。

语句块

 C++中用{}包含起来的多条语句称为语句块,语句块像是代码中独立开辟出来的一片空间。对于以下语句:

1
2
3
4
5
6
7
int x = 0;
{
cout << x << endl; // 输出0
int x = 1;
cout << x << endl; // 输出1
}
cout << x << endl; // 输出0

 可见,语句块内部变量的作用域为从该变量声明开始到语句块结尾。

表达式的值

 每个C++表达式都有值。C++将赋值表达式的值定义为左侧成员的值;逗号表达式的值为最后一个分句的值。

字符数组型字符串的比较

 C++引入string型变量来处理字符串,但是C中包含了字符数组存储的字符串类型。如何比较字符数组存储的字符串是否相等呢?这里有一个隐藏的误区,试看以下代码:

1
2
3
4
5
char word[] = {'d', 'o', 'g'};
if(word == "dog")
cout << "Equal" << endl;
else
cout << "Not equal" << endl;

 可想而知,程序无法正常输出“Equal”。其原因在于,C风格的字符数组将数组名作为地址常量来使用,因此上述if条件语句中的判断项比较的是地址而非字符数组内容。

clock()函数

 函数原型:clock_t clock(void);,用于返回该程序自执行起所用系统时间。两个问题,其一clock()的返回值不一定以秒为单位,其二返回类型在不同机器上可能有不同类型。

 对于问题一,通过在头文件中包含ctime文件可以使用符号常量CLOCKS_PER_SEC,它表示每秒包含的系统单位时间数。用clock()返回的值除以这个常量就能得到秒数。

 对于问题二,通过使用类型别名clock_t可以实现程序的跨平台移植而不必担心不同机器上类型长度不一的问题。C++中创建类型别名有两种方式:(1)使用#define来预定义替换,但是这样会带来潜在的问题,如:

1
2
3
#define int_pointer int *

int_pointer p1, p2; // 相当于: int *p1, p2; 不符合预期

 (2)使用typedef来起别名就不会出现上述问题,有时这种方法也是唯一可选的方法。

cin和cin.get(char)的区别

 一言蔽之,使用cin读取字符时将自动忽略空格符和换行符,而cin.get(char)则如实读入每一个遇到的字符。cin.get()有两种参数列表,除了以char型字符为参数外,还有cin.get(char* name, int size)的调用格式,意为从地址name中读取size个字符。


转载请注明来源:©Tinshine