C++ primer分章节快速回顾

时间:2023-03-09 15:05:52
C++ primer分章节快速回顾

第三章:

1,sozeof(int); int n_int=INT_MAX; sizeof n_int;(对变量括号可选)

2,#include<climits>包含一些类型的最大值
3,count 默认显示十进制, cout<<dec(默认) count<<hex count<<oct
4,bool, char, short, int, long, longlong, float, double, long double
5,count.setf(ios_base::fixed,ios_base::floatfield)//防止大的数切换到E表示法,显示小数点后6位小数(保留0)
6,C++风格 typeName(value)
7,变量初始化 int wren(23); int wren=23;
8,C++ const和#define区别:
(1)const 编译阶段使用,define是在预处理阶段展开;
(2)const可以指定类型,做安全检查,而define没有
(3)const可以在限定在指定区域
(4)const用于更复杂的类型,数组,结构体(大对象要分配内存,或extern声明或对其取地址时也要分配内存)
(5)const常量定义基本类型时放在符号表中(堆或栈),而define仅仅是展开,不分配内存
9常量的类型:L,l; U,u; ul,UL;

10 类型转换 float运算不提升为double,int型整数被赋给float时截取小数

***常量折叠:#define和const,const定义常量,你不能尝试通过更改变量的值去改变它,但是可以通过引用它的地址来改变,即通过指针。常量折叠说的是,在编译阶段,对该变量进行值替换,同时,该常量记录在符号表中,和define还不一样,有三种情况下,会为const分配内存。
实例:#include<iostream>
int main()
{
using namespace std;
const int i=20;
int *p=(int *) &i;//改变i内存地址上的值
*p=10;

cout<<(int *)&i<<":"<<i<<endl;//这个i在编译阶段已经被20给替换了
cout<<p<<":"<<*p<<endl;
return 0;
}
结果显示0012FF44:20
0012FF44:10

第四章:
1,数组只能定义时初始化,int hand[500]={0},此后只能单个单个元素赋值; 不能数组间赋值
初始化数组为{1}时,只有第一个元素是1,其它置0
a=int[10];sizeof a 数组字节数10*4; sizeof a[0] int类型字节数4

2,字符串数组 char cat[5]="C+owby"或 char cat[]="....."; count<<cat打印字符串,而非地址;

3,字符串输入:cin通过空白(space,\b,\n)来定界,不能读空格;
cin.getline(name,20),遇到\r,\n停止,丢弃换行符,最多读19个char;
cin.get(name,20).get()或name=cin.get();cin.get();cin.clear()
* 用cin>> 连续读入时,注意每次读入字符或数字时,cin,get()或者(cin>>value).get()处理掉字符流中的回车生成的\n

4,读数字 cin>>year;cin.get()处理空行,防止阻断输入

5,#include<string> string类在名称空间std中 使用前必须声明useing namespace std;
和字符串数组不同,相互赋值:str1=str2; 拼接:str1+=str2;读入:getline(cin,str1)(这是个函数,不是cin的类方法)

6,对比#include<cstring>,
void strcat(char *t,char *s){ while(*t++=*s++);}字符串拼接
strcpy(char *t,char *s);

字符串长度:string类方法 len=str1.size()(不计'\0'), 字符串数组 len=strlen(charr1)(cstring 中的函数,不计\0)
读入方法: 字符串数组 cin.getline(name,20), string:getline(cin,str1);

7,struct 可以相互赋值, 成员分隔定义时用;赋值时用,可以整体赋值,可以结构数组

8, union, enum spectum{oen,two=0,three=8,four};spectum myflag=one;

9,指针:使用前一定要有指向地址!cha c='a',*p=&c; (int*)强制转换为两个字节的地址类型,(double*)四个字节

10,new/delete 和malloc/free比较:
new/delete是操作符,而malloc/free是库函数,都是用于申请动态内存和释放动态内存的
  对非内部数据类型的对象而言,malloc/free不能执行构造函数和析构函数,注定只能用于C
  而new/delete可以胜任
11,new/delete条例:内存耗尽返回0(null pointer)可以被释放;不是new开辟的内存就不要用delete去释放;一个地址只能释放一次,无论多少指针指向它
12,指针和数组名:基本相同,根本区别:数组名是指向第一个元素的地址常量,不能被赋值!
  指针或数组名加1是指向下一个地址块,即下个元素
