C++基础——复合类型
字符串
字符串输入
cin
在读取字符串时以空格、制表符和换行符来确定字符串结束位置,这就导致当我们输入一行字符串,如果中间有空格或制表符,则会被拆成两个字符串作为输入。
为了方便,引入了读取一行的函数让字符串输入更加灵活。
getline
getline
作为cin
的一个成员函数,通过回车键输入的换行符来确定输入结尾。
getline
有两个参数,第一个参数为存储字符串的数组名称,第二个参数为要读取的字符个数,如果参数为20,则有效字符最多为19个,最后一个用作存储'\0'
。如果读取到19个字符,则舍弃输入流之后的字符,如果还未读取到19个字符,而发现了换行符,则将换行符替换为'\0'
,结束输入,同时将输入流中的换行符舍弃。
get
get
方法和getline
相似,都是读取一行字符串,但是get
不会舍弃输入流中最后的换行符,将其保留在输入序列中。
get
有两种变体,一种用于读取一行字符串,参数和getline
相同,另一种用于读取一个字符,没有参数,返回值为读取到的字符,与C语言的getchar()
相似。
另外get
还有一个变体,有一个参数,指示存储被读取到的字符的变量,用法为cin.get(char)
,这是C++版本中的方法,因为C++引入了引用,可以根据参数更改变量值。
空行和其他问题
当使用get
读取空行时会设置失效位,之后的输入都将被阻断,此时需要调用cin.clear()
来恢复输入。
如果读取的字符串长度比预先分配的空间长,则get
和getline
都会将余下的字符串留在输入队列中,而**getline
还会设置失效位**阻断输入。
注意cin
输入以空格、制表符和换行符作为结束标志,但是不会清除输入流中的这些字符,当下一次调用cin
时如果第一个字符就是结束字符则会跳过这些结束字符,直到遇见第一个非结束字符,才开始下一步读取。
因此当混合输入字符串和数字时可能出现getline
读取到未被清除的结束符号而什么也没有读取到。
其他形式的字符串字面值
这里主要说一下原始字符串。
因为C++中有很多符号已经有了特殊含义,比如""
,因此在输出时如果想要输出引号必须使用转义字符,在这种符号数量较多时可能会非常麻烦,因此引入了原始字符串。
为了区分,原始字符串以R
为前缀,以"(
和)"
作为界定符。
cout << R"("Hello world \n.")"
其输出为:
"Hello world \n."
这种情况也会出现想要输入"()"
而无法识别的情况,此时可以在界定符"
和(
之间添加任意多数量的基本字符(除了空格、括号、斜杠和控制字符),在结束符号之间也按照同样顺序添加同样的基本字符,就可以自定义界定符。
cout << R"+*("(Hello world.)")+*"
输出为:
"(Hello world.)"
字符函数库cctype
这个库可以用于检测字符是否为大小写字母、数字、标点符号等等。
函数名称 | 返回值 |
---|---|
isalnum() | 判断参数是否为数字或字母 |
isalpha() | 判断参数是否为字母 |
iscntrl() | 判断参数是否为控制字符 |
isdigit() | 判断参数是否为数字 |
isgraph() | 判断参数是否为除空格以外的打印字符 |
islower() | 判断参数是否为小写字母 |
isprint() | 判断参数是否为打印字符(包括空格) |
ispunct() | 判断参数是否为标点字符 |
isspace() | 判断参数是否为标准空白字符,如空格、制表、换行、回车等 |
isupper() | 判断参数是否为大写字母 |
isxdigit() | 判断参数是否为十六进制数字 |
tolower() | 如果参数为大写字符,返回其小写字符 |
toupper() | 如果参数为小写字符,返回其大写字符 |
指针
指针是C++中很重要的概念,基础知识很简单,这里简单分辨一下指针数组和数组指针。
指针数组和数组指针
根据优先级,[]
的优先级大于*
,因此对于下面的代码:
int * pa[10]; // 指针数组
这是一个指针数组,表示一个包含十个指针的数组。
即pa[10]
先表明这是一个数组,int *
再指定类型。
而:
int (*pa)[10]; // 数组指针
这是一个数组指针,表示一个指向包含十个int
数据的一维数组的指针。
通过括号提高了*
的优先级,*pa
先表明这是一个指针,int (*pa)[10]
再指定类型为数组。
通常数组指针用在二维数组中。
比如现有这样一段代码:
int a[120][5];
int (*pa)[5];
pa = a;
此时的情况为:
注意pa
指向的是array
数组的第一行。
当我们将pa
加一,此时pa
将会指向第二行:
共用体
共用体是一种数据格式,可以存储不同的数据类型,但是同时只能存储其中一种类型。
比如:
union val{
int int_val;
long long_val;
double double_val;
};
上面这个共用体可以表示三种数据类型,当选择不同类型时得到的结果是不同的。
比如:
val pail;
pail.int_val = 15;
cout << pail.int_val;
pail.double_val = 1.25;
cout << pail.double_val;
共用体其实就是一块空间,其存放的数据视选择的类型不同而不同,甚至可以以一种类型存储,而以另一种类型读取。
共用体大小为最大数据类型的大小,比如上面的例子中,共用体大小为double
类型的大小。
可以结构体中包含匿名共用体,此时共用体的两个成员被视为结构体的两个成员,它们的存储空间地址相同。
枚举类型
枚举类型enum
是另一种创建符号常量的方式。
enmu spectrum{red, orange, yellow, green, blue, violet, indigo, ultraviolet};
这是一种心得类型,spectrum
作为新类型的名称。
spectrum band;
定义了一个枚举变量为band
。
对于spectrum
枚举变量,它只有8个可能的值,取值范围为0~7
(默认情况),因此不能将范围之外的值赋值给band
,同时也不能进行某些运算。
赋值时也不能将整型直接赋值给枚举类型,但是枚举类型中定义的枚举量可以进行赋值:
band = red; // √
band = 0; // ×
可以在定义枚举类型时指定取值,可以用作一个常量。
当用在switch
语句中时,通常会被提升为int
类型,可以通过int
类型来指代枚举类型。
如果我们只使用枚举值而不打算创建枚举类型的变量,则可以声明略枚举类型的名称:
enmu spectrum{red, orange, yellow, green, blue, violet, indigo, ultraviolet};