C++ 数据符合类型
基于基本类型和浮点类型创建;影响最为深远的复合类型是类,这是OOP编程的堡垒。
C++ 还支持几种更普通的复合类型,它们都来自C语言。
例如,数组可以存多个同类型的值,一种特殊的数组可以存储字符串(一系列字符),结构可以存多个不同类型的值。
指针则是 微山一中将数据所处位置告诉计算机的变量 。
数组
创建数组,可使用声明语句, 数组声明应指出三点:
(1)数组的数据类型;
(2)数组名;
(3)数组长度;
声明数组的通用格式如下:
typename arrayname[arraySize] ;
arraySize指定数组元素数目,它必须是整形常数或const值,也可以是常量表达式(如8*sizeof(int)) ;及其中所有值在编译时都是已知的。
数组之所以称是复合类型,是因为它是由其他类型创建的。
编译器不会检查下标是否有效。
数组初始化:
(1)直接赋值。
(2)列表初始化
列表初始化,方框中可以为空,编译器计算元素个数。
C++ 11的列表化新增功能,
(1)列表初始化可省略等号
double a[4] {0,1,3,4};
(2) 可不在大括号中包含任何东西,这将把所有元素都设置为零;
double b[10]{};
(3) 列表初始化禁止缩窄转换。
long plifs[] = {25,92,3.0} //not allowed
char slifs[4] {‘h’,'d',112201,'\0'}; // not allowed
char tlifs[4]{'h','i'.113,'\0'}; // allowed
第一条,由于浮点数转换为整型是缩窄操作,即使浮点数的小数部分为0;
第二条,112201超出char型数据取值范围。
字符串
字符串是存储在内存的连续字节中的一系列字符。
C++ 处理字符串的方式有两种。
第一种来自C语言,常被称为C-风格字符串(C-style string);
第二种,基于string 类库的方法。
- 存储在连续字节中的字符意味着可以将字符串存储在char数组中,其中每个字符都位于自己的数组元素中,字符串提供了一种存储文本信息的便捷方式。
- C-风格字符串具有一种特殊的性质:以空字符结尾,空字符被写作\0,其ASCII码是0,用来标记字符串的结尾。
char dog[8]{'b','e','a','a','x',' ','I','I'}; // not a string
char cat[8]{'b','3','a','e','d','g','f','\0'}; // is a string
C-风格字符串必须以空字符结尾。空字符对C-风格字符串而言至关重要;
C++ 有很多处理字符串的函数,其中cout 使用的那些函数。 他们都是逐个的处理字符串中的字符,直到到达空字符位置。
如果使用cout 显示上面的dog数组,cout 将打印出数组中的8个字符,并接着将内存中随后的各个字节解释为要打印的字符,直到遇到空字符位置。
由于空字符实际上是被设置为0的字节在内存中很常见。通常这个过程很快停止。但是尽管如此,还是不应将不是字符串的数组当做字符串来处理。 - 另一种将数组初始化为字符串的方法,这种字符串被称为字符串常量(string constant) 或者 字符串字面值(string literal)。
char bind[11]{"Mr. Cheeps"}; // the \0 is understood
char fish[]{"Bubbles"};//let the compiler count
- 另外各种C++ 输入工具通过键盘输入,将字符串读入到字符串数组时,都将自动加上结尾的空字符。
- 使用字符串常量初始化字符数组是这样的一种情况,即让编译器计算元素数目更为安全。
- 处理字符串的函数根据空字符的位置,而不是数组长度来进行处理。
- C++对字符串长度没有限制。
- 字符串常量不能与字符常量互换。字符常量是字符串编码的简写表示,
char shift_size = 'S'; // this is OK
char shift_size = "S"; // illegal type mismatch
- “S”不是字符常量,它表示的是’S’和’\0’组成的字符串,更糟糕的是,"S"实际上表示的是字符串所在的地址,所以将字符串常量赋值给字符变量相当于将一个内存地址赋值给字符变量。 由于地址在C++ 中是一种独立的类型,因此C++ 编译器不允许这种不合理的做法。
-
字符串常量拼接:
- 有时候,字符串很长,无法放到一行中,C++允许拼接字符串字面值,即将两个用引号阔气的字符串合并为一个。事实上,任何两个由空白(空格、制表符、换行符)分隔的字符串常量都将自动拼接成 一个。因此:
cout <<"I'd give my right arm to be " " a great voilient.\n";
cout <<"I'd give my right arm to be a great voilinst.\n";
cout <<"I''d give my right ar" "m to be a great voilient.\n";
注意,拼接时不会在被连接的字符串之间添加空格,第二个字符串的第一个字符紧跟第一个字符串的最后一个字符(不考虑\0)后面,第一个字符串中的\0字符将被第二个字符串中的第一个字符取代。
- 字符串的输入,初始化。
- 数组初始化为字符串常量; 将键盘或文件读入到字符数组中。
- cin 使用空白(空格,制表符,换行符)来确定字符串的结束位置,这意味着cin在获取字符数组的输入只读取一个单词,读取该单词候,cin将该字符串放到数组中,并自动在结尾处添加空字符。
- 防止越界 ,面向行的输入 getline()
cin.getlne(name,20);
- getline 通过换行符来确定行尾。但是不保存换行符。在存储字符串时,用空字符来替换换行符
- 面向行的输入: get()
cin.get(name,size);
cin.get(name2,size2);//problem
- 连续两次调用get(),由于第一次调用get,换行符被保存在输入队列中,所以第二次调用时,第一个字符便是换行。get认为已经到行尾,没有发现任何可读取的内容。
- get()不带任何参数时,可读取下一个字符(即使是换行符),因此可以用它来处理换行符。为读取下一个字符串做准备。
cin.get(name,size);
cin.get();
cin.get(name2,size2);
- 另一种get()的 使用是将两个类成员函数拼接起来。
cin.get(name,size).get();
- 可以这样做是因为
cin.get(name,size)
返回的是一个cin对象,该对象随后被用来调用get()
函数。 - 推荐使用
get()
而不是getline()
,原因 :get()
使输入更仔细。getline()
会抛弃换行符之后的数据。 - 当
getline() or get()
读取到空行时,下一条输入语句将在前一条getline() or get()
结束读取的位置开始读取;但当前的做法 是,当get()
(不是getline()
)读取空行后将设置失效位(falibit
);这意味着接下来的输入将被阻断。 可以通过以下命令恢复输入:``cin.clear();` - 另一个潜在问题就是输入字符串可能比分配的空间长,
getline()
和get()
将把余下的字符留在输入队列中,而getline()
还会设置失效位,并关闭后面的输入。
string 类
ISO/ANSI C++98 标准通过添加string 类扩展了C++ 库,因此现在string 类型的对象来存字符串。
-
可以使用C-风格字符串来初始化string 对象;
-
可以使用cin 来将键盘输入存储到string 对象中;
-
可以使用cout 来显示string 对象;
-
可以使用数组表示法来访问存储在string 对象中的字符。
-
可以将一个string 对象赋给另一个对象(类的拷贝构造);
-
string 可以通过 +来进行拼接,
-
string 可以通过strcpy,strcat实现对字符数组的拷贝,拼接。
-
C++ 11新增char16_t 和char32_t; 分别使用u,U前缀。
-
C++11 还支持Unicode 字符编码方案UTF-8, 字符可能存储为1-4个8位组。
-
C++11 新增另一种类型 原始(raw) 字符串, 在原始字符串中,字符表示的就是自己。使用R来标志原始字符串 ; 输入原始字符串时,按回车键不仅会移到下一行,还将在原始字符串中添加回车字符;使用R“+(标志原始字符串的开头时,必须使用)+"标识原始字符串结尾。