13,cout的智能化:cout<<array;array是数组名,cout自动辨别是否为字符串数组(试了下,char数组就可以,比如字符数组char array[]=['a','b',' ','c']也可以)或string或char*,若是打印数组内容;其它则打印数组首元素地址

 #include<iostream>
#include<cstring>
#include<string> using namespace std;
int main()
{
string str1="hello";
cout<<str1;//打印字符串内容
char array[]="hello word"; cout<<endl<<array<<endl;//打印字符串数组内容
int mm[]={,,,,,};
cout<<mm<<endl;//打印整型数组地址 char c='a',nn[]={'a','b','c','d','e','f'};
cout<<"nn is:"<<nn<<endl;//打印字符型数组内容,但是由于n[4]后面的没有初始化,乱码
char *p1=new char[strlen(nn)+];
cout<<"strlen:"<<strlen(nn)<<endl;//strlen只是针对字符串数组有用!!12是怎么来的?
strcpy(p1,nn);
cout<<p1<<endl;//同打印nn一样,后面未初始化的依然乱码
cout<<*p1<<endl;//首个元素内容 char vv[]="hello word!!!";
cout<<vv<<endl;
cout<<"strlen:"<<strlen(vv)<<endl;
char *p2=new char[strlen(vv)+];//这次可以了 13
strcpy(p2,vv);
cout<<p2<<endl;//打印出hello word
delete [] p1;
delete [] p2;
return ; }

第五章:
1,前缀后缀++,对自己定义的对象来说,前缀效率更高;++p优先级同*,p++比*优先级高,从右到左计算,这样:
double arr[]={21,32,23,45,37};
double *p=arr;
++p; // 32 arr[1]
*++p; //23 arr[2]
++*p;//24 arr[2]
(*p)++;//25 arr[2] p这里就是arr的别名,arr是个地址常量,指向同一块内存
*p++; //后缀,当前命令行不加1,25,arr[3]

2,逗号表达式,右边的值为主

3,string字符串比较, 直接string word=“....”; if (word=="...."){....} C 风格 <string.h> strcpm()函数相同返回0否则回>0,<0

4,for(;;) while() do{} while();注意这里有分号

5, <ctime> clock_t 时间类型 clock()返回当前的clock_t类,就是long别名;CLOCKS_PER_SEC常量,代表每秒包含系统时间的 数量,可用来计算算法elapse time或者做延时函数

6,类型别名 #define Byte char // 宏 typedef Byte char;

7, cin不读空格,按下enter结束 多余的输入缓冲,下次读

8,cin.get()函数重载,三种读取方式,遇到换行符结束,不丢弃:cin.get(ch),cin.get(charr,10),cin.get()用来读回车产生的 换行符

9,EOF cin.eof() cin.fail() cin.clear()

10,int ch=cin.get()返回一个int型,cin.put()

11 二维数组

第六章:
1,&& and, || or, not !

2(**),#include<cctype> cctype函数库:(函数)
*isalnum(ch) 字母或数字,返回true
*isalpha() 字母,返回true
isblank() 空格或制表符 true
iscntrl() 控制字符 true
*isdigit() 数字(0~9) true
isgraph() 空格之外的打印字符 true
*islower() 小写字母 true
isprint() 打印字母(包括空格)
*ispunct() 标点
*isspace() 标准空白字符
*isupper() 大写字母
isxidigit() 十六进制数字 0~9, a~f, A~F
*tolower() 大写变小写
*toupper() 小写变大写

python中(类方法):
s.isalnum()
s.isalpha()
s.isdigit()
s.uslower()
s.isupper()
s.istile()
s.isspace()

3, switch语句的case标签必须是整数(char,int,long,longlong),enum做标签提升为int

第七章 函数
1,函数原型的必要性:告诉编译器函数的返回值和参数类型,以便编译器进行正确读取,可能的话进行转换(都是算术类型且可以 转换)

2, int a=0; const int *p = &a; *p的值不能通过指针改变,但可以由a改变(前提是 a没有const声明),p指向的地址可以变, 比如 p = &b;
int a=0; int * const p = &a; p和&a绑定死了,不能指向别人了,意味着这种指针必须声明时初始化,和引用效果一样。 但可以通过*p=1来 改变a,前提是a不是const

3,const int a=0; int *p = &a; 报错,但可以通过(int *) 强制地址转换,有涉及到常量折叠了

