萌新学习C++容易漏掉的知识点,看看你中招了没有(一)

时间:2022-07-28
本文章向大家介绍萌新学习C++容易漏掉的知识点,看看你中招了没有(一),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一. 前言

       很多人,包括我,看书,看完一章怎么怎么的,然后不管是作业,还是考试出现这一章的内容,总有些地方跟我们脑袋里面理解的不一样,自己明明学习过,但机器给出的答案和自己的完全相反,或者完全不正确,这就是为什么书读百遍,其义自见,可能夸张了,不知道你们是怎样的,一本书多读,确实能带给我不同的知识,这也是我为什么想起来写总结,我加了一个群,看到萌新们问的问题大多是他们看书漏掉的知识,这些人一定是只看了一遍或者没看,他们的程序刚好需要那么一点小小的知识去解决,可是他们不知道这一点小小的知识。        为什么会漏掉知识,我个人认为是这样的,最起码我是,比如这一章讲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]; //试图通过输入赋值,确定数组大小,这是错误的想法,要注意
  //之所以称为静态数组,是因为数组大小必须在编译之前确定,如果不确定,请使用动态数组。

目前就想到这些,我们下期见~