C++代码精炼

前言

主要以为主。

输入输出

文件尾类型

C 版

1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
int a,b;
while (scanf("%d %d",&a, &b) != EOF)
printf("%d\n",a+b);
}

C++ 版

1
2
3
4
5
6
#include<iostream>
using namespace std;
int main(){
int a,b;
while(cin>>a>>b){cout<<a+b<<endl;}
}

在C++里,cin本身就是一个对象,因此可以直接运用到while( )检测是否有输入,若无输入则结束运行。

例如:

1
2
3
 while(cin>>a){
...
}

格式化输出

1
printf("%d%c",bmax," \n"[i==n]);

当后面的执行条件i!=n的时候,%c就相当于空格
当后面的执行条件i==n的时候,%c就相当于\n 【来源

字符串类型

(1)cin>>

​ 可接受字符串,但遇到“空格”、“TAB”、”回车”(下一次缓冲区读取时 会被cin自动丢弃)均结束从缓冲区读取

(2)getline()

​ 默认”回车”(下一次缓冲区读取时 会被自动丢弃)结束

1
2
3
4
5
6
string line;
getline(cin,line);//按回车键结束输入
#指定分隔符
istream& getline(istream& is,string& str,char delimiter='\n')
//输入一串字符(不管多少个回车键),只要是在‘#’号之 前的字符都会读取并保存
getline(cin,line,'#');

(3)cin.get()

​ 默认”回车”(下一次缓冲区读取时 仍会被读取)结束

​ 两种用法:

a. cin.get(字符变量名)可以用来接收一个字符 

1
2
char ch;
ch = cin.get(); or cin.get(ch);

​  b.cin.get(字符数组名,接收字符数目)用来接收一行字符串,可以接收空格

1
2
char a[20];
cin.get(a,20);

cin.get()会将回车键存储在缓存中,若后面还有cin.get()函数,则该函数会将缓存中的 取出并赋予后面的输入变量中,故,使用了cin.get()函数就一定后面要加getchar(),将回车键读取并丢弃弃!!!

(4)cin.getline()
​ 接受一个字符串可以接受空格并输出  

1
2
3
4
char m[20];
cin.getline(m,5);
//输入:jkjkjkjkkjkjkjkj
//输出:jklj 第5个字符默认添加'\0'

(5)gets()【c++11已弃用!!!】
​ 接受一个字符,可以接受空格并输出,需包含头文件#include<string>

1
2
char ch;
gets(ch);

(6)getchar()

需包含头文件`#include<stdio.h>`

getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了,第一次getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的getchar()再执行时就会直接从缓冲区中读取了。
故一般用getchar()来清除缓存中的字符;

4)输入强行退出
​ Ctrl + Z 或输入EOF再按回车键

大佬解析:https://www.cnblogs.com/zzw1024/p/10502011.html

动态创建数组

1
2
3
4
5
6
7
8
9
10
11
//一维数组
#include <iostream>
#include <string.h>
using namespace std;

typedef long long ll;

ll *aim = new ll[n];
ll *maxj = new ll[n];
memset(aim,0,sizeof(aim)*n);
memset(maxj,0,sizeof(maxj)*n);

为何动态创建二维数组必先预先知道二维数组每一列的长度

大佬解析过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*  动态创建二维数组   */
//半自动化
char (*color)[20] = new char[n][20]; // √
char *color[20] = new char[n][20]; // ×
/*
[] 的优先级高于 *
*color[20] 为 指针数组(array of pointers),即20个 char 类型的指针
(*color)[20] 为 数组指针(a pointer to an array),即 指向数组(首地址,++按列大小)的指针
*/
//释放
delete [] color;


//真正意义上的创建二维数组
int **array;
array=new int *[row];
for(int i = 0; i < row; i++)
{
array[i]=new int [col];
//以0初始化,#include <string.h>
memset(array[i],0,col*sizeof(int));
}
//释放
for (int i = 0; i < row; i ++) {
delete[] array[i];
array[i] = NULL;
//不要忘记,释放空间后p[i]不会自动指向NULL值,还将守在原处,只是释放内存而已,仅此而已。
}
delete [] array
array=NULL;

