版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzt12345hf/article/details/84763096
C++三种复合类型:数组、结构和指针
数组
- 数组声明**
typeName arrayName[arraySize];
**,其中arraySize必须为常量值 - 数组初始化,C语言为
typeName arrayName[arraySize] = {value1, value2, value3, ...};
,C++新增方法typeName arrayName[arraySize]{value1, value2, value3, ...};
,如果括号里为空,则个元素都设置为零,但初始化列表禁止缩窄转换,如:long p[ ] {23, 93, 3.0} 是不允许的;
字符串
- 字符串都以
字符'\0'
结尾,用双引号括起
来的字符串称为字符串常量或字符串字面值;区别字符数组和字符串,字符串内置结束字符,而字符数组没有;
###字符和字符串的输入输出
- 默认cin遇到空格、制表符、换行符时自动结束字符串输入,意味着不可以输入带有空格的字符串,如果要输入一样字符串,则使用istream中面向行的类成员函数
getline()
或get()
cin.getline(char *arrayName , int size);
,arrayName表示数组名,size表示最多读入多少个字符,getline()函数遇到换行符结束输入,读取换行符,不将其留在输入队列中
;cin.get(char *arrayName , int size);
,arrayName表示数组名,size表示最多读入多少个字符,get()函数遇到换行符结束输入但不读取换行符,而是将其留在输入队列中
,因此需要再调用一次cin.get()来读取下一个字符;可以将两个get()结合起来cin.get(char *arrayName , int size).get();
;当get()读取到空行后将设置失效位(failbit),会阻塞输入,要使用cin.clear();
来恢复输入;- 一般的 cin>>x 输入会将换行符留在输入队列,因此如果要用getline()和get(),需要将剩余的换行符清除,可以这么写
(cin>>x).get();
- cin、getline、get对比:
对比 | cin>>xxx | cin.getline(xxx,size) | cin.get(xxx,size) |
---|---|---|---|
作用 | 输入基本类型数据 | 输入整行字符串 | 输入整行字符串 |
结束标志 | 空格、制表符、换行符 | 换行符 | 换行符 |
换行符去留 | 留在输入队列中 | 换行符已使用 | 留在输入队列中 |
- 读取字符可以使用
cin.get(ch);
或ch = cin.get();
,使用cout.put(ch);
输出字符;cin.get(ch)和ch = cin.get()区别如下:
属性 | cin.get(ch) | ch = cin.get() |
---|---|---|
传递输入字符的方式 | 赋值给参数ch | 将函数返回值赋给ch |
用于字符输入是函数的返回值 | istream对象(执行bool转换后为true) |
int类型的字符编码 |
到达EOF是函数的返回值 | istream对象(执行bool转换后为false) |
EOF |
字符函数库cctype
- C++从C那里继承了一个与字符相关的便捷的函数库,C中头文件为ctype.h,C++为cctype;
string类
- 要使用string类,需要包含
头文件string
,string对象和字符数组方式基本相同,C语言提供了头文件cstring(以前是string.h)来处理字符串; - string类字符串可以用cin输入,cout输出,不过string自己实现了getline()类方法
getline(istream &in, string &str);
,其中in表示标准输入类的实例,一般使用cin,str表示要输入到的string类对象 - C++11 新增了
原始字符串
,即字符串中不存在转义字符
,每个字符都代表自己,原始字符串使用"(
和)"
作为定界符,前缀R
标识原始字符串,允许在“和(直接添加东西来替换原始的定界符,但定界符前后要对称,举例如下:cout << R"+\*("(Who wouldn't?)" , she whispered.)+\*" << endl;
其中定界符为 “+*( 和 )*+”
结构体、共用体和枚举体
struct
: C++允许声明结构变量时省略关键字struct,也允许使用不带等号的初始化方式,但不允许缩窄转换,可以像C语言一样设置位字段来方便与寄存器对应union
:共用体可以节省空间,匿名共用体没有名称,其成员位于同一地址处,显然每次只有一个成员是当前的成员,举例如下
struct widget
{
char brand[30];
int type;
union
{
long id_num;
char id_char[20];
}; //分号要注意
};
...
widget prize;
...
if(prize.type == 1)
cin >> prize.id_num;
else
cin >> prize.id_char;
enum
:枚举体可以代替const方式定义的常量;枚举的值进行计算时会提前转换为整型,因为枚举类型并没有定义运算,但是要注意C++11的类内枚举的区别;枚举体取值范围定义如下:首先,找出上限,找到比枚举体最大值大的第一个2的幂,减去1即为取值范围的上限,计算下限,如果不小于0,则0就是下限,否则采用寻找上限一样的方法寻找下限;采用多少空间来存储由编译器决定
new、指针、数组
- 常规变量存储在栈(stack)的内存区域,而new从堆(heap)或自由存储区(free store)的内存区域分配内存;
- 面向对象编程更多的强调运行阶段(而不是编辑阶段)进行决策,指针可以使用new运算符,可在运行阶段分配内存,C++提供了检测并处理内存分配失败的工具;delete用来释放内存,如果不释放内存则有可能导致内存泄漏,而释放已经释放的内存块将导致不确定的结果;
int * d = new int;
//...
delete d;
- 编译时分配给数组的内存称为
静态联编(static binding)
,运行阶段分配的内存称为动态联编(dynamic binding)
,此数组也成为动态数组**type_name * pointer_name = new type_name[num_elements];
**;数组名和指针基本等价是C和C++的一个优点
int * d = new int[10];
//...
delete []d;
- 指针变量+1后,其增加的值等于指向的类型占用的字节数;
指针和数组操作方式很多情况下相同
,可以使用数组方括号表示法也可以使用解除引用运算符法;指针的值可以修改,但数组名是常量,而且sizeof()对数组名使用将会得到数组的长度,对指针使用只得到指针的长度;数组名表示数组第一个元素的地址,对数组名应用地址运算符时,得到的是整个数组的地址;
int a;
int * b;
int c[20];
b = &a;
b = c;
cout << c[0] << *(c+1) << b[0] << *(b + 1) << endl;//指针和数组操作类似,数组表示法、指针表示法
- new可以用来创建动态结构;如果结构标示是
结构名
,则使用局点运算符(.)
;如果标识符是指向结构的指针
,则使用箭头运算符(->)
,还可以这样(*p).name;
,但一定要加括号
分配内存方式
- C++有4种分配内存方式:
自动存储
、静态存储
、动态存储
、线程存储(C++11新增)
;
自动存储:函数内部定义的常规变量使用自动存储空间,被称为自动变量,这意味着函数被调用时自动产生,函数调用结束时消亡;
静态存储:整个程序执行期间一直存在的存储方式,定义静态变量可以定义在函数外面,也可以使用关键字static声明;
自动存储和静态存储的关键在于严格限制了变量的寿命
动态存储:使用new定义的变量,数据的生命周期不完全受程序或函数的生存时间控制,这也导致内存管理变得更复杂
vector和array模板类
- vector模板类,需要包含头文件vector,定义方式:
vector<typeName> vt(n_elem);
,n_elem可选填,可以整型常量也可以是整型变量; - array模板类,C++11新增,需要包含头文件array,定义方式:
array<typeName, n_elem> arr;
,n_elem必填,且不能是变量;array模板类长度固定,使用栈空间; - vector和array都不检测数组越界,然而两者共有的at()成员函数可以在运行期间捕获非法索引,如:a.at(1) = 3;