C++ Primer Plus学习笔记-第四章:复合类型

第四章:复合类型

声明数组:typeName arrayname[arraySize],可以用一个逗号隔开元素的大括号包括的列表初始化数组,可以不指定数组长度编译器会自动计算

只有在定义数组的时候才能使用初始化

初始化数组时提供的值可以少于数组元素数,未覆盖的元素初始化为0,初始化时可省略等号,列表初始化禁止缩窄转换

C风格字符串以’\0’结尾,ASCII码为0

cstdlib中的strlen()函数只计算有效字符,空白符和结束符都不计;sizeof算符机械统计数据长度

用引号囊括的字符串隐式以’\0’结尾,键盘输入的字符串也会被系统自动加上’\0’

两个字符串挨在一起时,会被紧密的连接在一起成为一个字符串(任何两个由空白符连接的字符串都会自动连接)

cin使用空白符确定字符串结束的位置,也就是说一次读取一个单词,每次读取一个单词后还自动添加’\0’

cin.getline()和cin.get()都一直读取直到遇到换行符,前者不保留换行符后者保留换行符

cin.getline()通过回车键确认一行的结束,第一个参数是数组名,第二个参数是数组大小;在读取了指定字符数或遇到换行符时停止;

cin.get()参数格式和cin.getline()相同,但不读取换行符,而是直接留在输入队列中

使用不带参数的cin.get()可以读取下一个字符,因此这种写法可以解决遗留的换行符:

cin.get(arrayName,arraySize).get();

C++允许函数有多个版本,只要参数表不同

cin.get()读取空行后会设置阻断位,cin.clear()可以清除阻断;cin.getline()不存在类似问题;

如果输入的字符数比数组的指定大小多,cin.getline()和cin.get()会将剩余的字符留在队列里,cin.getline()还会设置失效位来关闭后面的输入

字符串有专门的类:string类,位于命名空间std,还要包含头文件;string类型可以用+拼接,可以赋值

头文件提供了处理数组字符串的函数,如strcpy(s1,s2),strcat(s1,s2),前者把后者赋值给前者,后者把后者接在前者后面

string类有一个size()方法,可以计算字符串长短,普通的C风格字符串要使用strlen()计算长短,在中;

向string类输入时使用函数getline(cin,具体的string对象名)

未被初始化的string对象长度是0;

wchar_t类字符串前缀是L,char16_t前缀是小写u,char32_t前缀是大写U;,字符串前缀为u8表示UTF-8编码

R来标识原始字符串,可以设置开闭符,建议永远使用格式:"+ * (内容) * +"

结构体(struct)的基本格式:

struct inflatable
{
    char namr[20];
    float volume;
    double price;
};  //注意这里有一个分号

创建结构体后就可以像int,double关键字那样使用结构体名称了,且C++允许在声明结构体变量的时候省略关键字struct

结构体成员可使用成员运算符(.)来访问

位于函数外部的声明可以称为外部声明,对所有函数都可见,函数内部的声明只对函数本身可见;不提倡使用全局变量,但提倡使用全局结构体

C++支持使用列表初始化结构体,且等号是可选的,若大括号为空则所有成员被设置为0

可以使用等号(=)将一个结构体赋值给另一个同类型的结构体,即使结构体中存在数组也能生效

可以创建元素为结构体的数组

结构体中可以使用位字段:

struct torgle_register
{
    unsigned int sn : 4;
    unsigned int : 4;
    bool goodIn : 1;
    bool goodTorgle : 1;
}

共用体的关键字是union,能够存储不同的数据类型,但同时只能存储一种,长度为最大元素的长度;常用于在像嵌入式这样的设备中节省内存;

枚举也是一种创建常量的方式,例如:

enum spectrum {red, orange, yellow, green, blue, violent, indigo, ultraviolent};
//spectrum成为了新的类型名称
//枚举元素默认第一个是0,后一个比前一个大1

将非enum值赋值给enum变量会引起错误,只能赋同类型的值,但枚举变量可以通过升级来进行更高级的运算(C++中没有定义有关枚举变量本身的算数运算)

为了获得最大程度的可移植性,应把非enum值赋值给enum变量视为错误

但在一个int值是有效的枚举值时,可以通过强制类型转换赋值给枚举变量:

band = spectrum (3);
//强制类型转换

每个枚举都有取值范围,通过强制类型转换可以赋给枚举变量此前没有定义过的值;大小的上下限要保证不会溢出;

找到大于这个最大值的,最小的2的幂,将它减去1,得到的便是取值范围的上限

&符号可以运算得到一个变量的地址,*可以解除这种引用关系,使用cout显示地址时自动以十六进制显示;指针声明必须指出指针指向的数据类型
指针的声明方式:

