第三天(复合类型 · 一)

   国庆没回家,未来7天应该每天一篇笔记。

   本来打算把复合类型看完,不过太长了,分两天。


2011-10-01(Compound Types I)
1、字符串的拼接。任何由空白分隔符(空格、制表和换行符)分割的字符串常量都自动拼接成一个:
                           cout << "One Statement""Another Statement\n";
2、cin以空白符界定读取范围。如:

char front[20];
char tail[20];
cout << "Enter front: ";
cin >> front;
cout << "Enter tail: ";
cin >> tail;
cout << "Result: front = " << front << "; tail = " << tail << endl;
测试: 
                           Enter front: Marine King
                           Enter tail: Result: front = Marine; tail = King
3、get()和getline()。由于有了上面的问题,所以iostream类提供了两个面向行的字符串输入函数。当然,面向行亦有换行符的处理问题:getline()将'\n'视作读取结束标志,并将其抛弃;get()将'\n'视作读取结束标志,并留在输入队列中。
I、getline()。 getline()是iostream的实例函数,cin是iostream的对象,所以要通过“.”来调用。它的参数有两个,一个是字符数组,一个是你要接受的字符数,即可以用以下方式调用:
                        cin.getline(char arrayName[], int max);
II、get()。get()有几个形式(即已被重载),其中一种形式与getline()一样,即:
                        cin.get(char arrayName[], int max);
由于get()是将'\n'留在输入队列中的,所以如果使用get()的方法和getline()一样,将出现问题,即(与2一样的设定):
                        cin.get(front,20);
                        cin.get(tail,20);
运行,将会出现如下结果:
                        Enter front: Marine
                        Enter tail: Result: front = Marine; tail =
原因是,输入Marine按下的'Enter'键是作为'\n'留在输入队列,下一次调用get(),一开始就读取到读取结束标志'\n',认为已达行尾,程序直接执行下一行。解决的办法是把'\n'从输入队列中去掉,可调用get()的另一种形式,这种形式的功能是字符读取,将'\n'读取:
                        cin.get(front,20);
                        cin.get();
                        cin.get(tail,20);
当然,cin.get(front,20)返回的是一个cin对象,所以也可以采用如下形式:
                        cin.get(front,20).get();
                        cin.get(tail,20);
顺便说一句,getline()返回的也是cin的一个对象,所以……都懂的。

4、使用get()和getline()的程序健壮性问题。虽然使用get()在正常情况下代码量多于使用getline(),但还是要建议多使用get(),因为在处理输入字符串长度过长问题上要优于getline()。

#include <iostream>

int main()
{
    using namespace std;
    char front[10];
    char tail[10];
    //char ch;

    cout << "Enter front: ";
    cin.getline(front,10);//.get(ch);
    /*if(ch == '\n')
    cout << "Chars less than 10" << "; The lost char: " << ch <<endl;
    else 
    cout << "Chars more than 10" << "; The lost char: " << ch <<endl;*/
    cout << "Enter tail: ";
    cin.getline(tail,10);
    cout << "Result: front = " << front << "; tail = " << tail << endl;

    return 0;
}
如果第一次输入的是:1234567890123(长度大于等于10),则出现以下结果:

                 Enter front: 1234567890123
                 Enter tail: Result: front = 123456789; tail =
即当字符串长度大于等于所设定的最大长度值,截去数组可储存的部分后,余下的并不会被下一个getline()所读取。
将上述程序getline()函数改为get(),并去掉注释部分,运行三次分别输入:123456,654321(length<10);1234567890(length=10);1234567890123(length>10):
第一次结果:
                    Enter front: 123456
                    You enter chars less than 10; The lost char:

                    Enter tail: 654321
                    Result: front = 123456; tail = 654321
第二次结果:
                    Enter front: 1234567890
                    Chars more than 10; The lost char: 0
                    Enter tail: Result: front = 123456789; tail =
第三次结果:
                    Enter front: 1234567890123
                    Chars more than 10; The lost char: 0
                    Enter tail: Result: front = 123456789; tail = 123
可以看出,get()的优势在于,将包括换行符在内的所有字符都留在输入队列,通过对get()参数的控制和'\n'的取舍任意地读取所需的字符串。
5、string类。C++提供了另一个C中没有的字符串处理方式:使用string类。string是位于名称空间std中的,所以需使用using指令,另外,如果要使用string类,头文件应包括#include <string>。

对string对象的处理方法是取之于C语言而高于C语言:

string str1; //定义长度为0的string对象
string str2 = "abc"; //定义并初始化
str1 = str2; //赋值
string str3 = str1 + str2; //拼接
cout << str2[1] << endl; //string对象具有字符数组性质,输出'b'
cout << str3 << endl; //输出abcabc
通过“+”和“=”而不是C语言中的strcat()和strcpy(),不但书写简便,而且不会有字符数超出数组最大长度的情况。