计算数组长度

1
2
3
4
5
6
7
template<typename T>
//计算数组长度
int calculateLength(T &arr){
cout<<"size arr:"<<sizeof(arr)<<endl;
cout<<"size arr[0]:"<<sizeof(arr[0])<<endl;
return sizeof(arr) / sizeof(arr[0]);
}

STL标准库

首先使得dev 支持 C++11

使devc++拥有c++11的功能(如何让devc++支持c++11)

tools->compiler options->add the following commands when calling the compiler(勾选) ,然后添加如下语句(最好release\debug都添上)

1
-std=c++11

头文件

1
2
3
4
5
6
7
//set、map属于std, unordered_map属于std::tr1;
#include <set>
#include <map>
#include <tr1/unordered_map>

using namespace std::tr1;
using namespace std;

调试

dev 首先设置”生成调试信息“

(1)Tools -> setting ->linker-> generate debugging information 那栏改为”Yes“

dev调试

(2) tool->environment options->watch variable under mouse(勾选)

dev调试2

设置断点后 编译 F5 调试(勾勾) F7运行下一行

四舍五入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iomanip>
#include<iostream>
using namespace std;
int main()
{
double f = 123456789;
// 输出1.23457*(10,6)(采用科学记数法变成包含整数和小数,共6位,且最后一位四舍五入)
cout<<f<<endl;
//输出120000000 1.2*pow(10,6)采用科学记数法,包含整数和小数,共两位,且最后一位四舍五入)
cout<<setprecision(2)<<f<<endl;
cout<<fixed<<f<<endl; //输出12345689.000000(小数6位补0)
cout<<setprecision(2)<<fixed<<f<<endl; //输出12345689.00
cout<<fixed<<setprecision(2)<<f<<endl; // 效果同上

double f = 3.123456789;
// 输出3.12346 (包含整数和小数,且四舍五入)
cout<<f<<endl;
//输出3.1(包含整数和小数,共两位,且最后一位四舍五入),这条会作用到下一条去
cout<<setprecision(2)<<f<<endl;
//输出3.123457 (仅包含小数,且四舍五入),没有上一条,则输出六位小数3.123457
cout<<fixed<<f<<endl;
cout<<setprecision(2)<<fixed<<f<<endl; //输出3.12 (小数2位,四舍五入)
cout<<fixed<<setprecision(2)<<f<<endl; // 效果同上

system("pause");
return 0;
}

setprecision(n)是流格式控制符之一,在iomanip头文件中。

c++默认的流输出数值有效位是6包括整数和小数,若数值超出6位,则第七位四舍五入到6位数

fixed :浮点值显示为定点十进制默认是小数6位数,不包含整数,若小数位超出6位,则四舍五入到6位数

1.setprecision(n) 指定一个浮点数的精度默认设置输出的数字的总位数为n包含整数和小数部分;其中setprecision(0)效果是跟c++默认的流输出数值一样,有效位是6位,包括整数和小数

2.fixed必须与setprecision(n)配合使用,用来控制小数位数,不够补0,只要写一次fixed,后面的setprecision(n)就都是指小数了。 fixed与setprecision谁先谁后没有关系,但通常是fixed在前先固定6位小数(若此时小数已经超出6位,则先四舍五入到6位)再precision(n)取n位小数(n<6)

3.如果与setiosnags(ios::scientific)合用, 可以控制指数表示法的小数位数。setiosflags(ios::scientific)是用指数方式表示实数。

4.resetiosflags(ios::fixed) 取消精度的设置。

1.)超出的位数会被四舍五入进去!!!

2)与setw()不同 ,setprecision(n)一直作用到下一个setprecisin(n)之前,所以,只需要写一个setprecision(n)就可以。setw()要每次都写

floor(), ceil()函数都包含在头文件“Math.h”中

Floor() 不大于自变量的最大整数
Ceil() 不小于自变量的最大整数

数组开辟空间

来源:C/C++数组的大小最大能有多大?

局部变量:函数内申请的变量,数组,是在栈(stack)中申请的一段连续的空间。栈的默认大小为1M到2M,如果定义a[1024*1024];运行时就会报”段错误“;

