C++浓缩(一)

四、复合类型:

* 复合类型(类除外)
* new和delete以及如何使用它们来管理数据
* string类(另外一种处理字符串的途径)ios

4.1 数组

声明数组的通用格式是:git

arrayType arrayName[arraySize]

arraySize必须是可知数据,可使用 new 运算符来避开这种限制;程序员

【注:】express

一、编译器不会检查使用的下标是否有效。若对无效的下标进行赋值,编译器不会指出错误。
但程序运行后,赋值可能引起问题,它可能破坏数据或代码,也可能致使程序异常终止。so,必须确保只使用有效的下标值。编程

二、数组

sizeof是返回类型或者数据对象的长度(单位:字节);
若是sizeof用于数组名,获得的是整个数组的字节数;
若是用于数组元素,获得是元素的长度(单位:字节);函数

数组初始化的规则:工具

1. 只有在定义数组时能够初始化;然而,可使用下标的方式来进行赋值;
2. 若是没有对定义的数组进行初始化,则元素的值是不肯定的,意味着元素的值为之前驻留在该内存单元中的值;
3. 初始化时,若仅对一部分元素进行赋值,则其余的元素值为0;
4. 所以将数组中全部元素的值赋值为0,仅须要arrayName[500] = {0};
5. 若是初始化数组时,[]内的值为空,那么编译器将计算元素个数;测试

4.2 字符串编码

C++处理字符串的两种方式:

* C-风格字符串;
* string类;

1、C-风格字符串:

C-风格字符串有一个特殊的规则:以空字符串结尾,空字符串被写做\0,其ASCII码值为0,用来标记字符串的结尾。

char dog[8] = {'b', 'e', 'a', 'u', 'x', '', 'I', 'i'};
char cat[8] = {'f', 'a', 't', 'e', 's', 's', 'a', '\0'};//只有这个是字符串

C++有不少字符串处理函数,好比cout,它们逐个处理字符串中的字符,直至遇到空字符
cout显示cat将显示7个字符,遇到空字符串结束;
cout显示dog显示8个字符,并接着讲内存中随后各个字节解释为要打印的字符,直至遇到空字符结束

so,不该将不是字符串的char数组看成字符串来处理。

一种更好的方法,将字符数组初始化为字符串-这种字符串称为字符串常量或字符串字面值;

char birds[11] = "Mr. Cheeps";
char fish[] = "Bubbles";

这种初始化字符串的方式将隐式包含空字符串。

另外,各类C++输入工具经过键盘输入,将字符串都入到char数组时,将自动加上空字符做为结尾;
固然,应当确保数组足够大,可以存储字符串的全部字符-包括空字符;
让数组比字符串长没有什么害处, 只是会浪费一些空间,由于字符串的函数根据空字符串的位置[遇到空字符则中止处理],而不是数组长度进行处理。

注:不能将'S' 和 "S"互换:
'S'是字符常量,是83的另外一种写法,是字符串编码的简写表示。
"S"是字符串常量,表明字符S和\0组成的字符串,另外,“S”实际上表示的是字符串所在的内存地址。

4.2.1 拼接字符串常量

任何两个由空白(空格、制表符和换行符)分隔的字符串常量将自动拼接成一个。【拼接时不会在被链接的字符串之间添加空格】

4.2.2 在数组中使用字符串

将字符串存储在数组中,两种方法:

* 将数组初始化为字符串常量
* 将键盘或者文件都入到数组中,经过cin

char name1[15] = "Basicman" ;
char name2[15] = "C++owboy";
strlen(name1);
sizeof(name1);

sizeof指出整个数组的长度:15个字符;strlen返回存储在数组中的字符串的长度:8(strlen只计算可见的字符,而不把空字符计算在内),但数组长度须要strlen()+1;
另外,对于name2,若执行该操做,name2[3]='\0';这使得该字符串在第3个字符的时候即结束,虽然数组中还有其余的字符。

4.2.3 字符串输入

#include<iostream>
int main() {
    using namespace std;
    const int ArySize = 20;
    char name[ArySize];
    char dessert[ArySize];
    cout << "Enter your name:\n";
    cin >> name;
    cout << "Enter your favorite dessert:\n";
    cin >> dessert;
    cout << "I have some desicious dessert " << dessert ;
    cout << " for you " << name << endl;
    return 0;
}

具体输出状况是:

Enter your name:
Jason Yang
Enter your favorite dessert:
I have some desicious dessert Yang for you Jason

