@[TOC]
一. 前言
很多人,包括我,看书,看完一章怎么怎么的,然后不管是作业,还是考试出现这一章的内容,总有些地方跟我们脑袋里面理解的不一样,自己明明学习过,但机器给出的答案和自己的完全相反,或者完全不正确,这就是为什么书读百遍,其义自见,可能夸张了,不知道你们是怎样的,一本书多读,确实能带给我不同的知识,这也是我为什么想起来写总结,我加了一个群,看到萌新们问的问题大多是他们看书漏掉的知识,这些人一定是只看了一遍或者没看,他们的程序刚好需要那么一点小小的知识去解决,可是他们不知道这一点小小的知识。
为什么会漏掉知识,我个人认为是这样的,最起码我是,比如这一章讲for,一看语法,我去,就怎么简单?上机一敲,啪啦啪啦啪啦,循环正确,嗯,for循环我学会了,然后沉浸在自我喜悦中顺利进入了下一章,应该就是这样吧? 哈哈,然后后期写复杂程序的时候就出了问题,于是再次翻开了那久违的for循环。(手动狗头)好了,好了,下面的总结可能不是一块知识点的,而是我目前以来感觉会漏掉的知识点,有可能是提高程序效率的,为了查找方便,我都列了标题,或许我的整篇文章只有一处帮到了你,那么也是有意义的,下面我们进入正题。
二.进入正题
1. float和double
萌新初学浮点数要注意:
//float和double一个单精度浮点数,一个双精度浮点数,就不说了,
float f = 4.0; //不要这样写,虽然你定义的是float,但实际上默认还是double类型
float f_1= 4.0f //这是正确的写法,f是double类型,记得后要加 f
//而double直接写数字就好了
//浮点数的最大值和最小值从来都不是6-7位,也是15-16位,这指的是精度。
2. for循环
萌新只用这一种:
// 萌新用法:
for (int i = 0; i <= 10; i++)
{
// 代码。。。。。
}
萌新忽略的用法:
for (int i = 0; i != 10; i++)
{
//代码 第二个表达式不单单只可以使用大小符号
}
for (int i = 0; i <= 10; i+=2)
{
//我们可以修改第三个表达式,而不逾矩每次只加1,也可以加2,加3
}
for (int i = 0, j = 10; j < 20; i--,j++)
{
//这里使用了逗号运算符(下面会说),如果对for循环有两个变量变化要求的,该方法正好
}
int x;
for (cin >> x; x == 0; cin >> x)
{
//这种写法是不是很可以
}
//C++11新增的语法
int array[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (int a : array)
{
cout << a << endl;//自动遍历array[10] 不可修改变量
}
for (int & a : array)
{
a += 1; //可修改变量,也可遍历
}
for (int x : {1, 3, 5, 7, 9})
{
//初始化列表
}
3. 逗号运算符
萌新知道的:
逗号可以将允许使用一个表达式改为使用多个表达式。
萌新不知道的:
刷过题的同学对下面的写法应该很有印象,我就见过不少:
int a;
a = 10, 20;
a =(10, 20);
//第一次a应该是多少?,第二次a又应该是多少?
C++是这样规定的:
对于用多个逗号隔开的表达式,确保会先计算第一个,然后以此类推,并且逗号表达式的值是最后一部分。
也就是说第一次a为10,第二次a为20;
4. 数组
数组初始化和赋值
int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; //正确
int b[10];
//b[10] = {1,2,3,4,5,6,7,8,9,10};这是错误的写法,跟着上面,让你的思维认为这样也可以,其实不可以
//会提示初始预设值太多,现在的b[10]单单指一个元素,并不指整个数组
int c[10] = { 0 };
int d[10] = { 1 };
//数组c中的10个元素将被初始化为0,但是数组d,只有d[0]被初始化为1,其他元素还是初始化为0,你说气不气人
5. 申请动态数组
申请动态数组,也可以将其初始化为一个值
//int * w = new int[10]; 每个元素值是不确定的
int * w = new int[10]();//每个元素的值将被初始化为0 c98
int * w = new int[10]{};//每个元素的值将被初始化为0 c11船新版本
6. 分不清数组和指针
在很多情况下,可以以相同的方式使用指针名和数组名,对于它们,可以使用数组方括号表示法,也可以使用解除引用运算符(*)在多数表达式中,它们都表示地址。
数组和指针区别一:可以修改指针的值,而数组名是常量,无法修改。
数组和指针区别二:对数组应用sizeof()运算符得到的是数组的长度,而对指针应用sizeof()运算符得到是指针的长度,即使指针指向的是一个数组。
7. 数组的地址
short tell[10];
cout << tell << endl;
cout << &tell << endl;
从数字上说,这两个地址相同,但从概念上说,&tell[0] (既tell)是一个2字节内存块的地址,而&tell是一个20字节的内存块的地址,因此,表达式tell+1将地址值加2,而表达式&tell+2将地址加20,换句话说,tell是一个short指针(short ),而&tell是一个这样的指针,既指向包含20个元素的short数组( short()[20] )。
&tell如何等于( short(*)[20] ),如下:
short (*p )[20] = &tell;可以这样声明和初始化这种指针。
如果省略括号,优先级将使得p先与[20]结合,导致p是一个指针数组,它包含20个元素,因此括号必不可少,得到的结论是p等于&tell,p等于tell,(p)[0]为tell数组的第一个元素。
详见C++ primer plus 109页
8. 优先级和结合性
很多萌新可能不太注意优先级和结合性的顺序,这里告诉大家,先考虑优先级,在优先级同级的情况下再考虑结合性。
9. 利用循环创造暂停假象
萌新可能会使用如下for循环来创造程序暂停:
for(int i = 0; i<=1000000;i++)
{
//程序暂停,但暂停时间和机器的快慢有很大关系
}
更高级的用法是:
ANSI和C++库中有这样一个函数:clock(),存在于ctime头文件,它定义了一个符号常量:CLOCK_PER_SEC,该常量等于每秒钟包含的系统时间单位数,因此,将系统时间除以这个值,可以的得到秒数,或者将秒数乘以该常量,可以得到以系统时间为单位的时间,其次,ctime将clock_t作为clock()返回类型的别名。
#include<ctime>
float a = 10.0;
cloct_t delay = a * CLOCK_PER_SEC;
clock_t start = clock();
while(clock() - start < delay)
{
//程序暂停
}
clock_t b = clock();
// b/CLOCK_PER_SEC将得到秒数
10. 不注意类型转换
很多萌新代码逻辑正确,可是就是得不到正确答案,多半出在类型转换上面,下面给大家一条法则:
1.如果有一位操作数的类型是long double,则另一个操作数转换为long double。
2.否则,如果有一个操作数的类型是double,则另一个操作数转换为double。
3.否则,如果有一个操作数的类型float,则另一个操作数转换为float。
4.否则,说明操作数都是整形的,因此执行整形提升,什么是整形提升,下面有写。
5.在整形提升的情况下,如果两个操作数都是有符号或者无符号类型的,且其中一个操作数的级别比另一个低,则转换为最高级别的类型。
6.如果一个操作数为有符号的,另一个操作数是无符号的,且无符号操作数的级别比有符号操作数的级别高,则将有符号操作数转换为无符号操作数所属的类型。
7.否则,如果有符号类型可以表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。
8.否则,将两个操作数都转换为有符号类型的无符号版本。
整形提升:
如果bool,char、short,包括它们有符号或无符号变型,以及枚举类型,可以使用在需要int或者unsigned int的表达式中。如果int可以完整表示
源类型的所有值,那么该源类型的值就转换为int,否则转换为unsigned int。这称为整型提升。
11. 数组大小确定
const int n = 10;
int a[n]; //正确,可以使用常量确定数组大小
int n = 10;
int a[n]; //错误的写法,n必须为常量
萌新常常写出这样的程序:
int n;
cin >> n;
int a[n]; //试图通过输入赋值,确定数组大小,这是错误的想法,要注意
//之所以称为静态数组,是因为数组大小必须在编译之前确定,如果不确定,请使用动态数组。