全局变量:全局数组,静态数组(static)则是开在全局区(静态区)(static)。大小为2G,所以能够开的很大;

动态分配:malloc、new出的空间,则是开在堆(heap)的一段不连续的空间。理论上则是硬盘大小;

同一个程序共用栈和静态区,因此要申请一个超大数组或许定义为全局变量,而多个超大数组时最好是动态申请

bug

Time Limit Exceeded

(1)可能是某种情况没有考虑到或者逻辑bug(很大概率是这个(;´д`)ゞ)

(2)算法不优

think

数据范围,最好定义成long long 型

1
2
3
typedef long long ll;
//定义长整型
ll n;

数据范围

慎用递归,易导致超时

动态规划大概率适合求最优解问题

经典中的经典算法:动态规划(详细解释,从入门到实践,逐步讲解)

这一篇博文讲得比较透彻

逗号运算符

逗号运算符是将一系列运算按顺序执行。

整个逗号表达式的值为系列中最后一个表达式的值

1
var = (count=19, incr=10, count+1);

在这里,首先把 count 赋值为 19,把 incr 赋值为 10,然后把 count 加 1,最后,把最右边表达式 count+1 的计算结果 20 赋给 var。上面表达式中的括号是必需的,因为逗号运算符的优先级低于赋值操作符

1
2
a = 1*2,2*2,3*3;
//a = 2;因,优先级低于 = 后面表达式只运行,不保留结果

https://www.runoob.com/cplusplus/cpp-comma-operator.html

计算机存储数据

大佬解析: https://blog.csdn.net/daiyutage/article/details/8575248

乘法容易溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;

double sum(int n){
if(n%2 != 0)
return (n+1)/2*n;
else
return n/2*(n+1);
}

int addSum(int n){
int i,sum=0;
for(i=1; i<=n; i++){
sum+=i;
}
return sum;
}

int main(){

int n;
while(cin>>n){
//cout<<sum(n)<<endl<<endl;
cout<<addSum(n)<<endl<<endl;
}
return 0;
}

初始化数据的重要性

循环体内的局部变量内存分配和释放

循环体内的局部变量内存分配和释放2

在刷题过程中发现了如上bug ,以下面这段代码为例,目的是输出出现次数最多的字符串。 Count[1000] 、p[1000]若没有进行初始化,在多组数据输入后,虽然两者均为循环内部局部变量,但是未初始化将保留原来的数据,导致影响后续结果

所以以后编程不要依赖于编译器缺省初始化定义与初始化尽量同步~(ง •_•)ง

大佬解析:循环体内的局部变量内存分配和释放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <string.h>
using namespace std;

int main(){

int n;
cin>>n;
//至0结束
while(n){
//记录各种颜色出现多少次
//int *Count = new int[n];
int Count[1000] = {0};
int index = 0;
//char (*p)[20] = new char[n][20];
char p[1000][20] = {};
bool flag = true;

for(int i=0; i<n; i++){
char str[20];
cin>>str;
//计数
if(i == 0){
strcpy(p[index],str);
Count[index]++;
index++;
}else{
int j;
for(j=0; j<index; j++){
if(strcmp(str,p[j]) == 0){
Count[j]++;
flag = false;
break;
}
}//end of for
//没有就添加进去
if(flag){
strcpy(p[index],str);
Count[index]++;
index++;
flag = true;
}

}//end of else
}

//找到最大值
int Cmax = Count[0],t=0;
for(int i = 1; i < index; i++ ){
if(Cmax <= Count[i]){
Cmax = Count[i];
t = i;

}
}
cout<<p[t]<<endl;
//释放动态空间
// for(int i = 0; i < n; i++){
// delete []p[i];
// }
// delete []p;
cin>>n;
}
return 0;
}

C++的String对象(字符串类)

String详解

---------------- 本文结束 ----------------

本文标题:C++代码精炼

文章作者:Pabebe

发布时间:2019年10月24日 - 10:04:33

最后更新:2020年08月04日 - 14:32:33

原始链接:https://pabebezz.github.io/article/2fdcd6a9/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%