因为不能经过键盘输入空字符串\0,所以cin使用空白(空格、换行符或制表符)来肯定字符串的结束位置。这意味着cin在获取字符数组输入时只读取一个单词。读取该单词以后,cin将该单词放入数组中,并自动添加空字符。这样实际结果是,cin吧Jason做为第一个字符,并将它放到name中,把Yang放到输入队列中。当cin在输入队列中搜索甜点时,发现了Yang,所以读取Yang,将Yang放入到数组dessert中。

另外一个问题是,输入字符串的长度可能大于目标数组长度,那么,该怎么办呢?这须要使用cin的更高级特性。在17章进行介绍。

4.2.4 每次读取一行字符串输入

面向行的输入:

* cin类的getline
* cin类的get

getline丢弃换行符,get将换行符放入到输入队列中;

一、面向行的输入:getline()

经过回车输入的换行符来肯定字符串的结束;

* 有两个参数,第一个参数表示要输入的数组名称,第二个参数代码要输入的字符串的长度;
* 若是参数为20,则该函数仅接受19个字符,剩余的一个字符用来存储在结尾处自动添加的空字符;
* getline在读取指定数目的字符或者遇到换行符的时候中止;

二、面向行的输入:get()

使用方式与getline相同,不一样点:get读取换行符并保留在输入队列中。

cin.get(name, ArSize);
cin.get(dessert, ArSize);

第一次调用,将换行符留在输入队列中,所以第二次调用看的到第一个字符就是换行符,且认为已经达到行尾。

get有一种变体,cin.get()可读取下一个字符(即便是换行符)。

cin.get(name, ArSize);
cin.get();
cin.get(dessert, ArSize);

另外一种使用get的方式是将两个类成员函数链接起来:

cin.get(name, ArSize).get();

由于cin.get(name, ArSize)返回一个cin对象;

下面的语句将输入的两行语句分别读入到数组name和dessert中。

cin.getline(name, ArSize).getline(dessert, ArSize);

三、为何使用get而不是getline呢?

* 由于老式实现没有getline;
* 怎么肯定中止读取的缘由是由于换行符或者是数组已经满了呢?查看下一个输入符,若是是换行符,说明已经读取了整行;若是不是换行符说明数组已经满了,该行还有其余的输入。

4.2.5 混合输入字符串和数字

#include<iostream>
int main() {
    using namespace std;
    cout << "Enter the year:" << endl;
    int year;
    cin >> year;
    cout << "Enter the address: \n";
    char address[80];
    cin.getline(address, 80);
    cout << "year: " << year << endl;
    cout << "address: " << address << endl;
    return 0;
}

运行结果是:

Enter the year:
2000
Enter the address:
year: 2000
address:

用户根本没有输入地址的机会,由于cin读取年份时,将回车键生成的换行符放在了输入队列中。cin.getline看到换行符后,认为是一个空行,将空字符串赋值给address。

解决方法:丢弃换行符。

方法:
* 没有任何参数的cin.get()
* 使用一个char参数的cin.get(ch);

C++ 一般使用指针而不是数组来处理字符串。咱们再介绍指针以后,在介绍字符串方面的特性。

下面介绍一种新的字符串处理方式:string类。

4.3 String类介绍

要使用string类,必须包含头文件string,string类位于命名空间std中。须要添加using编译指令;

string类与使用数组字符串有不少类似之处:
* 可使用C-字符串风格来初始化string对象
* 可使用cin将键盘输入存储到string对象
* 可使用cout来显示string对象
* 可使用数组表示法来访问存储在string对象中的字符

string对象与数组字符串的主要区别就是:
能够将string声明为简单变量;
类设计让程序自动处理string的大小;

4.3.2 赋值、拼接和附加

能够将一个string对象的值赋值给另外一个string对象;可使用+将两个字符串链接起来,可使用+=将字符串附加到string对象的末尾;

4.3.3 string类的其余操做

在有string类以前,对于C-风格字符串,使用C语言库中的函数来完成,头文件ctring提供了这些函数。

eg:

* strcpy()将字符串赋值到字符数组
* strcat()将字符串附加到字符数组中

不一样之处:

赋值:

* string,赋值操做:str2 = str1;
* C-风格字符换,赋值操做:strcpy(ch2, ch1);

附加:

* string,附加操做:str2 += " Boy";
* C-风格字符串,附加操做:strcat(ch2, " Girl");

另外,使用字符数组,老是存在目标数组长度太小,没法存储指定信息的危险。

