重学C++ (一) 变量和基本类型、标准库类型
2016-01-10 18:17
381 查看
前言
大一的时候我就已经学过C++程序设计了,但是我从来不敢跟别人说我会C++。事实上,平时里大多数时候我用的是C++里面C的部分,偶尔用一下类来封装(其实用struct也可以实现的)。
对于C++的特点,我一直没有很好的去学习,只是略知一二,所以在实际使用中常常会出现一些难以察觉的问题。
我举个很简单的例子,我们打算输出一个vector内的元素:
[code]#include <iostream> #include <vector> using namespace std; int main() { vector<int> vc; vc.push_back(1); vc.push_back(2); for (int i = -1; i < vc.size()-1; i++) cout<<vc[i+1]<<endl; return 0; }
也许之前我们会以为这段代码完美无错,然而事实并非我们想的那样,结果是什么都没输出。
问题出在哪?如果你明白size()返回的是size_type类型,而该类型是unsigned的,那么就不会犯这种错误了。(同样的问题会出现在sizeof上)
另外,C++中main的返回值必须是int你是否知道?大部分iterator只能自增自减而不能像 i+=n 这样赋值?
C++的面向对象思想,范式编程,STL的源码实现,我都只是停留在“了解”的层面,这远远是不够的。
通常,只有在“熟悉”的情况下,我才敢将其写到简历上,跟别人说。
很多原因,促使我想要重新来学习C++,之前读过《C++ primer》,但是并没有读完,而且读到越后面越没耐心。
这一次,我希望自己能够一步一个脚印,把这本书啃下来,并将一些零散的,我自己认为需要注意的点在blog中记录下来,这也是敦促自己学习的一种方式。
与此同时,我将开始阅读STL的部分源码,很期待能够获取新知。
第一章 快速入门
1.对于main函数,返回类型必须是int型,返回值是一个状态指示器,0表示成功,非0由操作系统定义。UNIX中可以通过下面命令获取状态:[code]$ echo $?
2.标准库定义了4个IO对象:cin,cout,cerr,clog;(cerr默认不缓冲,clog默认带缓冲)
3.输出操作返回的值是输出流本身:
[code]std:cout<<"Hello "<<"world"<<std:endl;
能够执行是因为std:out<<”Hello “返回其左操作数std:out;
所以以上语句等价于:
[code]std:cout<<"Hello "; std:cout<<"world"; std:cout<<std:endl;
4.使用输出语句的时候应该注意刷新输出流,忘记刷新输出流将可能导致输出停留在缓冲区中。(换行可用于刷新输出流);
5.如果不能保证读取变量前重置变量,就应该初始化变量;
6.代码改变时,注释应该与代码保持一致,错误的注释比没有注释更糟糕;(所以我们应该尽可能提高代码的可读性,而不是依赖于注释!)
7.注释不可嵌套!
8.Unix系统中通常用Control-d来输入文件结束符(windows下是Control-z);
第二章 变量和基本类型
1.char类型通常是单个机器字节(byte),wchar_t(宽字符)类型用于拓展字符集,比如汉子和日语,这些字符集中一些字符不能用单个char表示;2.在C++中,把负值赋给unsigned对象是完全合法的,结果是该负数对该类型的取值个数求模后的值,比如-1赋给8位的unsigned char,结果是255;
使用unsigned可以避免值越界导致结果为负数的可能性。
3.float只能保证6位有效数字,而double至少保证10位;
4.char类型是整型,但是char通常用于存储字符而不用于计算(因为不同实现中char可能是unsigned或signed);
5.只有内置类型存在字面值,字面值常量的值是不能修改的(它存放在代码段中)。
[code]#include <iostream> using namespace std; int main() { char *ptr = "Linux"; *ptr = 'T'; cout<<ptr<<endl; return 0; }
上面程序将造成seg-fault或者崩溃,因为字面值常量”Linux”是在只读代码段中,对它的修改操作是失败的;
6.以0开头的字面值整数常量表示八进制,0x或0X开头则表示十六进制;
** int month = 09; 将会报错,因为八进制没有09这个值;
7.没有short类型的字面值常量;
8.默认的浮点字面值常量为double类型;
9.为兼容C,C++所有字符串字面值都由编译器自动在末尾添加一个空字符;
10.字符串字面值的连接:
[code]std::cout<<"a multi-line " "string literal " "using concatenation" <<std::endl;
输出: a multi-line string literal using concatenation
**字符串字面值和宽字符串字面值不能连接,是未定义的。
11.多行字面值
在一行的末尾加一个反斜杠可将此行和下一行当作同一行处理:
[code]std::co\ out << "Hi" << std::en\ dl;
**反斜杠必须是该行的尾字符,其后不能有注释或空格;
**后继行行首任何空格和制符表都是字符串字面值的一部分,所以后继行不能有正常的缩进。
12.左值:可以出现在赋值语句的左边或右边;
右值:只能出现在赋值的右边;
比如:变量是左值,数字字面值是右值。
13.建议:标识符不要包含两个连续的下划线,也不要以下划线开头后面紧跟一个大写字母(保留,用于标准库);
14.初始化不是赋值。初始化指创建变量并给他赋初始值,而赋值则是擦除对象的当前值并用新值代替;
15.内置类型的全局变量会初始化为0,局部变量不自动初始化;
作为习惯,我们都应该对变量进行初始化;
事实上,未初始化变量在内存中的某个位置,该位置有一个值,为上次使用余留下来的。
16.声明和定义:
变量的定义:为变量分配存储空间,还可以指定初始值,在一个程序中,变量有且只有一个定义;
声明:用于向程序表明变量的类型和名字;
可以通过使用extern关键字声明变量名而不定义它,也不分配存储空间;
定义也是声明:定义变量时我们声明了它的类型和名字;
声明也是定义,除非使用extern来说明不定义它;
如果声明有初始化式,它可被当作定义,即使有extern标记(只有当extern声明位于函数外部时,才可以含有初始化式);
[code]extern double pi = 3.14; //ok:定义 extern double pi; //ok:声明 extern double pi = 3.14; //error:重定义
17.因为常量在定义后就不能被修改,所以定义时必须初始化;
18.非const变量默认为extern,而要使const变量能够在其他文件访问, 必须显式指定为extern:
[code]//file1.cc int counter; //定义 //file2.cc extern int counter; //声明 ++counter; //使用
[code]//file1.cc extern const int size = MAXN; //定义 //file2.cc extern cosnt int size; //声明 int ssize = size; //使用
19.不能定义引用类型的引用;
引用必须用与该引用同类型的对象初始化;
引用初始化后,不能将引用绑定到另一个对象(这与指针不同);初始化时指明引用指向哪个对象的唯一方法;
引用不占用内存,而指针需要占用一个指针类型的内存;
const引用是指指向const对象的引用;
const引用可以绑定到不同但相关类型的对象或绑定到右值!
原因:
[code]double dval = 3.14; const int &ri = dval;
以上代码编译器将转换为:
[code]double dval = 3.14; int tmp = dval; const int &ri = tmp;
如果ri是非const,那么对ri的修改将修改的是tmp而不是dval,所以对于非const是禁止的,而对于const,因为其本身就不能修改,所以就没必要禁止。
20.枚举成员是常量,且不要求唯一:
[code]//point2d = 2, point2w = 3, point3d = 3, point3w = 4; enum Points {point2d = 2, point2w, point3d = 3, point3w};
21.struct默认成员是public,而class默认是private;
22.头文件用于声明而不是用于定义;
因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义;
允许const变量定义在头文件中,因为const对象默认定义为它的文件的局部变量,所以包含该头文件的源文件都有自己的const变量;另外,如果const变量不是用常量表达式初始化,那么它不应该在头文件中定义,否则,该变量应该在一个源文件中定义并初始化,然后在头文件中添加extern共享;
第三章 标准库类型
1.在头文件中必须使用【完全限定】的标准库名字:因为预处理器会将头文件复制到程序中,如果头文件中使用了using声明,则包含该头文件的每个程序都放置了同一using声明,然而程序并不一定需要using声明;2.一个有用的string IO操作:getline,它接收一个输入流和一个string对象;它读取的内容不包含换行符,getline函数将istream参数作为返回值;
3.string的size操作返回的是string::size_type类型,不要把它赋给一个int变量!
4.当进行string对象和字面值混合连接操作时,+操作符的左右操作数必须至少有一个是string类型的;
[code]string s1 = "hello" + ","; //error string s2 = s1 + "," + " world"; //ok string s3 = "hello" + "," + s2; //error
5.string的索引下标类型为unsigned的size_type;
6.string对象中字符的处理:头文件cctype;
7.cname头文件定义在名字空间std内,而name.h则不是;
8.vector不是一种数据类型,而是一个类模板,vector< int>才是数据类型;
9.使用vector的size_type类型时:
[code]vector<int>::size_type; //ok vector::size_type; //error
10.如果循环中插入或者删除元素,那么注意循环判断条件中size的变化;
11.迭代器操作:==或!=; 对其他操作如四则运算,大小比较需要谨慎;
12.const_iterator:只能用于读取容器内的元素,不能改变其值;
对const_iterator解引用,返回的是一个const值;
13.vector迭代器除自增自减,还支持以下操作(其他迭代器不一定支持):
[code]iter+n; iter-n; iter1-iter2;
14.任何改变vector长度的操作都会使已存在的迭代器失效!
15.定义bitset时,要明确bitset含有多少位,长度必须为整型字面值常量或者已用常量值初始化的整型const对象;
16.bitset的count操作返回类型是size_t,包含在cstddef头文件中。
相关文章推荐
- 【转载】完成C++不能做到的事 - Visitor模式
- 浅析C++智能指针
- C/C++琐碎知识归纳
- Sublime Text 3下C/C++开发环境搭建
- C/C++学习指南(语法篇) - 邵发
- c++ lamda表达式的注意事项
- C语言scanf输入格式 printf输出格式
- C++学习笔记(二)
- 【c++】静态数据成员定义及应用浅谈<重点>
- C语言指针详解(一)
- c/c++多维数组的动态内存开辟与释放
- C语言学习之回调函数
- c语言中gets ,getschar 和fgets 的用法及三者之间的差别,还有scanf
- C++中重载、重写(覆盖)和隐藏的区别实例分析
- IOS之c语言笔记 day01
- C/C++ 中头文件相互包含引发的问题
- C++ 编译多态 运行多态
- C++ 课本学习笔记(2)
- c++优先级
- 03day 进入32位模式并导入C语言