当前位置:   article > 正文

c++琐碎存疑知识点梳理_c++琐碎知识

c++琐碎知识

1、关于break的使用:

使用场景:用于跳出选择语句或者是循环语句

  • 在switch语句中,跳出当前的case;
  • 在循环语句中,跳出当前的循环语句。(注意,对于嵌套循环,跳出的是最内层的循环语句)

2、关于continue语句的使用:

作用:终止最近的循环中的当前迭代,开始下一次迭代 ;

使用场景:for 、while和do while 循环内部

注意:对于while和do while循环语句,继续进行下一次循环的条件判断;对于传统的for循环,会执行当前循环的循环更新表达式;

3、关于Double类型数据大小比较

遇到的问题简化示例:

  1. #include<iostream>
  2. using namespace std;
  3. int main(){
  4. for(double i=0.1;i<1;i+=0.1)
  5. cout<<i<<" ";
  6. // 输出结果为 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
  7. }

因为精度问题,这样使用和日常使用的int类型相同的方法是不行的,需要这样比较: 

  1. #include <math.h>    //头文件要记得加
  2. const double EPS = 1e-6; //一般这样子就够,但有时具体题目要考虑是否要更小的
  3. if(fabs(a-b) < EPS) //判断是否相等
  4. if(a > b+EPS) // 判断a是否大于b,因为大的肯定大,所以即使你小的加上,还是会更大

修改如下:

  1. #include<iostream>
  2. #include<cmath>
  3. const double eps = 1e-6;//一般负六次就够了
  4. using namespace std;
  5. int main(){
  6. for(double i=0.1;i+eps<1;i+=0.1)
  7. cout<<i<<" ";
  8. // 输出结果为 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
  9. }

4、关于文件输入输出

对于C语言输入输出流的底层知识学习:

参考文章:一文带你读懂C/C++语言输入输出流与缓存区 - 知乎 (zhihu.com)

缓冲区——内存空间的一部分,也就是说在内存空间中预留了一定大小的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区,根据其对应的是输入设备还是输出设备,分为输入缓冲区输出缓冲区

缓冲区的刷新:

  • 缓冲区满时;
  • 执行flush语句,即使用特定函数刷新缓冲区;
  • 执行endl语句,即行缓冲区遇到回车时;
  • 关闭文件。

可见,缓冲区满或关闭文件时都会刷新缓冲区,进行真正的I/O操作。

另外,在C++中,我们可以使用flush函数来刷新缓冲区(执行I/O操作并清空缓冲区) 如:

cout << flush; //将显存的内容立即输出到显示器上进行显示

所以在程序中向文件中输出内容(不含换行)的时候, 如果在程序结束之前断点调试的时候打开文件查看,则是看不到任何东西的!不要以为是出现问题了,实际上只是因为输出的内容还在缓冲区中,等程序执行完之后就会在文件中显示了。

 此外:(歪一下楼,这篇文章中对于getchar()函数的使用讲解非常好,这里摘录一下:

int getchar(void) ;

说明:当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。当用户键入回车之后,getchar()函数才开始从键盘缓冲区中每次读入一个字符。也就是说,后续的getchar()函数调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键。)

 5、按位逻辑运算

1、按位与 &

参加运算的两个数据,按二进制位进行“与”运算。

例如:

  1. int AndOperator(int &a, int &b){
  2. return a & b;
  3. }
  4. int main(){
  5. // 3&5 即 0000 0011 & 0000 0101 = 0000 0001 因此,3&5的值得1
  6. int a = 3, b = 5;
  7. cout<< AndOperator(a, b) <<endl;
  8. return 0;
  9. }

注意:负数按补码形式参加按位与运算。

例如: -3 & 5

   即 1111 1101 & 0000 0101 = 0000 0101

   因此,-3 & 5的值得5

按位与运算的应用:

1、清零。若想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与, 结果为零。 例:3 & 0 = 0

2、取一个数的指定位。指定位置为1,其余为0。

例:设 X = 10101110,

  取X的低4位: X & 0000 1111 = 0000 1110

  取X的第5位: X & 0000 1000 = 0000 1000

3、判断奇偶 根据未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if (a & 1 == 0)代替if (a % 2 == 0)来判断a是不是偶数。         

2、按位或运算 |

应用:常用来将数据的 指定位 置为1。
例:将X=10100000的低4位置1 ,用 X | 0000 1111 = 1010 1111即可得到。

3、异或运算 ^

应用:
(1)使特定位翻转 找一个数,对应X要翻转的各位,该数的对应位为1,其余位为零,此数与X对应位异或即可。
例:X=10101110,使X低4位翻转,用X ^ 0000 1111 = 1010 0001即可得到。

(2)与0相异或,保留原值 ,X ^ 0000 0000 = 1010 1110。


4、按位取反运算符 ~