函数strcat若是试图将所有12个字符复制到数组site中,这将覆盖相邻的内存。这可能致使程序种植,或者程序继续运行,但数据被损坏。

string具备自动调节大小的功能。

获取长度:

* strlen(ch2)
* str2.size()

4.3.4 string类I/O

* 使用cin >> 将输入存储到string对象中
* 使用cout << 显示string对象

其句法与C-风格字符串类似。但每次读取一行而不是一个单词时,使用的句法不一样。

* cin.getline(charr, 20);
* getline(cin, strr);

代码以下:

#include<iostream>
#include<string>
#include<cstring>
int main() {
    using namespace std;
    char charr[20];
    string strr;
    cout << "the length of charr is: " << strlen(charr) << endl;
    cout << "the length of strr is: " << strr.size() << endl;   

    cout << "Enter the charr: " << endl;
    cin.getline(charr, 20);

    cout << "Enter the strr: " << endl;

    getline(cin, strr);

    cout << "the length of charr is: " << strlen(charr) << endl;
    cout << "the length of strr is: " << strr.size() << endl;   

    return 0;
}

运行结果以下:

1. 未初始化的数组内容是未定义的;其次,strlen从数组的第一个元素开始计算字节数,直至遇到空字符;

2. 未初始化的string对象长度自动被设置为0;

3. C-风格字符串getline用法,cin.getline(charr, 20);

4. string getline用法,getline(cin, strr); 代表getline不是类方法,将cin做为参数,指出要到哪里查找输入,未指定长度,string对象会自动调整大小;

问题:为什么一个getline是类方法,一个不是呢?

4.4 结构简介

结构:用户定义类型,能够存储多种类型的数据。

使用:

1. 定义结构描述--描述标记可以存储在结构中的各类数据类型

2. 按照描述建立结构变量

struct student {
        int age;
        string name;
 };

* 定义结构以后,就能够建立这种类型的变量了;

* C++ 容许在声明结构变量时省略struct关键字,结构标记的用法和基本类型的用法相同;

* 可使用成员访问符(.)来访问成员;

eg:声明和初始化(逗号分割,并用花括号括起)

student stu1 = {
        24,
        "cql"
  };

4.4.1

定义结构类型的位置很重要:

* 定义在main函数中,内部声明仅能够被该声明所属的函数使用;

* 放到main的外面,位于函数外面的称为外部变量,外部声明能够被后面的全部函数访问;

C++ 也容许定义外部变量,但不提倡声明外部变量,提倡外部声明结构,另外,外部声明符号常量一般更合理。

4.4.3 

C++ 结构体容许将string做为成员吗?能够,只要能够编译经过。

4.4.4 其余结构属性

* 能够将结构做为参数进行传递,以及让函数返回一个结构;

* 使用赋值运算符(=)将结构赋值给另外一个结构,即便结构中包含数组;这种赋值被称为成员赋值;

* 能够同时完成定义结构和声明结构变量

struct student {
        int age;
        string name;
    } stu1, stu2;

甚至能够以这种方式既声明又初始化:

struct student {
        int age;
        string name;
    } stu1 = {
        24,
        "cql"
    };

另外,C++的结构不只仅能够有成员变量以外,还能够有成员函数。这点将在类中介绍

4.4.5结构数组

建立元素为结构的数组;

struct student {
        int age;
        string name;
    } stu1 = {
        24,
        "cql"
    };

初始化结构数组的规则能够结合初始化数组和初始化结构的规则。

因为数组中的每一个元素都是结构,所以可使用初始化结构的方式来提供值。最终结果为一个逗号分割,花括号括起来的列表。

4.5 共用体

一种数据格式,能够存储多个不一样的数据类型,但同时只能存储其中的一种。

union one4all {
int int_val;
double double_val;
string string_val;
};

one4all能够存储int、double、string类型,但条件是在不一样的时间;

    one4all onetest;
    onetest.int_val = 10;
    cout << onetest.int_val << endl;
    onetest.double_val = 13.8; (int_val has lost)
    cout << onetest.double_val << endl;

因为共用体能够每次只可能存储一个值,所以它必须有足够的空间来存储最大的成员。因此,共用体的最大程度为其最大成员的长度。

4.6 枚举

。。。。。。

4.7指针和自由存储空间

计算机在存储数据时必须跟踪的3种基本属性;

* 信息存储在何处;

* 存储的值是多少;

* 存储的信息类型;

实现上述策略的方法:

* 定义一个简单变量

* 使用指针

 