4,**二级指针**p和二维数组对照的理解, int arr[100][4]; int **p=arr; p//指向arr[0]; p+r//指向arr[r]; *p//指向arr[0] [0]地址; *(p+r)//指向arr[r][0]; *(p+r)+c//arr[r][c]的地址; *(*(p+r))+c//arr[r][c]的值也就是p[r][c]

5,函数指针 double (*pf)(int), *pf或pf就像是函数名的别名

第八章:函数2

1,内联 inline 不同于#define宏定义,宏定义是文本替换,没有参数传递,而inline有

2,引用创建时初始化,相当于int* const pt 引用参数和临时变量那块要仔细理解!形参用const声明,会根据需要产生临时变量 ,如果试图修改,会警告,只会修改临时变量的值

3,引用参数及返回值,啥时候加const啥时候不加~返回值加了const,比如const syone& func(); 不可以直接对func()进行写; 需要先创建一个同类型的变量,然后赋值进行写操作。

4,返回引用时, 不能返回不存在的内存单元~返回值的话,系统会先拷贝到临时区域,返回引用就不会拷贝

5,string类型自动转换: char *或char c[](实参)——>string(形参),返过来会报错:

   using namespace std;
void change(string s);
int main()
{
char * s="hello";
cout<<s<<endl;
change(s);
cout<<s<<endl;
return ;
} void change( string s)
{
s="nihao";
cout<<s<<endl;
}
//valid 传的是值 void change(char *);
int main()
{
string s="hello";
cout<<s<<endl;
change(s);
cout<<s<<endl;
return ;
} void change(char *s)
{
s="nihao";
cout<<s<<endl;
}
//unvalid 返过来不可以 void change(string &);
int main()
{
string s="hello";
cout<<s<<endl;
change(s);
cout<<s<<endl;
return ;
} void change(string &s)
{
s="nihao";
cout<<s<<endl;
}
//valid 改变了s的值 void change(string &);
int main()
{
char* s="hello";
cout<<s<<endl;
change(s);
cout<<s<<endl;
return ;
} void change(string &s)
{
s="nihao";
cout<<s<<endl;
}
//unvalid 可以把char类型转换为string,但是不能转换为string & 引用 void change(const string &);
int main()
{
char* s="hello";
cout<<s<<endl;
change(s);
cout<<s<<endl;
return ;
} void change(const string &s)
{
cout<<s<<endl;
}
//valid 加上const就可以,但是有了const,传的其实是值,和第一种情况一样,不能对其改变

补充:

A、数组名不是指针。

B、数组名 是 不是指针的指针。

数组名本质:

  (1)数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组;

  (2)数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量;

  (3)指向数组的指针则是另外一种变量类型(在WIN32平台下,长度为4),仅仅意味着数组的存放地址!

解析:

A

char str[10];
 char *pStr = str;
 sizeof(str);//值为10。对数组结构求长度。
 sizeof(pStr);//值为4。指针变量的长度。

首先对sizeof,是操作符不是函数,siziof(char)是合法的,而如果是函数,函数输入的必须是实参。

B

char str1[10] = "I Love U";
 char str2[10];
strcpy(str2,str1);
函数原形中能接纳的两个参数都为char型指针,而我们在调用中传给它的却是两个数组名!

其原因是数组名可以作为指针常量使用,即指针是常量。符合指向数组结构地址的特性。

本质:

1、数组名指代一种数据结构:数组

所以数组名是指向数据结构的指针,且是指针常量,所以不能作为累加来用,不能等同于指针,例如求长度sizeof。

2、数组名可作为指针常量

int intArray[10];
  intArray++; //编译器会报错此条。数组名不能作为指针变量一样累加。数组名是指针常量。

3、数组名可能失去其数据结构内涵

数组名因为可以作为指针常量,所以可以作为实参进行传递指针,但是当传递进函数的时候,作为函数的形参,其自动换成了指针。  数组名作为指针常量,可以作实参, 传递到函数的形参中,自动转换成指针变量。

void arrayTest(char str[])
  {
   cout << sizeof(str) << endl;//长度为4
  }
  int main(int argc, char* argv[])
  {
   char str1[10] = "I Love U";
   arrayTest(str1);
   return 0;
  }

  (1)数组名作为函数形参时,在函数体内,其失去了本身的内涵,仅仅只是一个指针;

  (2)很遗憾,在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

  所以,数据名作为函数形参时,其全面沦落为一个普通指针!它的贵族身份被剥夺,成了一个地地道道的只拥有4个字节的平民。

结构体和指针

数组定义好了数组的类型。例如int a[10];

而结构体的类型是结构体本身,