1、数组的声明与初始化:
//数组的声明与初始化
int arr1[3] {12,3,2}; // 列表初始化禁止缩窄转换,如int arr[]{22.0}
int arr2[3] = {12}; // 第一个设置为12,其他为0
int arr3[3];
int arr4[] = {1,2,3,4,5}; // C++编译器将计算元素个数
arr3[0] = 1;
arr3[1] = 1;
arr3[2] = 1;
2、字符串
C类字符串为char类数组或指针声明的字符串,以\0为字符串结尾;cout逐个输出字符串中的字符,直至遇到\0。字符串常量不能与字符互换,虽然编译器不会报错,但是互换后字符串常量为空。
char* a = "aaaa\0bbbbb" // 这种字符串被称为字符串常量或字符串字面值
cout<<a; // 输出aaaa
char b[10]{"abcd"};
strlen(b); // 返回数组长度
sizeof(b); // 返回字符串长度,不把空字符计算在内
cin使用空白(空格、制表符、换行符)来确定字符串的结束位置,这意味着cin在获取字符数组输入时只读取一个单词。读取该单词后,cin将该字符串放到数组中,并自动在结尾添加空字符。
cin的getline()和get()函数:
getline(char*, int)函数每次读取一行,通过换行符确定行尾,但不保存换行符,用空字符替换换行符。
get(char*, int)函数每次读取一行,通过换行符确定行尾,保存换行符。需要通过cin.get()来读取缓冲区内的一个字符(换行符),不然get(char*, int)将一直被困在换行符位置处,无法继续读取。
当get()读取到空行时,将设置失效位failbit,这意味着接下来的输入将被阻断,需要用cin.clear()来回复输入。如果输入字符串比指定空间长,会将剩余的字符留在队列中,getline()会设置失效位,并关闭后面的输入。
string和字符数组之间的主要区别:
可以将string对象声明为简单变量,而不是数组
3、结构体(使用struct声明):
结构体默认成员为public,类的默认成员为private,其余属性完全相同。
struct //创建一个匿名结构体,并创建一个position结构变量
{
int x;
int y;
}position;
4、共用体(使用union声明):
只能存储int ,long,或double
共用体能够存储不同数据类型,但只能同时存储其中一种类型。匿名共用体用法跟匿名结构体用法一样。
union sss
{
int a;
long b;
double c;
};
int main ()
{
sss u;
u.b = 100;
cout<<u.a<<endl; //100
cout<<u.b<<endl; //100
cout<<u.c<<endl; //1.79678e-307
return 0;
}
5、枚举:
枚举提供了一种创建符号常量的方式,这种方式可以替代const
enum spectrum
{
red,
yellow,
orange = 20,
blue,
green
};
//上述枚举中,符号常量的值默认从0(red=0)开始递增,
//若自定义赋值,如orange=20,那么blue为21,green为22
可以将枚举转换为int,但是不可以将int转换为枚举 (可以进行强制转换)。
可以创建多个值相同的枚举量。
将整数强转为枚举值时,需要考虑枚举的最大值和最小值。枚举中最大值和最小值计算:最大值为最小的大于枚举中最大的值的2的幂再减1,便得到上限。如最大枚举值为101,那么上限就是2的7次方再减一,也就是127。下限如果枚举值都大于0,那么下限为0,不然采用寻找最大值的方式找最小值,再取符号。
6、指针:
指针是一种复合类型,以下的指针和变量的值都存储在被称为栈(stack)的内存区域中
//int* 是一种复合类型,指向int的指针
int *p1, val = 10; // 创建一个指针名为p,和一个int变量val
p1 = &val; // 两种方式给指针赋值
*p1 = val;
以下为在堆中创建一个内存区域,存储p2和p3指向在堆中创建的内存。
int* p2 = new int(4);
int* p3 = new int;
delete(p2);
delete(p3);
还可以使用new创建数组大小运行时才确定的动态数组
int num = 10;
int* arr1 = new int[num]; //使用new创建动态数组,称为动态联编
int arr2[10] ; //创建静态数组,从称为静态联编
delete[] arr1;
使用new和delete时应遵循以下规则:
1、不要使用delete释放不是new分配的内存。
2、不要使用delete释放同一块内存块两次。
3、如果使用new[]为数组分配内存,则应使用delete[]来释放。
4、如果使用new为一个实体分配内存,则应使用delete来释放。
5、对空指针应用delete是安全的。
关于指针的零碎小知识:
1、对指针变量进行加1后,增加的量等于它指向的类型的字节数。
2、无论是静态数组还是动态数组,如stacks[1],C++编译器将该表达式看作是*(stacks+1)。
3、对数组应用sizeof运算符得到的是数组的长度,对指针应用sizeof运算符得到的是指针的长度。
int tell[10];
int (*pas)[10] = &tell;
以上数组tell,&tell[0]和&tell得到的都是数组tell的首地址,但是前者是一个4字节的内存卡地址,后者是一个40字节内存卡的地址。因此表达式tell+1是将地址加4,&tell+1是将地址加40。也就是说,tell是一个int指针,&tell是一个指向包含10个元素的int数组的指针。
可以通过int (*pas)[10] = &tell; 表示&tell,如果省略括号。优先级规则将使得pas先与[10]结合,导致pas是一个int数组,他包括10个元素,因此括号不能少。其次,如果要描述变量的类型,可将声明中的变量名删除。因此,pas 的类型为int(*)[10]。另外,由于pas被设置为&tall,因此*pas与tell等价,所以(*pas)[0]为itell数组的第一个元素。
int a=0,b=1,c=2;
int* aa[3] = {&a,&b,&c};
int** bb = aa;
cout<< *aa[1]<<endl;
cout<< **(bb+1)<<endl;
指针数组和二维指针:如上代码,指针数组和二维指针可以相互转换。
7、自动存储、静态存储、动态存储
在C++中,内存分成5个区,他们分别是堆、栈、*存储区、全局/静态存储区和常量存储区
1.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
2.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
3.*存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
4.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
5.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)
C++有四种管理数据内存的方式:自动存储、静态存储、动态存储和线程存储(先不介绍)
1、自动存储:函数内部定义的常规变量使用自动存储空间,这种变量被称为自动变量,在函数结束时消亡,其作用域为包含它的代码块。自动变量存储在栈中,在执行代码块时,其中的变量讲一次加入到栈中,而在离开代码块时,将按相反的顺序释放这些变量。在程序执行的过程中,栈将不断地增大和缩小。
2、静态存储:静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是声明变量时使用关键字static。
3、动态存储:new、delete、malloc、free提供了比自动变量和静态变量更灵活的方法,管理了一个内存池(在C++中被称为堆或*存储空间)。