* 指针是一种变量,存储的是值的地址,而不是值自己;

* 获取常规变量的地址方法:使用地址运算符&

* 使用常规变量时,值是指定的量,而地址是派生量

* 使用指针时,地址是指定的量,而值是派生量

* *运算符,将其应用于指针,能够获得该地址处存储的值

指针策略(C++ 内存管理编程理念的核心):

int updates = 6;
int * p_updates;
p_updates = &updates;
cout << "the value of updates is: " << updates << endl;
cout << ", *p_updates is: " << *p_updates << endl;
cout << "the address of updates is: " << &updates << endl; 
cout << ", p_updates is: " << p_updates << endl;
*p_updates = *p_updates + 1;
cout << "the value of updates is: " << updates << endl;

其实,p_updates和updates只不过是硬币的正反面:

* p_updates表示地址,使用*可得到值;

* updates表示值,使用&可得到地址;

因为p_updates指向updates,所以,*p_updates和updates是等价的,能够像使用int变量那样使用*p_updates,甚至能够赋值给*p_updates,这样将修改指向的值,即updates;

4.7.1 声明和初始化指针

计算机须要跟踪指针指向的值的类型,例如,char与double的地址看上去没有什么区别,char和double使用的字节数不一样,内部表示格式也不一样,所以,在声明指针时,须要指明指针指向的数据的类型。

* int*是一种复合类型,是指向int的指针

声明方式以下均可以:

* int *ptr
* int* ptr
* int*prt
* int * ptr

使用一样的语法来声明其余类型的指针变量:

char * char_ptr;
double * dou_prt;

虽然char_ptr和 dou_prt指向两种长度不一样的数据类型,可是这两个变量自己的长度一般是相同的。

地址须要2个字节仍是4个字节(取决于具体的计算机系统)(有些系统可能须要更大的地址,系统能够针对不一样类型使用不一样长度的地址)。

4.7.2 指针的危险

C++在建立指针时,将分配用来存储地址的内存,但不会分配用来存储地址指向的值得内存。

int * fellow;

*fellow = 223344;

fellow指向哪里呢?并无将地址赋值给fellow,那么223344将放在哪里呢?

因为fellow没有被初始化,它里面可能有任何值,无论是什么,都将它解释为存储223344的地址。

好比,fellow碰巧值为1200,那么1200存储的值就是223344,即便恰巧1200存储的是代码的地址。

so,警告:必定要在指针使用*运算符以前,将指针初始化为一个肯定的、适当的地址。

4.7.3 指针的数字

4.7.4 使用new来分配内存

4.7.5 使用delete释放内存

4.7.6 使用new来建立动态数组

。。。。。。。。。。

5

5.1 for循环

5.1.1 for循环的组成部分

其中注意,测试表达式的值不必定为true或者false,可使用任意表达式,C++将把结果强制转换成true或者false;

若为0,为false;若非零,为true;

C++程序会在须要整数值的时候将true和false转换为1和0,在须要bool值的地方将0和非零转换成false和true;

一、表达式和语句

(任何值)或者(任何有效的值和运算符的组合)都是表达式;每一个表达式都有值

eg:十、22+2七、x=22;x=22这个表达式的值为22;

x = y = z = 0;(赋值运算符从右到左执行)

    int x;
    cout << "1: " << (x = 1000) << endl;
    cout << "2: " << (x < 3) <<endl;
    cout << "3: " << (x > 3) <<endl;
    cout.setf(ios::boolalpha);

    cout << "2: " << (x < 3) <<endl;
    cout << "3: " << (x > 3) <<endl;

输出结果:

一般,cout在现实bool值以前会将他们转换成int,但cout.setf(ios::boolalpha);函数设置了一个标记,

该标记命令cout显示true或者false,而不是1或者0;(固然,前提是运算结果是bool)

从表达式到语句的转换:只须要加上分号便可。

二、非表达式和语句

* 对任何表达式加上分号均可以成为语句

* 但语句去掉分号并不同是表达式

三、修改规则

5.1.2 回到for循环

5.1.3 改变步长

5.1.4 使用for循环访问字符串

5.1.5 递增运算符(++)和递减运算符(--)

5.1.6 反作用和顺序点

5.1.7 前缀和后缀格式

前缀和后缀对执行速度有细微的差异;

* 前缀是将值加1,返回结果;

* 后缀首先复制一个副本,将值加1,返回副本;

相比而言,前缀效率比后缀效率高;

5.1.8 递增\递减运算符和指针

