把《c++ primer》读薄(1-2)

来源:互联网 发布:js实现继承 编辑:程序博客网 时间:2024/05/08 21:53

一:大小端的概念Big-Endian和Little-Endian(见计算机存储的大小端模式解析)

二:浮点数的机器级表示(见从如何判断浮点数是否等于0说起——浮点数的机器级表示)

三:c++的基本的内置类型:

1)算术类型,又包括:

整型(包括:整数int、short、long int类型,单个字符(分为存储单个机器字节的char类型,1个字节,char有三种不同的类型,普通char,unsigned char和signed char,一共两个表达方式unsigned char和signed char。和存储汉字和日语等的扩展字符集的wchar_t类型,2个字节),布尔值0,1)。

整型又分为无符号和有符号的(除bool类型之外)

在选用整数类型的时候,一定先分析好大概范围,一些机器int和long int一样,如果贸然总使用范围很大的类型,则额外代价较高,总用范围娇小的,又容易溢出。

浮点型,float,double,long double。一般用double就足够了,且很多经典书籍都建议使用double,少用long doouble,因为一没必要那么高精度,二运行起来代价额外很大。

2)还有一种void ,空类型。

问题1:在输出汉字字符串的时候会乱码,一般解决方案是字符串前面加L,why?

这是在说明字符串的字面值是宽字符wchar_t,  L"大家好!"   这样表示就可以了。因为编译器有时候默认使用unicode字符集,不加L显示的日文或者韩文,L代表宽字符

问题2:针对模的问题

复制代码
     unsigned char chr = 255;     printf("%u\n", chr);//255      unsigned char chr1 = 256;     printf("%u\n", chr1);//1     //在c++或者c,这样的赋值是能被接受的     //超出范围的数值%取值范围,unsigned char是0-255,就是336模256之后的值再赋值chr2     unsigned char chr2 = 336;     printf("%u\n", chr2);//80     //-1显然已经超出了范围,但是-1%256应该还是-1的,这里打印255,是因为-1是负数,而我们打印的是无符号数     //编译器就认为-1的补码1111 1111,是无符号数的补码,打印出来那就是255     unsigned char chr3 = -1;     printf("%u\n", chr3);//255     //同理,-1模无符号int取值范围之后还是-1,且-1的32位补码16进制是0xffff ffff,编译器认为是无符号的数的补码,那就是32位无符号int类型的最大值4294967295     unsigned int in = -1;     printf("%u\n", in);//4294967295     //相对的,使用%d打印就是-1,因为编译器认为这是带符号数的补码     printf("%d\n", in);//-1      int in1 = -1;     printf("%d\n", in1);//-1     unsigned int in = 4294967296;     printf("%u\n", in);//0
复制代码

4294967296模4294967296就是0

//%运算符只能用于整数相除求余,运算结果的符号与被除数相同,绝对不能用于实数。
//被除数=商 x 除数 + 余数
//余数的绝对值一定小于除数的绝对值

复制代码
 printf("%d", 5 % 3);//2    printf("\n%d", 3 % 5);//3    printf("\n%d", 3 % -5);//3,3=0 * -5 + 3    printf("\n%d", -3 % 5);//-3,-3=0 * 5 + -3    //一定要思路清晰,脑子里有数学的概念就行    printf("\n%d", 5 % -3);//2,5=-1 * -3 + 2
复制代码

问题3:没有short类型的字面值常量

字面值常量比如:

有无符号int类型111u,有默认带符号的int类型111,有long int类型111L,有无符号long int类型111LU或者111UL,有默认的double类型,1.1,有单精度类型1.1F,有扩展精度类型1.1L,有true,false的bool字面值,有字符和字符串类型的字面值。就是没有short int类型字面值!

问题4:多行字面值的表示

复制代码
cout << "aaaaaaaaa" "ddddddd" << endl;//ok    cout << "aaaaaaaaaaaa"        "bbbbbbbbbbbbbb" << endl;//ok    cout << "aaaaaaaa\            bbbbbbbbbbb" << endl;//ok    //cout << "aaaaaaaaaaaa    //    bbbbbbbbbb" << endl;//error
复制代码