注意: ~1=-2; ~0=-1;      是按照补码来取反的!!!

如:(~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。

原理分析:

二进制数在内存中以补码的形式存储。

~9的计算步骤:
        转二进制:0 1001
        计算补码:0 1001
        按位取反:1 0110
_____
        转为原码:
        按位取反:1 1001   
        末位加一:1 1010
        符号位为1是负数,即-10

~-9的计算步骤:
        转二进制:1 1001
        计算补码:1 0111
        按位取反:0 1000
        _____
        转为原码:
        正数的补码和原码相同,仍为:0 1000 ,即8

6、关于生成随机数

  1、 C 库函数 rand()

在 C++ 程序中,在新标准出现之前,C 和 C++ 都依赖一个简单的 库函数 rand 来生成随机数

这个函数生成的是均匀分布的伪随机数,每个随机数的范围在 0 和一个系统相关的最大值(至少为 32767)之间。

int rand(void);

rand()函数 返回一个 0 ~ RAND_MAX 之间的整数。RAND_MAX 是一个定义在 <cstdlib> 的常数。 

该函数返回的数字实际上是用算法生成的,实际上并不是随机的。它是根据种子生成的,根据不同的种子产生不同的随机序列。系统默认的种子是1,所以说每次使用的随机序列都是固定的。

所以需要配合随机种子生成函数来使用 ——

要想使每次运行时变量 x 的值都不同,就必须使它的种子随机,这时就需要用到srand函数。

void srand(unsigned int seed);

srand()函数 就是用来设置rand()函数的种子的。根据不同的输入参数可以产生不同的种子。通常使用time函数作为srand函数的输入参数。

time函数会返回1970年1月1日至今所经历的时间(以秒为单位)。

在使用 rand() 函数之前,srand() 函数要先被调用,并且在整个程序中只需被调用一次

具体使用示例:

  1. #include <cstdlib>
  2. #include <ctime>
  3. using namespace std;
  4. int main()
  5. {
  6. srand(time(nullptr)); // 用当前时间作为种子
  7. int min = 5, max = 10;
  8. int randomValue = (rand() % (max - min)) + min;//范围[min,max)
  9. randomValue = (rand() % (max - min + 1)) + min;//范围[min,max]
  10. randomValue = (rand() % (max - min)) + min + 1;//范围(min,max]
  11. }

缺点:

1、不能产生随机浮点数

2、均匀分布:有很多程序需要不通范围的随机数。一些程序需要非均匀分布的随机数。而在编写程序为了解决这些通常会转换 rand 生成的随机数的范围、类型或者是分布时,常常会引入非随机性。

3、随机数:多次循环产生的随机数序列是完全一样的

如:

  1. #include<iostream>
  2. #include<ctime>
  3. using namespace std;
  4. int main() {
  5. for (int j = 0; j < 5; j++) {
  6. srand(time(0)); //产生不同的随机数种子
  7. for (int i = 0; i < 10; i++)
  8. cout << rand() % 10 << " "; //rand函数 ;
  9. cout << endl;
  10. }
  11. }

运行结果:

但是,如果将程序修改如下就不会出现这样的重复序列

  1. #include<iostream>
  2. #include<ctime>
  3. using namespace std;
  4. int main() {
  5. srand(time(0)); //产生不同的随机数种子
  6. for (int j = 0; j < 5; j++) {
  7. //srand(time(0)); //产生不同的随机数种子
  8. for (int i = 0; i < 10; i++)
  9. cout << rand() % 10 << " "; //rand函数 ;
  10. cout << endl;
  11. }
  12. }

 运行结果:

一种特性应用场景:

结合 rand() 函数的均匀分布以及有限范围的特点,可以在遗传算法的实现中实现“随机性”的要求

  1. double p = (rand()/RAND_MAX)*Len;//将随机数均匀投射到[0,Len]的区间范围内
  2. if(p<X){
  3. //情况1
  4. }
  5. else //……

 详见我之前关于遗传算法实现的文章:
GA遗传算法实现记录_努力的耿耿的博客-CSDN博客

 

2、C++11函数random()

头文件 random

运用示例代码:

  1. #include<random>//头文件
  2. #include<iostream>
  3. #include<ctime>
  4. using namespace std;
  5. int main()
  6. {
  7. default_random_engine e(time(0));//引擎生成随机序列,设置种子
  8. uniform_real_distribution<double> u(-1.2,3.5);//设置产生的随机数的类型以及范围
  9. for(int i = 0; i < 10; ++i)
  10. cout << u(e) << endl;
  11. return 0;
  12. }

详细原理见这篇博客:
 【C++】c++ 11中的随机数 ——random_S大幕的博客-CSDN博客_c++11 随机数

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/463098
推荐阅读
相关标签
  

闽ICP备14008679号