将*和++同时用于指针;怎么处理,取决于运算符的位置和优先级。

* 前缀递增、前缀递减和*优先级相同;从右到左的方式进行结合;

* 后缀递增、后缀递减的优先级比前缀运算符的优先级高;从左到右的方式进行结合;

int age[10] = {10, 20, 30, 40, 50};
int *p;
p = age;
cout << *p << endl;
*p++;// 将p的地址+1,而后获取值,age[1] 
cout << *p << endl;
++*p;// 获取age[1]的值,而后+1
cout << *p << endl;

注意:

指针递增和递减遵循指针算数规则。所以,若是p指向数组的第一个元素,++p将修改p,使之指向第二个元素。

5.1.9 组合赋值运算符

-= += *=  /= %=

5.1.10 复合语句(语句块)

多条语句使用花括号括起来;

* 复合语句有一个有趣的特性,语句块中定义一个新的变量,则当程序执行该语句块中的语句时,该变量才存在。

执行完该语句块,变量将被释放。这代表此变量仅在该语句块中才是有用的。

* 若语句块中声明一个变量,外部声明也有一个重名的变量,该怎么处理呢?

* 在声明位置到内部语句块结束的范围以内,新变量隐藏旧变量

5.1.11 其余语法技巧---逗号运算符

逗号运算符容许将两个表达式放到只容许放一个表达式的地方。

    string word;
    char temp;
    cin >> word;
    for (int i = 0, j = (word.size()-1); i < j; i++, j--) {
        temp = word[i];
        word[i] = word[j];
        word[j] = temp;
    }
    cout << word << endl;

到目前为止,逗号运算符最多见的用途是将两个或者更多的表达式放到一个for循环表达式中。

另外,

* 逗号运算符先计算第一个表达式,在计算第二个表达式

    int m, n, p;
    p = (m = 2, n = 2 * m);
    cout << p << endl;

* 其次,逗号表达式的值是第二部分的值,如上,值为4;

* 逗号运算符的优先级是最低的;

5.1.12 关系表达式

C++提供了6种关系运算符来对数字进行比较。因为字符用其ASCII码表示,所以也能够进行关系比较。

不能将它们用于C-风格字符串,但能够用于string类对象。

< <= == >  >= !=

5.1.13 赋值、比较和可能犯的错误

使用=赋值,使用==比较

5.1.14 C-风格字符串比较

假设要知道字符数组中的字符串是否是mate,word是数组名。

word="mate"

注:数组名是数组的地址,字符串常量"mate"也是其地址。这就是判断两个字符串是否存储在相同地址上

使用strcmp()函数。

接受两个字符串地址做为参数,意味着参数能够是指针、字符串常量或者字符数组名。

若两个字符串相同,返回0;

若第一个字符串按字母排序排在第二个字符串以前,返回负值;

若第一个字符串按字母排序排在第二个字符串以后,返回正值;

实际上,按“系统排列顺序”比按“字母排列顺序”更准确。这意味着字符是根据字符的系统编码来比较的。

C-风格字符串经过空字符来定义,而不是其所在数组的长度。这意味着,即便两个字符串被存储在不一样长度的数组中,也多是相同的。

虽然不能使用关系运算符来比较字符串,但却能够来比较字符,由于字符实际上就是整型。

5.1.15 比较string类字符串

类设计可以使用关系运算符进行比较。

之因此可行,是由于类函数重载了这些运算符。具体在12章介绍。

string类重载运算符!=使用条件:至少有一个操做数为string对象,另外一个操做数能够是string对象或者C-风格字符串。

5.2 while循环

5.2.1 for 与while循环

5.2.2 等待一段时间,编写延时循环

。。。。

5.3 do和while循环

5.4 基于范围的for循环(C++11)

5.5 循环和文本输入

cin对象支持3中不一样模式的单字符输入,其用户接口各不相同

5.5.1 使用原始的cin进行输入

cin忽略空格和换行符

    char a;
    int count = 0;
    cin >> a;
    while(a != '#'){
        count++;
        cin >> a;
    }
    cout << count << endl;

5.5.2 使用cin.get(char)进行补救

可以读取包括空格、制表符和换行符;

若是熟悉C语言,可能觉得这个程序存在严重的错误。

cin.get(ch)调用将一个值放到ch边两种,意味着改变该变量的值。

C语言中,要修改变量的值,必须将变量的地址传递给函数。

但cin.get(ch),传递的是ch,而不是&ch。在C语言中,这样的代码无效,但在C++中,这样的代码有效。