针对第三行代码,\  虽然可以实现多行字面值字符串的输出输入,但是有局限,\  必须在本行末尾,后面不能有注释和其他字符,且后续行bbbb前面的空,都算作了字符串字面值的一部分,故出现如图第三行所示的情况,解决办法:

    cout << "aaaaaaaa\bbbbbbbbbbb" << endl;

问题5:程序尽量的不要过多的依赖机器

比如,int在win32下是一个长度,也许换个机器就不一样了,如果有,最好是在依赖处都有说明,否则程序移植起来很困难。

问题6:c和c++的变量为什么要先声明还要定义名字,使用前为什么还必须先定义变量或者常量的类型?

c/c++是静态类型的语言(编译时做类型检测),对程序的操作是否合法都是在编译期间检测,故编译器必须能够识别程序内每个实体,对于不是关键字的且没有呗引号括起来的符号,对于c/c++编译器来说,它是不认识的,如何让编译器知道这个单词是什么意思呢?

所以就有了声明(declare)。编译器每次开始工作,不知道有哪些变量,不知道有哪些函数,也不知道有哪些符号常量,它不是人!如从代码里读了一个单词,既不是关键字,又不是自己认识的东西,编译器就认为这是一个没有声明的东西,因为不认识它,所以不知道如何处理。所以“声明”,就是告诉编译器有这么一个东西。声明的时候主要做四件事: 

一是建立变量符号表

声明变量,编译器可以建立变量符号表,如此,程序用到多少变量,每个变量类型是什么,编译器非常清楚,是否使用了没有声明的变量,编译器在编译期间就可以发现,从而帮助了程序员远离由于疏忽而将变量名写错的情况。 

二是变量的数据类型指示系统分配多少内存空间

数据类型指示系统如何解释存储空间中的值。同样的数值,不同的类型将有不同的解释。32位机器,一般情况下,int占4个字节,float占4个字节,在内存中同样存储二进制数,且这个二进制数也没有标志区分当前是int还是float型,那么如何区分?就是通过变量的数据类型来区分。由于声明建立了变量符号表,所以系统知道变量存储空间该如何解释。

三是变量的数据类型确定了该变量的取值范围

例如短整型short的数据取值-32768~32767之间。

四是不同的数据类型有不同的操作

比如,模运算,不能用于浮点数。如下:

printf("%d", 5 % 2);// 1printf("%d", 5.0 % 2);// errorprintf("%d", 10.0);// %d对应解析带符号10进制整数,实数解析会失败,结果为0。这种陷阱题,基础题,经验题往往确定一个人的水平printf("%d", (int)10.0);//使用强制类型转换,ok!printf("%f", 1);//因为%f对应解析实数,如果是整数,转化失败就是0.000000,同样可以强制类型转换改正。

问题7:理解初始化和赋值是两个完全不同的概念

c++支持两种初始化方式,复制初始化(使用=),和直接初始化(常用于构造函数的初始化列表),且使用直接初始化,语法更灵活,效率更高(对内置类型没什么区别),专家推荐多用!

    double d = 1.0;//ok,复制初始化    double dd(1.11);//ok,直接初始化,想起了构造函数的初始化列表

初始化:创建新的变量,并给变量赋一个初始值的过程。

赋值:变量早在前面声明过,且有了初始值,此时再给它一个新值(把前面的值擦掉)的过程。

    string boy("dadadadadafwe"), girl = "   ";//ok,混搭没问题!    int a , b = 10, c, d = 100;//ok    char chr = 'a', chr1('0');//ok

注意

    //int a = a;//error,提示变量a没有呗初始化就使用!但是一些编译器就不会报错,建议不要这样写。    //string str1 = str2("dadafa");//error,要分开,分别初始化    //double a = b = c = 1.0;//error,同样要分别分开初始化!    string str1 ="da", str2(" ");    double a = 0.0, b = 0.1, c = 0.2;

问题8:关于自动初始化

在函数外定义的变量自动初始化为0,函数内就不会自动初始化,且对于c和c++的基本内置类型,最好定义的同时就初始化,即使当下没用。