6、string对象的输入。输出使用cout这个不必提。输入因为cin是以空白符为读取结束标志,使用它有诸多不便,所以要使用:
                    string str;
                    getline(cin,str);
来进行整行的字符输入,cin作为一个参数,标明要到哪里去找输入。至于为什么getline()有时需要cin调用(表明是istream的类方法),有时不需要(表明不是类方法),涉及到友元函数,教材没讲清楚,这里不便论述。
7、结构体。
VC++7.1之后才能使用string类作为结构体成员;
结构体可定义在所有函数之外也可定义main函数内,应用范围有所不同。当定义在main外的时候,且结构体成员包括string,则名称空间也应声明在main之外,否则应使用std::string。

结构体初始化一般采用数组形式:

struct Student
{
    char name[20];
    int number;
};
    Student stu1 = 
{
    "Tom",
    25
};
注意到结构体成员之间的逗号。当然也可以写成Student stu1 = {"Tom",25};

结构体可同时完成声明和创建变量工作:
struct Student
{
    char name[20];
    int number;
}stu1,stu2;
也可以同时完成初始化的工作:
struct Student 
{
    //the same as above
}stu1 = {"Tom",25};
不过如此做可读性差点。
结构体可无名称,如struct{int x; int y;}position;以后通过position来访问,但这样后面就不能创建这种类型的结构体变量了。
结构体可赋值,在成员变量有字符数组的情况下也可进行。如,在初始化完stu1而stu2没有的情况下,可通过stu2=stu1赋值。
8、共同体。是一种数据格式,能储存不同的数据类型,但只能同时储存一种。就像一个学生,他/她可以用学号(int型)或者姓名(char[]型)代表。共同体的定义和应用可以如下:
#include <iostream>
#include <string>

using namespace std;
struct Student
{
    int type;//if type = 0,ID's form is int,otherwise,is string
    union ID
    {
        int number;
        char name[20];
    }ID_val;
};

int main()
{
    Student stu[3] = { {1},{0},{1} };
    for(int i = 0;i<3;i++)
    {
        cout << "Enter student " << i+1 << ": \n";
        if(stu[i].type == 1)
        {
            cout << "Enter a number as his or her ID: ";
            (cin >> stu[i].ID_val.number).get();
        }
        else 
        {
            cout << "Enter a string as his or her ID: ";
            cin.get(stu[i].ID_val.name,20).get();
        }
    }

    for(int i = 0;i<3;i++)
        if(stu[i].type == 1)cout << "Student " << i+1 <<"'s ID: " << stu[i].ID_val.number <<endl;
        else cout << "Student " << i+1 <<"'s ID: " << stu[i].ID_val.name <<endl;
    return 0;
}
输入输出如下:
                             Enter student 1:
                             Enter a number as his or her ID: 25
                             Enter student 2:
                             Enter a string as his or her ID: Tom
                             Enter student 3:
                             Enter a number as his or her ID: 30
                             Student 1's ID: 25
                             Student 2's ID: Tom
                             Student 3's ID: 30
注意到17行,可部分初始化;注意到第24行,用get()来接收输入数字后的换行符,以免影响后面的字符串输入。另外,共同体大小是确定的,等于共同体定义的类型中长度最大的,如此可看出,共同体是不允许定义string类的对象的,因为其大小不确定。
9、匿名共同体。对于上面的例子,可以省去共同体名称及其变量:ID和ID_val。则在调用它的时候,可以直接调用它的成员:
                             stu[i].number //34行部分修改
                             stu[i].name //35行部分修改
10、枚举。其实是多个const的组合,即定义多个符号常量。
①定义。用enum关键字定义:
       enum Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
默认情况下,系统将整数赋给枚举量,Monday = 0,Tuesday =2 ...所以,上面的定义等效于:
       const int Monday = 0;
       const int Tuesday = 1;
       //... ...
可以显式地设置枚举量的值:
                       enum race {Zerg = 0, Terran = 5, Protoss = 10};
也可以部分设置:
                       enum race {Zerg, Terran = 5,Protoss};
这时,Zerg = 0,Protoss = 6。
②枚举量与整型。枚举量是整型,可被提升为int类型,但int不能被自动转换成枚举类型:  
int day1 = Thursday;       //合法,Thursday自动转换成3
Day day2 = 3               //非法,3不能自动转换成Thursday,可通过强制转换:Day day2 = (Day)3;
Day day3 = Monday + Friday;//非法,Monday和Friday自动转换成0和4,所得4不能转换成枚举型day3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值