只要函数将参数声明为引用便可。第8张介绍。

另外,一般,在C++中传递的参数的工做方式与C语言相同。而后,cin.get(ch)并非这样;

    char a;
    int count = 0;
    cin.get(a);
    while(a != '#'){
        count++;
        cin.get(a);
    }
    cout << count << endl;

5.5.3 使用哪个cin.get()

cin.get()的三种使用方法:

    cin.get(arrayName, arraySize);
    cin.get();
    cin.get(ch);

函数重载,函数重载容许建立多个同名函数,条件式参数列表不一样;

函数以不一样的方式或针对不一样类型执行相同的任务;

5.5.4 文件尾条件

。。。。。。。。。。。

5.6 嵌套循环和二维数组

5.6.1 初始化二维数组

5.6.2 使用二维数组

在此,仅介绍下声明城市数组的集中方式;

char 指针

   const char * cities[5] = {
        "Beijing",
        "Shanghai",
        "Henan",
        "Tianjin",
        "Ganchazhuang"
    };
    cout << cities[0] << endl;

char数组的数组:

    const char cities[5][25] = {
        "Beijing",
        "Shanghai",
        "Henan",
        "Tianjin",
        "Ganchazhuang"
    };
    cout << cities[0] << endl;

string对象数组:

 const string cities[5] = {
        "Beijing",
        "Shanghai",
        "Henan",
        "Tianjin",
        "Ganchazhuang"
    };
    cout << cities[0] << endl;

6 分支语句与逻辑运算符

* 条件运算符;

* 逻辑运算符;

* 文件输入\输出;

6.1 if语句

和循环测试条件同样,if测试条件也被将值转换为bool值,所以0将被转换为false,非零为true。

6.1.1 if else 语句

6.1.2 格式化if else语句

对多条语句添加大括号;

6.1.3 if else if else 结构

6.2 逻辑表达式

逻辑OR || 逻辑AND && 逻辑NOT !

6.2.1 逻辑OR ||

    char yourchoice;
    cout << "Enter your choice: " << endl;
    cin >> yourchoice;
    if (yourchoice == 'Y' || yourchoice == 'y')
        cout << "you choose" << endl;
    else if (yourchoice == 'N' || yourchoice == 'n')
        cout << "you don't choose'" << endl;
    else
        cout << "no choice" << endl;

因为程序只读取一个字符,所以只读取响应的第一个字符。意味着用户能够用NO进行回答,程序只读取N.

然而,若是程序后面再读取输入时,将从O开始读取,O已经进入的输入队列了。

6.2.2 逻辑AND &&

char * ch_ptr = "my god";
cout << ch_ptr << endl;

程序正常运行,但该方式不建议使用,已经被弃用

6.2.3 用&&来设置取值范围

6.2.4 逻辑NOT运算符!

6.2.5 逻辑运算符细节

逻辑OR和逻辑AND运算符优先级 < 关系运算符

!运算符优先级> 全部关系运算符和算术运算符>逻辑OR和逻辑AND

6.2.6 其余表示方式

* C++ 可用and 、or 和not;

* C可用and、or和not,前提:包含头文件iso646.h

6.3 字符函数库cctype

cctype:与字符相关的、方面的函数软件包;

函数名称返回值isalnum()若是参数是字母数字,即字母或数字,该函数返回trueisalpha()若是参数是字母,该函数返回真isblank()若是参数是空格或水平制表符,该函数返回trueiscntrl()若是参数是控制字符,该函数返回trueisdigit()若是参数是数字(0~9),该函数返回trueisgraph()若是参数是除空格以外的打印字符,该函数返回trueislower()若是参数是小写字母,该函数返回trueisprint()若是参数是打印字符(包括空格),该函数返回trueispunct()若是参数是标点符号,该函数返回trueisspace()若是参数是标准空白字符,如空格、进纸、换行符、回车

、水平制表符或者垂直制表符,该函数返回true

isupper()若是参数是大写字母,该函数返回trueisxdigit()若是参数是十六进制的数字,即0~九、a~f、A~F,该函数返回truetolower()若是参数是大写字符,则返回其小写,不然返回该参数toupper()

若是参数是小写字母,则返回其大写,不然返回该参数

什么是控制字符?

什么是打印字符?

6.4 ?:运算符

6.5 switch语句

switch(integer-expression) 
{
     case label1: statement(s)
     case label2: statement(s)
     ...
     default statement(s)
}

integer-expression必须是一个结果为整数值的表达式。

