1. 对于float,C++只保证6位有效位,如果需要更高的精度,使用double或long double。
2. 类型转换:对不同类型进行运算时,C++将把它们转换为同一类型。
(1)浮点常量在默认情况下为double类型。
(2)将浮点型转换为整型时,C++采取截取(丢弃小数部分)而不是四舍五入。
3. 求模运算符返回整数除法的余数,它与整数除法相结合,尤其适用于解决要求将一个量分成不同整数单元的问题。例如将英寸转换为英尺和英寸。
4. sizeof是C++的一个操作符,作用是返回一个对象或者类型所占用的内存字节数。其计算发生在编译时刻,因此可以被当作常量表达式使用。如果将sizeof用于数组名,返回的是整个数组的长度(字节数),而sizeof用于数组元素,返回的是这个元素的长度。
5. strlen()函数返回的是存储在数组中字符串的长度,而不是数组本身的长度。且只计算可见的字符,不把空字符'\0'计算在内。如果cosmic是字符串,则存储此字符串的数组长度不能小于strlen(cosmic)+1。
6. cin使用空白(空格、制表符和换行符)来确定字符串的结束位置,这意味着cin在获取字符数组输入时只读取一个单词,将其放到数组中,并自动在结尾添加空字符。
7. istream中的类(如cin)提供了一些面向行的类成员函数:getline()和get()。这俩函数都读取一行输入,直到到达换行符。区别是,getline()将丢弃换行符,而get()将换行符保留在输入序列中。
(1)面向行的输入:getline()。调用方法:cin.getline()
该函数包含两个参数,第一个参数用来存储输入行的数组的名称,第二个参数指出要读取的字符数,如果此参数为20,则最多读取19个字符,余下的空间用于存储在结尾自动添加的空字符。getline()成员函数在读取指定数目的字符或遇到换行符时停止读取。
// instr2.cpp -- reading more than one word with getline
#include <iostream>
int main()
{
using namespace std;
const int ArSize = 20;
char name[ArSize];
char dessert[ArSize];
cout << "Enter your name: \n";
cin.getline(name, ArSize); //reads through newline
cout << "Enter your favorite dessert: \n";
cin.getline(dessert, ArSize);
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
return 0;
}
(2)面向行的输入:get()
使用不带任何参数的cin.get()调用可读取下一个字符(即使时换行符)。注意,get()函数在调用后,会将换行符留在输入队列里。注意采用下面的调用序列:
cin.get(name, ArSize);
cin.get();
cin.get(dessert, ArSize);
另一种使用get()的方式是将两个类成员函数拼接起来:
cin.get(name, ArSize).get();
这是由于cin.get(name, ArSize)返回一个cin对象,该对象随后呗用来调用get()函数。同样,下面的语句用来将输入中连续的两行分别读入数组name1和name2中,其效果与两次调用cin.getline()相同:
cin.getline(name1, ArSize).getline(name2, ArSize);
get()的使用使得错误检查更简单些。比如如何知道停止读取的原因是由于已经读取了整行而不是由于数组已填满呢?假如使用get()读取,查看下一个输入字符,如果是换行符则说明已经读取了整行,否则说明该行中还有其他输入。
(3)空行和其他问题
当getline()或get()读取空行时,当前的做法是,当get()读取空行后将设置失效位(failbit),着意味着接下来的输入将被阻断,但可以用命令cin.clear();来恢复输入。
如果输入行包含的字符数比指定的多,则getline()和get()将把余下的字符留在输入队列中,而getline()还会设置失效位,并关闭后面的输入。
(4)混合输入字符串和数字
// numstr.cpp -- following number input with line input
#include <iostream>
int main()
{
using namespace std;
cout << "What year was your house built? \n";
int year;
cin >> year;
cin.get(); // 或者使用cin.get(ch);
// 或者使用拼接:(cin >> year).get(); 目的都是为了将输入数字后的换行符消掉
cout << "What is its street address? \n";
char address[80];
cin.getline(address, 80);
cout << "Year built: " << year << endl;
cout << "Address: " << address << endl;
cout << "Done!\n";
return 0;
}
8. 枚举的取值范围
每个枚举都有取值范围,通过强制类型转换,可以将取值范围中的任何整数数值赋值给枚举变量,即使这个值不是枚举值。取值范围的定义:
(1)上限:首先找到枚举量的最大值,找到大于这个最大值、最小的2次幂,将它减1,就得到上限。
(2)下限:首先找到枚举量的最小值,如果其不小于0,则取值范围的下限为0;否则,采用与寻找上限相同的方式,但加上负号。例如:最小的枚举量为-6,则比它小的最大的2次幂是-8,则下限为-7。
9. 一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。
10. 动态数组
假如要编写一个程序,它是否需要数组取决于运行时用户提供的信息。如果通过声明来创建数组,则在程序被编译时将为它分配内存空间。不管程序最终是否使用数组,内存已被占用。在编译时给数组分配内存被称为静态联编(static binding),意味着数组是在编译时加入到程序中的。
但是使用new时,如果在运行阶段需要数组则创建它;如果不需要,则不创建。同时还可以在程序运行时选择数组的长度。这被称为动态联编(dynamic binding),意味着数组是在程序运行时创建的。这种数组被称为动态数组,程序将在运行时确定数组的长度。
11. 对于new分配的动态数组,可以把指针当作数组名来使用。可以这样做的原因是:C和C++内部都使用指针来处理数组。数组和指针基本等价是C和C++的优点之一。指针和真正的数组名之间的根本差别:
// 4.18 arraynew.cpp -- using the new operator for arrays
#include <iostream>
int main()
{
using namespace std;
double* p3 = new double[3];
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.8;
cout << "p3[1] is " << p3[1] << ".\n";
p3 = p3 + 1;
cout << "Now p3[0] is " << p3[0] << " and ";
cout << "p3[1] is " << p3[1] << ".\n";
p3 = p3 - 1;
delete[] p3;
return 0;
}
代码运行结果:
p3[1] is 0.5.
Now p3[0] is 0.5 and p3[1] is 0.8.
数组名和指针的根本差别:不能修改数组名的值,但指针是变量可以修改它的值。将p3加1,它将指向下一个元素的地址。将指针变量加1后,其增加的值等于指向的类型占用的字节数。
指针和数组基本等价的原因在于指针算术和C++内部处理数组的方式。C++将数组名解释为地址。
11. 数组的地址
数组名被解释为数组第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。
short tell[10];
cout << tell << endl;
cout <<&tell << endl;
从数字上说,这两个地址相同;从概念上说,&tell[0](即tell)是一个2字节内存块的地址,而&tell是一个20字节内存块的地址。因此,表达式tell+1将地址加2,而表达式&tell+1将地址加20。换句话说,tell是一个short指针(*short),而&tell是一个指向包含10个元素的short数组(short(*)[10])的指针。
声明和初始化指针:short (*pas) [20] = &tell;
pas的类型为short(*)[20],另外由于pas被设置为&tell,因此*pas与tell等价,所以(*pas)[0]为tell数组的第一个元素。
在多数情况下,C++将数组名视为数组的第一个元素的地址。一种例外情况是,将sizeof运算符用于数组名时,将返回整个数组的长度(单位为字节)。
12. 指针和字符串
在cout和多数C++表达式中,char数组名、char指针以及用引号括起的字符串常量都被解释为字符串第一个字符的地址。
可以将指向char的指针变量作为cout的参数。
13. 应使用strcpy()和strncpy(),而不是赋值运算符来将字符串赋给数组。(C风格字符串)
#include <iostream>
#include <cstring>
int main()
{
using namespace std;
char animal[20] = "bear";
const char* bird = "wren";
char* ps;
cout << animal << " and ";
cout << bird << "\n";
//cout << ps << "\n";
cout << "Enter a kind of animal: ";
cin >> animal;
ps = animal;
cout << ps << "!\n";
cout << "Before using strcpy():\n";
cout << animal << " at " << (int*)animal << endl;
cout << ps << " at " << (int*)ps << endl;
cout << "*animal: " << *animal << endl;
ps = new char[strlen(animal) + 1];
strcpy(ps, animal);
cout << "After using strcpy(): \n";
cout << animal << " at " << (int*)animal << endl;
cout << ps << " at " << (int*)ps << endl;
delete[] ps;
return 0;
}
14. 自动存储、静态存储和动态存储
(1)自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量。自动变量是一个局部变量,其作用域为包含它的代码块。自动变量通常存储在栈中。
(2)静态存储:整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static。
自动存储和静态存储的关键在于:这些方法严格限制了变量的寿命。
(3)动态存储:new和delete管理了一个内存池,在C++中被称为自由存储空间(free store)或堆(heap),该内存池同用于静态变量和自动变量的内存是分开的。new和delete能够可以让程序员在一个函数中分配内存,而在另一个函数中释放它,因此数据的生命周期不完全受程序或函数的生存时间控制。在栈中,自动添加和删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。
15. 学会定义一个const值来表示数组中的元素个数。
16. 关于前缀格式和后缀格式
C++允许程序员针对类定义运算符,在这种情况下,用户这样定义前缀函数:将值加1,然后返回结果;但后缀版本首先复制一个副本,将其加1,然后将复制的副本返回。因此,对于类而言,前缀版本的效率比后缀版本高。
对于内置类型,采用哪种格式不会有差别;但对于用户定义的类型,如果有用户定义的递增递减运算符,前缀的效率更高。
17. 运算符的优先级
前缀递增、前缀递减和解除引用运算符的优先级相同,以从右到左的方式进行结合。后缀递增和后缀递减的优先级相同,但比前缀运算符的优先级高,这两个运算符以从左到右的方式进行结合。
18.cin.get(ch)和cin.get()
不接受任何参数的cin.get()成员函数返回输入中的下一个字符。因此可以这样使用:ch = cin.get()。而cin.get(ch)返回一个对象,而不是读取的字符。
如果输入来自于文件,则可以使用一种功能更加强大的技术——检测文件尾(EOF)。很多操作系统都允许通过键盘来模拟文件尾条件。
// textin4.cpp -- reading chars with cin.get()
#include <iostream>
int main()
{
using namespace std;
int ch; //由于EOF表示的不是有效字符编码,因此可能不与char类型兼容
int count = 0;
while ((ch = cin.get()) != EOF) //EOF表示没有字符
{
cout.put(char(ch));
++count;
}
cout << endl << count << " characters read\n";
return 0;
}
也可以使用:
while(cin.get(ch))
{
...
}
属性 | cin.get(ch) | ch = cin.get() |
---|---|---|
传递输入字符的方式 | 赋给参数ch | 将函数返回值赋给ch |
用于字符输入时函数的返回值 | istream对象(执行bool转换后为true) | int类型的字符编码 |
到达EOF时函数的返回值 | istream对象(执行bool转换后为false) | EOF |
get()的主要用途是能够将stdio.h的getchar()和putchar()函数转换为iostream的cin.get()和cout.put()方法。
19. 字符库函数cctype
(1)isalpha()检查字符是否为字母字符
(2)isdigits()测试字符是否为数字字符
(3)isspace()测试字符是否为空白,如换行符、空格和制表符
(4)ispunct()测试字符是否为标点符号
(5)isalnum() -- 字母或数字
(6)iscntrl() -- 控制字符
(7)isgraph() -- 除空格之外的打印字符
(8)islower() -- 小写字母
(9)isprint() -- 打印字符(包括空格)
(10)isupper() -- 大写字母
(11)isxdigit() -- 十六进制数字
(12)tolower() -- 如果参数是大写字符,则返回其小写,否则返回该参数
(13)toupper() -- 如果参数是小写字符,则返回其大写,否则返回该参数