c++笔记
第三章 变量
-
变量名
- 只能使用数字、字母和下划线
- 数字不能开头
- 尽量不以下划线开头
- 不要使用关键字比如double
-
整型
- 术语宽度表示存储整数时使用的内存量
- 1byte=8bit
- 1kb=1024byte
- 1mb=1024kb
- sizeof()返回类型或变量的长度,单位为字节。注意对类型名使用时,要将类型名加上括号 例如sizeof(int),对变量使用时可以不加括号 sizeof n-int
- 整型溢出规则:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yWpZVP1u-1681736558247)(./sec.pic/屏幕截图_20230220_200704.png)] - cin 和cout的行为都是由变量类型引导的.
char ch=78; //char ch=N; //char ch='N'; cout<<"hello "<<ch<<" you are perfect!\n";
输出结果
hello N you are perfect!
变量类型比较
char ch; cin>>ch;
int ch; cin>>ch;
对于上述两段代码,都键入数字 5 ,第一段代码中ch的值为数字5对应的ASCII值53,而第二段则是整型数字5.
-
浮点数
#include <iostream> int main(){ using namespace std; float a=2.34e22f; float b=a+1.0f; cout << "a= "<< a <<endl; cout << "b-a= "<< b-a <<endl; return 0; }
输出
a=2.34e22 b-a=0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iTDwKElZ-1681736558248)(sec.pic/屏幕截图_20230223_153718.png)]
- 浮点常量在默认情况下为double型
- 取模运算% :返回 整数 除法的余数
整数除法结果为整数,小数部分直接省略;
系统要求float浮点数有效位数只有6位;
-
几种类型转换情况
- 将一种算术类型的值赋给另一种算术类型的值;
- 表达式中包含不同的类型;
- 将参数传递给函数。
第四章 复合类型
-
数组
- 数组是一种数据格式,可以存储多个同类型的值。
- 数组声明:
- 数组名
- 数组中的元素数
- 存储在每个元素中的值的类型
- 声明格式:typeName arrayName[arraysize],其中arraysize必须是整型常数或const值或常量表达式,总之是个已知的整数。例如int months[12]
- c++使用带索引的方括号表示法来指定数组元素,索引编号从0开始。
- 初始化规则:
- 只有在定义数组时才能初始化,也不能将一个数组赋值给另一数组,可以使用下标给单个元素赋值;
- 只对部分元素初始化,其他元素默认为0;
- 方括号可以为空,编译器自动计算元素个数;
- 初始化数组时可以省略等号;
- 大括号可以为空,表示元素全部为0;
- 列表初始化禁止缩窄转换[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-99eIxYZX-1681736558248)(sec.pic/屏幕截图_20230227_152523.png)]
-
字符串
- 字符串是存储在内存的连续字节中的一系列字符,这种特性意味着可以将其存储在char数组中。
- 以空字符作为结尾,\0,ASCII值为0;
- 字符串长度包含空字符;
- 尽量使数组长度大于字符串长度,所以使用[]即可,让编译器计算数组长度。
- 字符串允许拼接,第二个字符串的第一个字母紧跟在第一个字符串的最后一个字母之后,空字符被取代。
- strlen()返回存储在数组中的字符串的长度,且不包含空字符,也不是数组本身的长度,与sizeof()区分
- cin.getline( a, b): a:数组名称,b:读取字符数,读取指定字符数后或读取到换行符时停止。实际的读取数为b-1,因为最后会给自动生成的空字符留一个位置。
- cin.get(a,b): a,b和上述一致,在读取指定字符数后或换行符时停止,但是它存储的最后一个字符是换行符。
- 两次cin.get()连用时需要在第二次调用前加一句cin.get(),将第一次调用末尾的换行符处理掉,避免第二次调用为空。
-
string类
- string类属于std空间
- 可将其视为简单变量,一种数据类型,一个表示字符串的实体。
- 支持赋值=、合并+、添加到末尾+=
- 两种确定字符串字符数的方法:strlen(); str.size()
- 未被初始化的string对象的长度为0,而未被初始化的数组,其空字符出现的位置不定,所以长度也不定。
-
结构
- 可以储存多种类型的数据
- 结构是用户定义的类型,结构声明是结构的数据属性
- 创建结构包括两步:
- 定义结构描述:描述并标记了能够存储在结构中的数据类型;(注意每条声明语句都以分号结尾)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vle8JLFQ-1681736558248)(sec.pic/屏幕截图%202023-03-08%20171541.png)] - 按描述创建结构变量
- 定义结构描述:描述并标记了能够存储在结构中的数据类型;(注意每条声明语句都以分号结尾)
- 声明结构变量时可省略关键字struct
- 有string类时要用std::string或事先声明 using namespace std;
- 使用成员运算符(.)来访问成员:inflatable hat; hat.volume 指hat的volume成员
- 结构声明的两种方式:
- 内部声明:在函数里声明,只能在该函数里面调用;
- 外部声明:在函数之前声明,可以被其后面的任何函数使用。
- 提倡使用外部结构声明和外部符号常量声明,但不提倡使用外部变量声明。
- 初始化:
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BgZ2O7iO-1681736558248)(sec.pic/屏幕截图%202023-03-08%20190143.png)]
- "="号可省略;
- 成员用逗号隔开;
- 分号结尾;
- 大括号为空时,各成员为0;
- 不允许缩窄转换;
- 可以赋值给另一个同一类型的结构,即便成员中含有数组;
- 结构可以作为参数传递给函数,也可以让函数返回一个结构。
-
结构数组:以结构为元素的数组即为结构数组
- 初始化结构数组:数组初始化和结构初始化结合。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RmwVOf8Z-1681736558249)(sec.pic/屏幕截图%202023-03-08%20204054.png)]
- guests是一个inflatable数组,guests[0]和guests[1]为数组成员,是一个结构,所以下面的成员运算符是有效的:guests[0].name
-
枚举
- enum提供了另一种创建符号常量的方式,可以代替const
enum spectrum {red,orange,yellow,green,blue,violet,indigo,ultraviolet};该语句创建了名称为spectrum的枚举类型;
类比于结构声明:enum—struct、 spectrum—inflatable - 将red、orange等作为符号常量,这些常量称为枚举量。它们对应的整数值为0~7,在默认情况下,将整数值赋给枚举量时,从0开始依次加1
- 枚举可以使用赋值运算符:specturm band; band=blue;
- 枚举量是整型,可被提升为int整型,但int整型不可以转变为枚举类型。
int color=blue;(valid) blue=3;(not valid); color=3+red;(valid) - 如果int值是有效的,则可以进行强制类型转换赋给枚举变量。
blue=spectrum(3);(valid),但是blue=spectrum(12052);(not valid) - 如果只使用常量,而不创建枚举类型的变量,可以省略枚举类型的名称
enum {red,orange,yellow,green,blue,violet,indigo,ultraviolet};
枚举关键字enum、枚举类型名称如spectrum、枚举变量如spectrum band,band即为枚举变量、枚举量如red等
- enum提供了另一种创建符号常量的方式,可以代替const
-
设置枚举量的值
- "="显式设置枚举量的值,指定的值必须是整数。
enmu bits{one=1,two=2}; - 允许部分初始化,未被初始化的枚举量的值默认为0,后面没有被初始化的枚举量的值比前一个大1
enum bigstep{first,second=100,thrid};
first为1,thrid为101. - 允许创建多个值相同的枚举量
enum{zero,null=0,one,numebr_one=1};
- "="显式设置枚举量的值,指定的值必须是整数。
-
枚举的取值范围
每个枚举都有取值范围,通过强制类型转换,可以将枚举范围内的任何整数值赋给枚举变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RcHDspnd-1681736558249)(sec.pic/屏幕截图%202023-03-08%20215643.png)] -
指针
a. 指针是一个变量,存储的是值的地址。
b. 指针名表示的是地址,将*(解除引用运算符)用于指针,可以得到该地址存储的值。 -
声明和初始化指针
a.指针声明必须指定指针指向数据的类型:intp,指针p指向的值为int类型。int 为复合类型,是指向int的指针。
b.对每个指针变量名,都需要一个运算符。intp1,p2;创建一个指针和一个int变量p2。int p1;intp2才可以创建两个指针。
c.指针指向的值的长度可能不同(char,int等),但是地址的长度一般相同,2个或4个字节,取决于计算机。
d.示例:int a=5;int p=&a; -
指针的危险
计算机将分配用来存储地址的内存,但不会分配用于存储指针指向的数据的内存。例如:longfellow; fellow =23330; 第一句代码为fellow创建了一个内存地址,但没有定义fellow的值;第二句代码将fellow指向了数据23330。也就是说我们知道fellow是23330的指针,其值应该是23330的地址,但由于fellow的值并未定义,且计算机不会为23330分配内存,所以23330的地址就是未知的,是随机的。
要避免指针的危险,就要在使用 * 运算符前,将指针初始化为一个确定的、合适的地址。 -
指针和数字
a.指针不是整型,虽然计算机通常把指针当作整数处理。
b.不能将整数简单地赋给指针。例如:
intpt;
pt=0xB8000000; (type mismatch)
pt=(int )0xB8000000; (强制类型转换后type match) -
使用new分配内存
a.为一个数据对象(可以是结构,可以是基本类型)获得并指定分配内存的通用格式如下:
typeNamepointer_name = new typeName;
int pn = new int; new运算符根据数据类型(此处为int)确定需要多少字节的内存,然后找到这样的内存并将地址返回给pn。
b.常规声明变量分配的内存块存储在栈(stack)的内存区域,而new从堆(heap)或自由存储区(free store)的内存区域分配内存。 -
使用delete释放内存
a.使用delete时,后面加上指针即可。
int* ps = new int;
delete ps;
这将释放ps指向的内存,但不会删除ps指针本身。
b.只能用delete释放new分配的内存,不可以释放常规声明变量的内存。 -
使用new创建动态数组
-
静态联编(static binding):在编译时给数组分配内存。
-
动态联编(dynamic binding):在运行且需要时给数组分配内存,而且可以在运行时选择数组的长度。
-
通用格式:typeName*pointer_name = new typeName [num_elements];
示例:int* ps = new int [10]; new返回第一个元素的地址并将其赋给ps。
对于new创建的数组,应该使用delete[]释放内存。int* ps = new int [10]; delete [] ps;
[]表明delete释放了整个数组,而不仅仅是指针指向的第一个元素。
-
使用new和delete的一些规则
- 不能使用delete释放不是new分配的内存。
- 不能使用delete释放同一个内存块两次或以上。
- 如果使用new[ ]分配内存,则应使用delete[ ]来释放内存。
- 如果使用new[ ]为一个实体分配内存,则应使用delete来(不带方括号)释放内存。
- 对空指针使用delete是安全的。
-
-
使用动态数组
- 指针和数组具有基本等价性。引用上述例子,ps[0]是动态数组的第一个元素,* ps也是第一个元素的值。ps[1]是第二个元素,
- 指针是变量,因此可以修改它的值。在动态数组中,指针数加1代表指向下一个元素,与元素本身占几个字节无关 。即指针变量加1后,其增加的值等于指向类型占用的字节数。
-
指针、数组、指针算术
- 多数情况下,数组名解释为第一个元素的地址。
int wages[3]={1,2,3};
如下等式是成立的:wage = &wage[0];
但在计算数组长度时数组名不代表第一个元素的地址。
sizeof(wage),返回整个数组的长度,12个字节长度。
- 多数情况下,数组名解释为第一个元素的地址。
-
指针与字符串
- 如果给cout提供字符的地址,则它将从该字符开始打印,直到空字符结束。
- 在cout和大多数情况中,char数组名、char指针以及加引号的字符串常量都被解释为字符串的第一个字符的地址。
- 示例:
#include<iostream> #include<cstring>//字符处理应当包含的头文件 int main(){ using namespace std; char animal[20]="bear"; const char* bird = "wren";//字符串字面值是常量,const表面可以用bird来访问该字符串,但不可以修改 char* ps; cout << animal << " and "<< bird << endl; cout << "Enter a kind of animal: " ; cin >> animal; ps =animal;//此处为指针赋值,只进行地址复制,而不会复制整个字符串到ps cout << ps<<"!\n"; cout << "Before using strcpy():"<<endl; cout << animal << " is at "<< (int*)animal<<endl;//一般来说,给cout提供一个指针,它将会打印该地址;但是如果指针的类型是char,则cout将会打印字符串而不是地址。如果想要打印地址,需要强制类型转换。 cout << ps << " is at "<< (int*)ps << endl; ps = new char[strlen(animal)+1];//分配准确的长度来保存animal的所有内容,注意这里最后加上一个字节存储空字符,使cout完成打印停止。 strcpy(ps,animal); cout << "After using strcpy():" << endl; cout << animal << " is at "<< (int*)animal<<endl; cout << ps << " is at "<< (int*)ps << endl; delete [] ps; return 0; }
- strcpy(a,b);a代表目标地址,b代表要复制字符串的地址;
- strncpy(a,b,c);c代表要复制的最大字节数,其余两个参数与上述一致。
-
使用new创建动态结构
- 创建结构:
inflatable* ps = new inflatable
,inflatable为结构类型名称。 - 访问成员:
- a.箭头运算符 -> 用于指向结构的指针,
ps->price;
代表ps指向的inflatable结构中的price成员; - b.
ps->price;
等价于(*ps).price;
注意小括号的位置。
- a.箭头运算符 -> 用于指向结构的指针,
- 创建结构:
-
自动存储、静态存储和动态存储
- 在函数内部定义的变量使用自动存储空间,称为自动变量。
- 特点:在所属的函数调用时自动产生,函数结束时自动消亡;
- 存储在栈中,变量释放内存时遵循后进先出的原则。
- 静态存储是变量在整个程序运行期间都存在的存储方式。
- 声明方式:在函数外定义变量或者使用关键字static.
- new和delete运算符被认为管理一个内存池,称为自由存储空间或者堆(heap)。
- 区别:在栈中,自动添加和删除机制使得占用的内存总是连续的,但动态存储可能导致占用的内存不连续,这使得跟踪新分配内存的地址更加困难。
- 在函数内部定义的变量使用自动存储空间,称为自动变量。
-
内存泄漏
- 如果使用new运算符在堆上创建变量后没有使用delete,即使包含指针的内存由于作用域规则和对象生命周期的原因被释放,但之前分配的变量还是存在,但我们却无法访问它,因为指向这些内存的指针已经无效,这就导致内存泄漏。被泄露的内存在程序的整个生命周期都不可使用,内存被分配出去却无法收回。极端情况是内存被耗尽,程序崩溃。
-
模板类vector
- vector属于动态数组,本质上也是通过new,delete来完成操作的,但这个过程是自动完成的。因此其存储在堆中。
- 使用一段代码来举例
#include<vector>//包含头文件 ... using namespace std;//vector包含在名称空间std中 vector<int>vi;//创建一个int型空"数组" int n; cin>>n; vector<double>vd(n);//创建一个长度为n的double"数组"
一般而言,声明vector的格式为:
vector<typeName>vt(n_element);//n_element可以是整型常量或者整型变量。
-
模板类array
- 与数组一样,array的长度是固定的,且存储在栈。
#include<array> ... using namespace std; array<int,4>ai;//创建包含5个int变量的array array<double,5>ad={1.2,2.0,2.3,2.4};//声明和初始化
一般格式:
array<typename,num>ai;
num为整型常量,不可以是变量。 -
三者的区别
- 都可以使用索引法访问成员。
- array和数组存储在栈中;而vector存储在堆中。
- array可以直接复制给另一个array,而数组的复制需要逐个元素复制。
- 数组的索引不检查边界错误。
a1[-2]=20.2;
这行代码代表将20.2存储到(a1-2)的地址对应的内存。