每一个标签都必须是整数常量表达式。

最多见的标签是int或char常量、枚举量。

6.5.1 将枚举量用做标签

cin没法识别枚举类型(它不知道程序员是如何定义他们的)。所以要求用户输入一个整数。

当switch语句将int值和枚举量标签进行比较时,将枚举量提高为int。

另外,在while循环测试条件中,也会将枚举量提高为int类型。

enum {red, green};
    int code;
    cin >> code;
    while(code >= red && code <= black) {
        switch(code){
            case red:
                cout << "oh,red." << endl;
                break;
            case green:
                cout << "oh,green." << endl;
                break;   
        }
        cin >> code;
    }

6.5.2 switch 和 if else

switch和if else相比,if else更通用。

switch的每一个case标签值必须是单独的值且必须是整数(包括char)。

6.6 break和continue语句

6.7 读取数字的循环

假设要编写一个将一系列数字读入到数组中的程序,并容许用户在数组填满以前结束输入。

若是用户输入一个单词,而不是一个数字,状况将如何呢?发生这种类型不匹配的状况时,将发生4中状况:

* n值保持不变;

* 不匹配的输入将被留在输入队列中;

* cin对象中的一个错误标记被设置;

* 对cin方法的调用将返回false(若是被转换为bool类型);

方法返回false意味着能够用非数字输入来结束读取数字的循环。

非数字输入设置错误标记意味着必须重置该标记,程序才能继续读取输入。clear方法重置错误输入标记,同时也重置文件尾(EOF条件)。输入错误和EOF都将致使cin返回false。

   while(i < MAX && cin >> fishes[i]){
        cout << fishes[i] << endl;
        i++;
    }
    cin >> fishes[i] ;

是一个cin方法函数调用,该方法返回cin。若是cin位于测试条件中,则将被转换为bool类型。

若是输入成功,则转换后的值为true,不然为false。

当用户输入的不是数字时,该程序再也不读取输入。

可使用cin输入表达式的值来检测输入是否是数字。程序发现用户输入了错误内容时,应采起3个步骤:

1. 重置cin以接受新的输入

2. 删除错误输入

3. 提示用户再输入

double fishes[MAX];
    int i = 0;
    while(i < MAX){
        while(!(cin >> fishes[i])){
            cin.clear();
            while(cin.get()!='\n')
                continue;
            cout << "error input, please go on: " << endl;
         }
        cout << fishes[i] << endl;
        i++;
    }
    return 0;

6.8 简单文件输入/输出

6.8.1 文件I/O和文本文件

使用cin输入时,程序将输入视为一系列的字节,其中每一个字节都被解释为字符编码。无论目标数据类型是什么,输入一开始都是字符数据--文本数据。而后,cin对象负责将文本转换为其余类型。

对于输出,将执行相反的转换,即整数被转换为数字字符序列,浮点数被转换为数字字符和其余字符组成的字符序列(如284.53或-1.58E+06)。字符数据不须要作任何转换。

6.8.2 写入到文本文件中

对于文件输入,C++ 使用相似于cout的东西。

* 必须包含头文件iostream

* 头文件iostream定义了一个用处理输出的ostream类;

* 头文件iostream 声明了一个名为cout的ostream变量(对象)。

* 必须指明命名空间std;

* 能够结合使用cout和<<来显示各类类型的数据。

文件输出与此及其类似。

* 必须包含头文件fstream

* 头文件fstream定义了一个用于处理输出的ofstream类。

* 须要声明一个或多个ofstream变量(对象)

* 必须指明命名空间std

* 须要将ofstream对象与文件关联起来,为此,方法之一是使用open()方法。

* 使用完文件后,应使用方法close()将其关闭

* 可结合ofstream对象和运算符<<来输出各类类型的数据。

    char filename[20];
    cout << "Enter the filename: " << endl;
    cin >> filename;
    ofstream infile;
    infile.open(filename);
    double test = 12.5;
    infile << test;
    infile.close();

* 重要的是,声明一个ofstream对象并将其同文件关联起来后,即可以像使用cout那样使用它。全部可用于cout的操做和方法(如<< 、 endl和self())均可以用于ofstream对象。

* 另外,close不须要使用文件名做为参数,由于infile已经同文件关联起来。若是忘记关闭文件,程序正常终止时将自动关闭它。

* infile可以使用cout可以使用的任何方法。不但能使用<<还可使用各类格式化方法,如self()和precision(),这些方法只影响调用它们的对象。

