1017
C++ Primer Plus
- 第1-3章
- 第4章 复合类型
-
- 4.1 数组
- 4.2 字符串(C语言)
- 4.3 string类(C++)
- 4.4 结构体struct
- 4.5 共用体/联合体union
- 4.6 枚举enum
- 4.7 指针
- 4.8 指针、数组和指针算术
- 4.9 类型组合---数组、指针、结构体的组合
- 4.10 数组的替代品
- 4.11 总结
- 4.12 复习题(第2、14、16、17题)
- 4.13 编程练习
- 第5章 循环和关系表达式
第1-3章
第4章 复合类型
4.1 数组
4.1.1 概念、三要素、书写格式、下标
①数组里的元素必须是同类型的,且在计算机中占用连续的内存空间。
②数组三要素:元素的类型、数组名、数组大小。
③声明数组的通用格式:
④数组通过下标或者索引来访问元素,下标从0开始。
4.1.2 数组的初始化规则:
只有在定义数组时才能使用初始化,此后就不能再初始化了,也不能将一个数组赋给另一个数组。
4.1.3 C++11中数组初始化方式
用大括号,并且等号可以省略。
此外,C++标准模板库(STL)提供了一种数组替代品—模板类vector,而C++11新增了模板类array。
4.2 字符串(C语言)
4.2.1 在数组中使用字符串
要把字符串存储到数组中,最常用的方法有两种:
1.将数组初始化为字符串常量;
2.从文件或键盘输入把字符串读入到数组中。
案例
4.2.2 区分 ①字符数组 和 字符串;②字符常量 和 字符串常量;③sizeof() 和 strlen() 。
①字符串 和 字符数组 的区别
C++笔记5:字符串 字符数组 string
字符数组不一定是字符串,但字符串一定是字符数组。
字符串以 空字符(null character) 结尾,空字符写作’\0’。
②字符常量 和 字符串常量的区别(字符串常量本质上是个地址)
举例:
字符常量’S’是数字83的另一种写法;
字符串常量"S"由 字符’S’和’\0’ 组成,而且实际上"S"表示的是字符串的内存地址。
③sizeof() 和 strlen() 的区别
注意区分sizeof()和strlen():
sizeof()统计整个字符数组所占内存的大小,单位是字节;
使用strlen()的前提是必须是字符串,只统计字符数组中可见的字符(‘\0’之后的字符就是不可见的字符),而且不会把 空字符\0 计算在内。
综合案例
主要用代码测试:
①字符数组 和 字符串 的区别;
②字符常量 和 字符串常量 的区别;
③sizeof() 和 strlen() 的区别。
//1.字符数组&字符串
char arr1[10] = {
'd','o','g','s' };//字符数组,不是字符串
char arr2[10] = {
'd','o','g','\0','s'};//字符数组,字符串(有结束符\0)
cout << sizeof(arr1) << endl;//10个字节,而不是4个字节,因为sizeof()统计的是整个数组的长度
cout << sizeof(arr2) << endl;//10个字节
cout << strlen(arr1) << endl;//4个字符 不会报错,会警告 C6054可能没有为字符串“arr1”添加字符串零终止符。
cout << strlen(arr2) << endl;//3个字符 只统计到结束符前的位置上,而且不把结束符算在内
//因为结束符后面还有内容,所以也会警告 C6054可能没有为字符串“arr2”添加字符串零终止符。
//2.字符常量&字符串常量
//用双引号括起来的字符串常量会隐式的包括结尾的空字符\0
cout << sizeof('s') << endl;//1个字节
cout << sizeof("s") << endl;//2个字节 除了字符s,还有结束符\0
//cout << strlen('s') << endl;//报错,strlen()是用于字符串的
cout << strlen("s") << endl;//1个字符
4.2.3 字符串输入–>每次读取一行字符串输入(案例见编程练习第1题
)
①用cin输入字符串的问题:只能读一个单词
问题:
cin使用空白(空格、制表符、换行符)作为字符串输入结束的标志,这意味着用cin获取字符数组的输入内容时一次只能读取到一个单词(因为有的单词之间是空格,比如New York,Marco Reus,而cin把空格做为字符串输入结束的标志之一)。
解决方法:
可以用istream类中成员函数getline()和get(),这两个函数都可以读取一整行直到遇到换行符。其中,getline()会丢弃最后的换行符,而get()将把换行符也作为输入的内容传输给电脑。
②面向行的输入:cin.getline() — 推荐☆☆
(4.3.3 string类I/O中会讲到getline();)
这节介绍的是cin.getline():
语法:
cin.getline(name1, 20);//默认是以'\n'作为输入结束符
cin.getline(name5, 20,'_');//以'_'作为输入结束符
括号里的参数分别是用来存储输入行的数组的名称,第二个参数是要读取的字符数(第二个参数是用来避免超越数组的边界),第三个参数是输入结束符,默认是换行符’\n’。
注意:cin.getline()不会保留结束符。
案例:
问题+结论:
问题:
从上面的例子能看出如果一次输入的内容有多余的,就会被当作下一次输入的内容,归根结底是因为用下划线作为结束符。
结论:
所以一般不推荐使用下划线作为结束符。
③面向行的输入:cin.get() —推荐☆
语法:
cin.get(name1, 20); //默认是以'\n'作为输入结束符
cin.get(name5, 20, '_' ); //以'_'作为输入结束符
括号里的参数分别是用来存储输入行的数组的名称,第二个参数是要读取的字符数(第二个参数是用来避免超越数组的边界),第三个参数是输入结束符,默认是换行符’\n’。
注意:cin.get()
会保留结束符,将其放到输入队列中。
案例1:
问题1+改进:
问题1:
从上面的例子可以看出,结束符和多余的内容会被当做是下一次的输入内容,这样会造成下一次的输入出错。
结论:
针对这个问题的解决办法是用cin.get()
把结束符吃掉。
案例2:
问题2+改进:
问题2:
由于一般输入结束后都会回车,如果用下划线做结束符,并且下划线后面还有多余的内容,这样就算用cin.get()把结束符吃掉,后面多余的内容依然会影响到下一次输入。
结论:
所以不推荐用下划线或者别的符号做结束符。
总结:
①首先,不论输入结束符是什么,都用.get()
(可以读取一个字符)把这个结束符给读取掉,即跨过这个换行符;
②另外,不要把下划线或者其他符合作为结束符,直接用默认的回车符作为结束符最简单,没有那么多问题。
这样就为下一次输入做好充分的准备了:
④cin、cin.getline()、cin.get()总结☆☆☆(案例见编程练习第1题
)
读取字符串char name[20];
的三种方法,推荐用第一种:(也可以看看第5章 - 5.9 编程练习 的 第7、7’、8、9题的汇总☆☆☆)
char name[20]; | cin.getline(name,20)☆☆ | cin.get(name,20)☆ | cin >> name; |
---|---|---|---|
多余的内容 | 当以下划线作为结束符时,输入时下划线后面多余的内容会影响下次输入。 | 当以下划线作为结束符时,输入时下划线后面多余的内容会影响下次输入。 | 不受多余的内容的影响 |
结束符 | 不受结束符的影响 | 因为会保留结束符,所以结束符和多余的内容会影响下次输入。 | 虽然cin只能读取一个单词,但也是以\n作为结束符,并且 \n会被存入到输入队列中 ,所以会影响到下次输入。 |
解决办法 | 对于多余的内容: 不要用下划线或者其他符号作为结束符。 |
对于结束符的影响: 用.get()来消除; 对于多余的内容: 不要用下划线或者其他符号作为结束符 |
对于结束符的影响: 用.get()来消除; |
示例: | cin.getline(name1,20); | cin.get(name2,20).get(); | cin >> name3; cin.get(); |
结论: | |||
cin 和cin.get() 都需要.get() 来消除结束符,而cin.getline() 不需要,所以推荐用cin.getline(name,20);//把读取的整行内容给到数组name,一次最多读20个字节,这个20一般是字符数组name[20]的大小,是用来避免超越数组的边界 。 |
⑤空行和其他问题
有一个问题:如果输入的内容全是空格会怎么办,就没办法退出输入操作,其实如果想要空行,可以直接’\n’。
4.2.5 混合输入字符串和数字(案例见编程练习第1题
)
案例(这个案例不好,看编程练习第1题):
问题又是结束符被当做下一次输入的内容,所以先用cin.get()吃掉第一次输入遗留的结束符(‘\n’):
案例用的是cin.get(),应该用cin.getline(),不会保留结束符。
4.3 string类(C++)
4.3.1 C语言的字符串 和 C++的string类 的相同点
都可以通过下标的方式访问元素:
4.3.2 string类的 赋值、拼接、附加
不同于4.1.2 数组的初始化规则中不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象;
C语言库中的函数:(包含头文件#include)
strcpy(str1, str2);//复制
strcat(str1, str2);//附加
C++中的str3 = str1 + str2; 需要
C语言中的strcpy(str3, str1); strcat(str3, str2); 来实现。
string的赋值、拼接、附加:
strlen() 和 str.size()、str.length()的区别
C++笔记5:字符串 字符数组 string
strlen()
函数,这是C语言里的库函数。
.size()
函数和.length()
函数:都是用来统计字符个数,也不包含结束符’\0’。
4.3.3 string类I/O(案例见编程练习第1题
)
两种方法:
string name3;
getline(cin,name3);//可以读取整行 或者
cin >> name3;//只能读取一个单词 都可以,其中cin是istream类的一个对象。
C语言的字符串输入 | C++的字符串输入 | |
---|---|---|
章节 | 4.2.3 字符串输入–>每次读取一行字符串输入 | 4.3.3 string类I/O |
读取整行 | 由于cin一次只能读取一个单词,想要读取一行要用cin.getline()或者cin.get(); | 由于cin>>str也是一次只能读取一个单词,想要读取一行要用getline() (注意:没有cin.) |
示例 | ①char name1[20]; char name2[20]; ②cin>>name1;//读一个单词 cin.getline(name1,20); 和 cin.get(name2,20).get();//读整行 |
①string name3; ②getline(cin,name3);//读整行 cin >> name3;//读一个单词 |
示例备注 | name1和name2是C语言的char name[],20是要读取的字符数 | cin是istream类的对象,name3是string类的对象 |
补充:
C++笔记12:C++中.txt和.csv文件的写入和读取
这里的getline() 中不是istream类的对象cin,而是ifstream类的对象ifs和stringstream类的对象ss:
ifstream ifs;//创建输入流对象
string line;//记录每行的内容
getline(ifs, line)//整行读取,默认以'\n'作为分隔符
stringstream ss;
string subStr;
getline(ss, subStr, ',')) {
//3.以','作为分隔符,将当前行的内容分开
4.4 结构体struct
关键字:struct
创建结构包括两步:
①声明结构体—它描述并标记了能够存储在结构中的各种数据类型;
②创建结构变量。
①声明结构体:
②创建结构体变量(C++中可以省略关键字struct):
补充:
①结构体可以通过使用成员运算符(.) 来访问各个成员变量;
②访问类成员函数(如cin.getline())的方式是从访问结构成员变量(vincent.price)的方式衍生而来的。
4.4.1 结构体初始化
方式1:(定义结构体 和 创建结构体变量 分开进行)
#include<iostream>
#include<string>
using namespace std;
//结构体声明:
struct Students{
string name;
int age;
};
int main(){
//C语言的常规初始化方式:
struct