c++ Primer Plus(第四章)

第四章

1.数组初始化规则

  • 数组不能相互赋值,因为数组名本质上是const指针
  • 数组如果不用花括号进行初始化,那么值是未知的,如果未全部初始化,即花括号元素小于数组大小,那么编译器将会把其他元素全部初始化为0(所以把数组所有元素初始化的方式是显式设置为0)
  • c++11新规则
    • 初始化数组时候,可省略等号,大括号内可以不以不包含元素,系统默认设置为0
      1
      int count[10]{};//元素全部被设置为0,同时这种列表初始化方式不允许,精度丢失的转换
  1. 字符串
  • 字符串与字符数组

    • 字符数组如果没有显式包含’\0’,那么不是字符串,只是字符数组,反之为字符串(将之当作字符串处理使用一些库函数将出错)
  • c++中允许以下的方式初始化(不必显式包含’\0’)

    1
    char [10]="hello";//“hello”字符串隐式包含'\0'
  • c++输入工具通过键盘输入时,将字符串读入到char数组时,将自动加上结尾的’\0’;

  • 以字符串常量初始化数组时,应该保证数组足够,能装下字符串+’\0’

  • “S”=’S’+’\0’; 注意与单个字符不一致

  • 字符常量拼接

    • 事实上,任何两个由空白(空格,制表符和换行符)分隔的字符串常量都将自动拼接为一个
      1
      2
      3
      4
      5
      6
      cout<<"hello world";
      cout<<"hello " "world";
      cout<<"hello"
      "world";
      //这三种输出均等价
      //应该注意,拼接时不会在连接的字符串中添加空格。第一个字符串的\0将被第二个字符串的第一个字符覆盖
  1. 字符串cin输入

    • cin用空白(空格,制表符,换行)作为字符串的结束位置,也就是说,如果使用cin>>str,来为str赋值,那么输入的字符串不能被空白符间隔开来,否则系统将会留下后半部分在队列中,等待下一次输入,同时作为结束标志的换行符会被留在队列
  2. 读取一行的输入

    • 基于上面所说的问题,iostream中的类(如cin),提供了一些类成员函数
      • getline()
        • getline()函数读取整行,他使用通过回车键来确定输入结尾。调用 cin.getline().该函数有两个参数,第一个参数用来存储输入行的存贮地址,即数组名。第二个参数是读取字符数(包括\0),即参数设置为20,那么最多读取19个字符。(在碰到换行符或者到达指定的数目时停止读取,(并且丢弃换行符(丢弃指缓冲区都没),如果是以换行符结束)
      • get()
        • get()接受参数与工作方式与getline()相似,但是并不丢弃(但也不读取,而是留在缓冲区(带参数的get(name,len)))\n,而是将其留在输入队列。即连续两次读取,第二次读取将会应为读取到\n,而终止
        • get()的重载函数,不带参数的get()可读取下一个字符,即使是换行符\n,可以使用这个函数来吸收留在缓冲区的换行符
1
2
3
cin.get(name,len);//返回一个cin对象
cin.get();
//上面两句等价与 cin.get(name,len).get();
  1. 空行和其他问题
  • get()(不是getline())读取空行后将设置失效位置(failbit)阻断输入,可以使用cin.clear();来恢复
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main()
    {
    char s1[20],s2[30],s3[30],s4;
    cin.get(s1,20);
    cin.get();
    cin.get(s2,20);//空行
    cin.get();
    cin.get(s3,20);
    puts(s1);
    puts(s2);
    puts(s3);
    }

程序截屏

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
char s1[20],s2[30],s3[30],s4;
cin.get(s1,20);
cin.get();
cin.get(s2,20);//空行
cin.clear();//读取空行后,应该立即重新设置,否则get()无法读取换行符,产生错误
cin.get();
cin.get(s3,20);
puts(s1);
puts(s2);
puts(s3);
}

程序截屏
1dcd7dccec6a39b13e3dd9ce2032c49e.png

  • 当输入字符串长于可分配空间,get()和getline()将把余下的字符留在缓冲区,getline()还会设置失效位,关闭后面的输入

6.String

  • c++11允许使用列表初始化字符串和字符数组 string s1={“hello”}
  • string 的赋值拼接和附加
    • string类变量允许使用等号直接赋值,字符数组不行
    • string类可是使用+号合并两个字符串,使用+=追加字符串
    • string 类 + 等价与 c的strcop(charr1,charr2):第一个,第二个参数都为数组名,函数的意义是把第二个参数赋值给第一个,但是有可能因为数组长度问题,发生内存错误
    • +=等价对于strcat(charr1,charr2):c++中,第二个可以为字符串常量,如果字符串常量大于数组的,那么不会为数组添加\0,并且剩余部分继续覆盖,可能会覆盖其他程序所需要使用的内存

7.string类i\o

  • string 类处理字符串与字符数组不同,处理字符串默认按行读取
  • 声明一个string对象,但是不初始化那么系统默认为零,但是会随着后面的输入而自动变化
  • 输出string的类方法(非>>)getline(cin,stringob);

8.c++结构体的特性

  • c++中结构体可以有成员函数
  • c++结构体初始化 inflatable duck{X,x};,如果花括号为空,那么所以成员都会被初始化为0

9.位字段

  • 在结构体正常的声明后面加:和数字,数字代表这个变量所被允许使用的位数

10.共用体

  • 共用体除了关键字位union,其他声明与结构体相同,不同的是共用体共用地址,所以共用体大小取决与最大那一给变量,(通过使用共用体的不同变量完成类型转换,名共用体所有成员成为相同地址的变量,相当于同一地址的不同名称(但是与类型有光)

11.枚举

  • 枚举只有赋值=运算符,不存在+,++等
  • 枚举只能被赋予花括号中声明的值(才有意义),但是可以通过在适当范围的整数强制转换位对应的枚举值,不在范围的被转换的结果是未知的
  • 枚举值只能是整数(long long long int均可),并且没显式指定的枚举值比前面的大1,如果都没指定,那么第一个默认0,枚举值可以显式指定为相同

12.指针

  • c++中int* 是一种复合类型,表示int类型的指针
  • int p1,p2`,**p1是指针,p2是int变量**!对于c++中每个指针变量都需要一个

13.new与delete

  • new(凡是动态开辟的变量)存在堆中,int,double等在堆栈
  • new开辟的动态空间存class对象才会自动调用构造函数和析构函数
  • delete删除的内存并不会删除指针,所以需要将指针重新指向
  • 对已经delete的空间delete将会产生不确定的结果
  • 删除多个连续空间,用delete[] p;

13.数组名与指针的区别

  • 指针可以指向其他地方,但是数组名不能,代表一个常量
  • sizeof算指针是指针的长度(1),但是算数组名是数组长度
  • int arr[10] &arr和arr在值上是相同的,都是地址的值,但是arr等价于&arr[0],这代表对arr+1每次加4,指向数组下一个int元素,但是&arr+1(arr+10),一次加的数组长度
  • 给指针赋值相当于给给指针一个地址,两个指针指向同一块地址

14.指针与字符串

  • 字符串常量相当于其首地址
  • c++并不能保证字符串字面值被唯一的存储,也就是说相同字面值的字符串,可能有多个副本也可能一个