* open(),若文件不存在,将新建;若文件已经存在,丢弃原有内容,重写文件。

6.8.3 读取文本文件

接下来介绍文本文件输入,它是基于控制台输入的,控制台输入涉及多个方面:

* 必须包含头文件iostream

* 头文件iostream定义了一个用于处理输入的istream类

* 头文件iostream声明了一个名为cin的istream对象

* 必须指明命名空间std

* 结合使用cin和>>来读取各类类型的数据

* 可使用cin和get()方法读取一个字符,使用cin和getline()来读取一行字符

* 能够结合使用cin和eof() fail() 方法来判断输入是否成功

* 对象cin自己被用做测试条件时,若是最后一个读取操做成功,它将被转换为布尔值true,不然被转换为false

文件输出与此及其类似:

* 必须包含头文件fstream

* 头文件fstream定义了一个用于处理输入的ifstream类。

* 须要声明一个或多个ifstream对象

* 必须指明命名空间std

* 须要将ifstream与文件关联起来,方法之一使用open()方法

* 使用完文件后,使用close()方法将其关闭

* 可结合使用ifstream对象和get()方法来读取一个字符,使用ifstream对象和getline()来读取一行字符。

* 能够结合使用ifstream和eof()、fail()等方法来判断输入是否成功

* ifstream对象自己被用做测试条件时,若是最后一个读取操做成功,它将被转换为布尔值true,不然被转换为false

    ifstream outfile;
    outfile.open(filename);   
    double test;
    outfile >> test;
    char test2[20];
    outfile >> test2;
    cout << test << endl;
    cout << test2 << endl;
    outfile.close();

若是打开一个不存在的文件用于输入,将致使使用ifstream对象使用输入时失败。检查文件是否成功打开的首先方法就是使用is_open()。

    outfile.open(filename);   
    if (!outfile.is_open())
        exit(EXIT_FAILURE);

若是文件被成功打开,方法is_open()返回true,不然,返回false;

函数exit原型在头文件cstdlib中定义的,在该头文件中,还定义了一个用于同操做系统通讯的参数值EXIT_FAILURE。函数exit()终止程序。

is_open是C++相对较新的内容。若是编译不过,可以使用较老的方法good()来代替。不过,方法good在检查可能存在的问题方面,没有is_open()那么普遍。

    ifstream outfile;
    outfile.open(filename);   
    if (!outfile.is_open())
        exit(EXIT_FAILURE);

    int sum = 0;
    int number;

    outfile >> number;
    while(outfile.good()){
        outfile >> number;   
        sum += number;
    }

    if(outfile.eof()) {
        cout << "eof" << endl;
    } else if (outfile.fail()) {
        cout << "fail" << endl;
    } else {
        cout << "other" << endl;
    }
    outfile.close();

检查文件是否成功打开相当重要,好比:

* 指定的文件不存在;

* 文件可能位于另外一个目录中;

* 访问被拒绝;

* 输错了文件名或省略了文件扩展名。

程序读取文件时不该超过EOF。

* 首先,若是最后一次读取数据时遇到EOF,方法eof()返回true。

* 其次,程序可能遇到类型不匹配的状况,方法fail()返回true(若是遇到了EOF,该方法也返回true)。

* 最后,可能出现意外问题,如文件受损或者硬盘故障。

* 若是最后一次读取文件时放生了这样的问题,方法bad()将返回true。

不要分别检查这些状况,一个更简单的方法是使用good()方法,该方法在没有发生任何错误时返回true;

若是愿意,可使用其余方法来肯定循环终止的真正缘由:

    if(outfile.eof()) {
        cout << "eof" << endl;
    } else if (outfile.fail()) {
        cout << "fail" << endl;
    } else {
        cout << "other" << endl;
    }

eof()只能判断是否到达EOF;

fail()能够检查是EOF仍是类型不匹配;

方法good()指出最后一次读取输入的操做是否成功,这一点相当重要。这意味着在执行读取输入的操做后,马上应用这种测试。为此,一种标准的方法是,在循环以前放置一条输入语句,并在循环的末尾放置另外一条输入语句。

    outfile >> number;
    while(outfile.good()){
        ++count;
        outfile >> number;   
        sum += number;
    }

可对上述语句进行精简;

表达式outfile>>number的结果为outfile,而在须要一个bool值得状况下,outfile的结果为outfile.good()即,true或者false;

所以,能够改形成以下:

while(outfile >> number){
        ++count;
        sum += number;
}
相关文章
相关标签/搜索