复制代码
#include <iostream>#include <string>using namespace std;string str1;//空字符串int a;//0double d;//0float f;//0char c;//空字符int main(void){    string str;//ok,string对象创建,自动调用string类的默认构造函数,进行初始化    cout << str << endl;//str自动初始化为空字符串    cout << a << endl;//0    cout << str1 << endl;//    cout << d << endl;//0    cout << f << endl;//0    cout << c << endl;//    return 0;}
复制代码

针对c++,还需要考虑类的构造函数

问题9:变量定义和声明的区别

因为c和c++经常是多文件开发,故有了声明和定义

变量的定义是为了给变量分配内存,指定初始值,一个变量只能有一个定义存在。

声明变量,是告诉程序变量的类型和名称

即定义也是声明,因为定义变量的同时,也声明了变量的名字和类型,一个变量可以有多次声明,但是定义只有一次!因为声明仅仅指定名称和类型,不分配内存

通常用关键字extern专门进行变量的声明,而不定义。告诉本文件,这个变量已经定义在了其他文件。俗称外链接。

复制代码
extern double d;//仅仅是变量的声明extern double d;//同一个变量,可以被声明多次!double d = 0.0;//变量的声明,同时包含了定义//double d;变量仅仅只能被定义一次int main(void){    return 0;}
复制代码

同样,声明也可以变为定义,如果声明有初始化,那么就变为定义,针对extern语句仅仅在函数外部(拥有文件作用域范围),才可以变为定义,否则出错!

复制代码
#include <iostream>#include <string>using namespace std;extern int a = 1;//声明变为了定义//int a;“int a”: 重定义int main(void){    //extern int a = 1;//在函数内部,这样不对//“a”: 不能对带有块范围的外部变量进行初始化,想实现声明变定义,那么必须给extern的变量 文件作用域范围,也就是写在函数外部,使得a成为一个全局变量    return 0;}
复制代码

回忆,多文件开发,都是在一个文件进行变量的定义,而其他文件使用这些变量就仅仅需要包含这些变量的声明 即可,无需(也不可以)重定义。

再看:

复制代码
    int sum = 0;    for (int i = 0; i != 10; i++)    {        sum += i;    }    cout << i << endl;//error,因为i的作用域在for循环体内有效,for外部没有定义变量i,故报错!    //“i”: 未声明的标识符
复制代码

问题10;避免硬编码