int * p;
//对于每个指针变量,前面都必须有*符号;

警告 一定要在对指针解除引用之前,将指针初始化为一个确定的适当的地址!如果不这么做,则可能对导致难以排查的的崩溃问题!

指针不是整型,因此不能简单的将整型数字赋值给指针,但可以通过强制类型转换执行:

pt = (int *)0xB8000000
//将整型转换为指向整型的指针类型

new关键字可以分配能容纳指定对象大小的内存,并将结果作为指针返回,而在C语言中malloc()函数可以起到分配内存的作用

比如: int * p = new int;,分配一块大小为int的内存,把内存块的地址赋给指针p,这样分配的内存只能通过指针来读写

内存分配的通用格式:

typeName * pointer_name = new typeName;

new分配的内存块和常规变量分配的内存块不同,常规变量存储在"栈(stack)"中,new则从"堆(heap)"中或"自由存储区(free store)"中申请空间;

栈和堆的区别是:前者存储的变量根据"后进先出"的原则创建和销毁,堆则不具有任何自动属性(只有在程序退出时会销毁所申请的内存);因此在某个函数中使用new关键字申请到的变量完全可以在函数运行结束之后继续存在,只有程序结束和关键字delete能销毁它们;

delet运算符释放new分配的内存

在编译时给数组分配内存称为静态联编,执行中分配内存称为动态联编;,也存在动态数组;

new返回第一个元素的地址;delete释放内存空间,而下面这样:

delete [] psome;
//释放整个数组的内存,而不是数组的第一个元素;
//如果new时带方括号,则delete时也要带方括号

使用new和delete时要注意:

不要使用delete释放不是new分配的空间
不要使用delete释放同一个内存块两次
使用 new[]为数组分配内存,则应使用delete []释放
使用new分配的内存,使用delete释放
对空指针使用delete是安全的

不能使用sizeof来确定动态数组包含的字节数

为数组分配内存的格式

type_name * pointer_name = new type_name [size];

对于一个指向数组的指针,可以直接把指针名当数组名使用,但数组名使用sizeof算符得到数组长度,指针只得到指针变量的长度(即使它指向指针);

总之,如果提供给cout一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止;在cout和多数C++表达式中,char数组名,char指针以及用括号引起的字符串常量都被解释为字符串的第一个字符的地址;

使用cout打印字符串第一个元素的地址的时候可能有问题:程序自动打印了整个字符串,使用(int *) p就可以解决问题了;原理是将一个默认代表整个字符串的指针强制转换为了一个常规指针;

字符串被C++解释为常量;

当然为了解决这些问题,可以直接使用string对象;

strcpy()接受两个参数,将后一个参数复制进前一个参数,可以在函数strncpy()的第三个参数中指定最大写入字符数;但如果函数是因为写入了足够的字符数而结束的,就不会在末尾添加结束符,需要手动添加,比如:

strncpy(p,"超长的字符串",19);
food[19]='\0';

如果该字符串小于19个字符,则strncpy()将在复制完该字符串后加上空字符以标记字符串的结尾

在运行时创建数组优于在编译时创建数组;创建一个指针指向分配了结构体的内存空间的方式:

inflatble * ps = new inflatable;

创建动态结构时,不能将成员运算符句点用于结构名,因为这种结构没有名称,只有知道地址;可以使用箭头(->)运算符访问结构体成员;

如果结构标识符是结构名,则使用句点运算符;如果表示运算符是指向结构的指针,则使用箭头运算符;

以下是变量的种类:

  1. 自动变量,属于局部变量,作用域为包含它的代码块,储存在栈中,执行代码时其中的变量依次压入栈中,在离开代码时反向释放这些变量,被称为后进先出(LIFO),在程序执行的过程中栈会不断的放大缩小;

  2. 静态存储,在整个程序执行期间都有效;有两种实现方式:在函数外定义它或在声明变量时使用static关键字;

  3. 动态存储,使用new和delete这两个关键字进行动态内存分配,管理一个称为"自由存储空间(free store)"或"堆(heap)"的内存池,和静态变量自动变量是分开的;

模板类vector和array是数组的替代品;

模板类vector类似string类,也是一种动态数组,可以在运行阶段设置vecter对象的长度,可在末尾附加新数据,还可在中间插入新数据;必须包含命名空间std
声明一个vector变量:

vector<typeName> vt(n_elem);
//圆括号中的内容是可选的
//要调整长度需要vector包中的各种方法

模板类array也存在于命名空间std中,和数组一样对象长度固定,也使用栈,要创建array对象要包含头文件
声明一个array变量:

array<typeName,n_elem> arr;
//需要在尖括号中指明类型和长度

可以在vector和array中使用方法.set()来过滤非法的索引访问,成员函数begin()和end()能够让函数确定边界

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值