复制代码
    int sum = 0;    /*for (int i = 0; i < 512; i++)    {        sum += i;    }判断语句的512就是硬编码,如果程序很大,那么可读性就很差(无法从上下文获得512的含义),且如果类似的for语句很多,一旦需求变化,那么想改就不那么容易了!    应该多多用const对象*/    const int j  = 512;    for (int i = 0; i < j; i++)    {        //    }
复制代码

这样做,如果常量定义出错,或者被无心的修改,那么可以被编译器立马检测出来!程序健壮性提高!因为常量定义后不能被修改,故常量定义的同时必须马上初始化!

问题11:引用初步探讨

int a = 1024;double d = 0.1, dd = 0.2, ddd = 2.2;int &ref = a;//okdouble &refd(d);//okdouble &refd1 = dd, &refd2 = ddd;//ok

多个方法定义多个引用没问题,记住:引用就是外号而已!不占新的内存空间,和原数值共享内存空间。

注意,引用必须初始化!因为引用必需要绑定到一个实体对象!故不能是引用的引用。也不能不初始化!

复制代码
int &ref1;    //error C2530:“ref1”: 必须初始化引用int i = 1024;int &refint = i;//okint &refint1 = i;//ok,可以给一个对象,起多个外号int &refint2 = refint;//okint &&refint3 = i;//error C2440: “初始化”: 无法从“int”转换为“int &&” 无法将左值绑定到右值引用
复制代码

引用一旦绑定一个对象,不能再绑定其他对象

double d = 1.0;double dd = 1.1;double &refd = d;double &refd = dd;// error C2374: “refd”: 重定义;多次初始化

引用要注意字面值常量的绑定问题

int &ref2 = 1024; // error C2440: “初始化”: 无法从“int”转换为“int &”//因为1024是字面值常量,而ref2是普通引用,ref2是一个变量,又常量不能被修改,故用变量绑定肯定报错!//修改const int &ref2 = 1024;//ok

同理,const常量必须用const引用来绑定!

//const常量必须用const引用来绑定!const char c = 'a';//char &refc = c;  error C2440: “初始化”: 无法从“const char”转换为“char &” 转换丢失限定符const char &refc = c;//ok

注意引用和不同类型变量的绑定问题

//把引用绑定到不同类型的对象int i = 512;//double &refi = i;  //error C2440: “初始化”: 无法从“int”转换为“double &”//使用const引用就对了const double &refi = i;

原因:对于不同类型的引用绑定过程,编译器内部做了这样的优化,先针对int类型的i = 512,自动生成一个double类型的临时变量

double temp = 512;

再让double引用去绑定temp,而不是我们看到的直接绑定int i=512;

double &refi = temp;

故这里有一个问题,现在refi是非const类型,那么说明可以对refi也就是i修改,但是事实上,我们修改只是修改了temp,不会对原值i修改,这违背了引用的初衷,故这样是定义为不合法的行为。同理,使用const引用就ok了,因为仅仅是使用i的值,并不修改,这样是完全合法的。

问题12:尽量多用枚举定义常量

//c++的枚举类型可以省略美剧名字,也可以加上名字,枚举本身就是常量表达式!不能修改它的成员!

复制代码
    enum {}; //勿忘;    //枚举默认第一个变量赋值为0,以后的依次+1,如果有初始值,则按照初始值,以后依次+1    enum e{        a, b, c    };    //a =0,b =1, c=2
复制代码

//使用枚举定义de 常量,是真正的常量!不受限于类的对象!且有很好的可读性!含义的聚集性!

比如在类中定义const成员,我们不能在类里初始化,必须创建对象的时候,构造函数初始化。看似是常量,但是针对的只是某一个对象,其他对象的话,仍然可以去初始化属于自己的那一份const成员。并不是真正的constant!而枚举就无所谓这个问题。

复制代码
    enum ee{        aa = 1, bb, cc    };    //bb = 2, cc =3    enum eee{        aaa = 1, bbb, ccc = 4, ddd    };    //bbb = 2, ddd = 5
复制代码

//枚举是一种类型!可以定义枚举类型的对象,同理也可以给枚举类型的对象赋值。赋值,必须是这个枚举类型的成员,或者是同一枚举类型的其他的枚举对象!

复制代码
    eee e1;//ok,定义枚举类型的对象e1    //eee e2 = 1;//error,赋值过程错误,应该是本枚举类型的成员    //eee e0 = aa;//error, 赋值错误,应该是同类型的枚举对象,aa是属于ee这个枚举的    //修改    eee e2 = aaa;    eee e3 = e2;
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 打蜡后下雨了怎么办 飞机起飞耳朵不舒服怎么办 宝宝脸上口水疹怎么办 婴儿身上长癣怎么办 婴儿下巴口水藓怎么办 婴儿嘴边长癣怎么办 婴儿脸上口水癣怎么办 嘴巴旁边长癣怎么办 美团机票不出票怎么办 东方航空会员锁定怎么办 大众车烧机油怎么办 大众cc烧机油怎么办 叫外卖给差评被打怎么办 发现宿舍被盗后怎么办 知了猴变黑了怎么办 婴儿仙人掌的刺怎么办 仙人掌刺扎进皮肤里怎么办 被仙人掌的小细绒刺扎到怎么办 值机截止了怎么办 社保卡消磁了怎么办 住宾馆没身份证怎么办 社保卡电话错误怎么办 没住过酒店怎么办 上海合规网约车证件怎么办 取票没有身份证怎么办 买车票没有身份证怎么办 登机身份证丢了怎么办 飞机没带身份证怎么办 上飞机没带身份证怎么办 机场没带身份证怎么办 儿童坐飞机没有户口本怎么办 不需要行李托运化妆品怎么办 坐飞机被限制了怎么办 坐飞机没买保险怎么办 飞机起飞时难受怎么办 婴儿坐飞机没座位怎么办 转机行李不直达怎么办 儿童自己坐飞机怎么办手续 两岁宝宝发烧怎么办 网上购票待核验怎么办 老人坐飞机找不到登机口怎么办