scanf的%c读取的是单个字符,是连续的,
如:scanf("%c%c",&ch1,&ch2),输入'ab'则接受'ab',但若输入'a b'则会接收'a '。
解决方案: scanf("%c %c",&ch1,&ch2),注意只是加了个空格
Num.2 switch语句的参数类型 (2021/8/6)
switch语句的参数类型只能为int、char等,不能为实型(浮点数、实数等)或字符串!!!
Num.3 输入字符串(string) (2021/8/6)
1 scanf("%s %s",book[i].name,temptype);
运行时报错:
[Error] cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...'
[Error] cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...'
分析:
这里的book[i].name和temptype均为string类型。
语法:
- const char *c_str();
- c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.
- 为了与C兼容,在C中没有string类型,故必须通过string类对象的成员函数c_str()把string对象转换成C中的字符串样式。
解决方案:
在要打印的string后面加 .c_str()即可
更正后:
1 scanf("%s %s",book[i].name.c_str(),temptype.c_str());
然鹅,上面的分析都是错的!!!
虽然修改后编译可以通过,但运行结果仍然是错的-输入后根本没有为book[i].name和temptype赋值!
解决方案的解决方案:
1 cin>>book[i].name>>temptype;
总结:
输入字符串,千万不要用scanf!!!
用cin!!!
Num.4 字符串(string)赋值 (2021/8/6)
1 string sort1[k+1]={0},sort2[k+1]={0};
运行时报错(编译已通过):
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
Aborted (core dumped)
分析:
我竟然给字符串赋值为0...
解决方案:
直接赋为空集。
更正后:
1 string sort1[k+1]={},sort2[k+1]={};
Num.5 C++精度修正问题 (2021/8/7)
原题:求解一元二次方程
原代码:
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 using namespace std;
5
6 double a,b,c,x1,x2,delta;
7
8 int main()
9 {
10 cin>>a>>b>>c;
11 delta=b*b-4*a*c;
12 if(delta<0)cout<<"No answer!";
13 else if(delta>0) printf("x1=%.5lf;x2=%.5lf",min((-b-sqrt(delta))/(2*a),(-b+sqrt(delta))/(2*a)),max((-b-sqrt(delta))/(2*a),(-b+sqrt(delta))/(2*a)));
14 else printf("x1=x2=%.5lf",(-b)/(2*a));//x1+x2=-b/a,x1=x2时,x1=x2=-b/2a
15 return 0;
16 }
测试信息:一个测试点WA了
分析:
C/C++中,浮点数的运算(和函数)有可能存在误差,
例如,在经过大量计算后,由于误差的影响,整数1变成了0.9999999999。
因此,浮点数只有完全一样才能使用==判断相等。
解决方案:
可以借助修正写法,fabs(a – b) < eps,可以自定义精度esp,esp一般取1e-8左右大小。
比如double类型的a和b,要判断a==b,在一定的精度范围内比较大小。
修正后:
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #define eps1 1e-10//定义精度esp 10的-10次方
5 #define eps2 1e-6//定义精度esp 10的-6次方
6 using namespace std;
7
8 double a,b,c,x1,x2,delta;
9
10 int main()
11 {
12 cin>>a>>b>>c;
13 delta=b*b-4*a*c;
14 if(delta<0&&abs(delta)>eps1)cout<<"No answer!";//(修正写法)
15 else if(abs(delta)<eps1)printf("x1=x2=%.5lf",(-b)/(2*a));//x1+x2=-b/a,x1=x2时,x1=x2=-b/2a //(修正写法)
16 else
17 {
18 x1=(-b+sqrt(delta))/(2*a);
19 x2=(-b-sqrt(delta))/(2*a);
20 printf("x1=%.5lf;x2=%.5lf",min((-b-sqrt(delta))/(2*a),(-b+sqrt(delta))/(2*a)),max((-b-sqrt(delta))/(2*a),(-b+sqrt(delta))/(2*a)));
21 }
22 return 0;
23 }
总结:
细节决定成败!
Num.6 C++中的对数函数 (2021/8/9)
知识点:
exp(x)----求e的x次方
log2(x)----返回以2为底数,以x为真数的对数的值
log10(x)----返回以10为底数,以x为真数的对数的值
注意:
C++没有自定义的对数函数!!!
就是说,无法提供loga(b)----以a为底数,以b为真数的对数!!!
但是,可以通过换底公式间接地来求。
代码如下:
1 #include<iostream>
2 #include<cmath>
3 using namespace std;
4 int main()
5 {
6 double a,b;//以a为底数,b为真数的对数函数
7 cin>>a>>b;
8 cout<<"loga(b)="<<log(b)/log(a)<<endl;//换底公式
9 return 0;
10 }
换底公式:
对于a,c∈(0,1)∪(1,+∞)且b∈(0,+∞),有
推导过程:
若有对数 ax=b ,则
x=logab ---- ①
因此,
待会①式,得:
证毕。
Num.7 floor/ceil取整问题 (2021/8/19)
用floor/ceil取整时,得到的返回值是浮点数!!!
这就导致一些题不明不白就WA了...
解决方案: 强制类型转换,前面加个(int)或(long long)
Num.8 !右结合性问题 (2021/8/20)
!右结合性非常强,用的时候一定不要忘了加括号!!!
运行结果错误:
1 while(!x%(int)pow(2,t)){t++;}
显然,这里的!与x结合到了一起,x是非0的数,!x就变成了0,这不是我们想要的结果。
更正后:
1 while(!(x%(int)pow(2,t))){t++;}
Num.9 数组&数据类型问题 (2021/8/29)
数组不是基础数据类型,而是构造数据类型。
(基础数据类型有bool,char,int,float,double,void,wchar_t【宽字符型】)
注:
宽字符型wchar_t是这样来的:
1 typedef short int wchar_t;
所以 wchar_t 实际上的空间是和 short int 一样。
关于wchar_t,详见这篇博客
一些基本类型可以使用一个或多个类型修饰符进行修饰,如signed,unsigned,short和long。
关于typedef:
可以使用ta为一个已有的类型取一个新的名字。
e.g.
1 typedef long long ll;
2 ll a; //声明变量
其实这就相当于
#define ll long long
ll a;
回到正题。
正因为数组不是基础数据类型,所以在stack和queue中,像这样用就会报错:
1 #include<iostream>
2 #include<typeinfo>
3 #include<cxxabi.h>
4 #include<stack>
5 #include<queue>
6
7 using namespace std;
8
9 template<typename type>
10 inline string type_of(type &x)
11 {
12 return abi::__cxa_demangle(typeid(x).name(),0,0,0);
13 }
14
15 stack<char[200]>a;
16 queue<char[200]>b;
17
18 signed main()
19 {
20 cout<<type_of(a)<<endl;
21 cout<<type_of(b)<<endl;
22 return 0;
23 }
改成string就好了
1 #include<iostream>
2 #include<typeinfo>
3 #include<cxxabi.h>
4 #include<stack>
5 #include<queue>
6
7 using namespace std;
8
9 template<typename type>
10 inline string type_of(type &x)
11 {
12 return abi::__cxa_demangle(typeid(x).name(),0,0,0);
13 }
14
15 stack<string>a;
16 queue<string>b;
17
18 signed main()
19 {
20 cout<<type_of(a)<<endl;
21 cout<<type_of(b)<<endl;
22 return 0;
23 }
不过玄学的是,用在vector好像就可以???
1 #include<iostream>
2 #include<typeinfo>
3 #include<cxxabi.h>
4 #include<vector>
5
6 using namespace std;
7
8 template<typename type>
9 inline string type_of(type &x)
10 {
11 return abi::__cxa_demangle(typeid(x).name(),0,0,0);
12 }
13
14 vector<char[200]>n;
15
16 signed main()
17 {
18 cout<<type_of(n)<<endl;
19 return 0;
20 }
不知道什么原理。。。
但在实际用n数组的时候又会报错
如果改为vector<string>n就不会报错了,但这又是为什么?
求高手指教~
Num.10 关于static (2021/9/1)
听一个dalao说,static放快写里可以卡常(虽然他也不明白怎么回事)
然后我一听来精神了,一并将其写进了快读里……
第一天啥事没有,题目照常AC
但在第二天
我竟然被一个单调队列的黄题卡了一上午……
我百思不得其解,最后手动二分调试代码,才发现竟然是快读出问题了。。。
1 template<typename type> 2 inline void read(type &x) 3 { 4 x=0;static bool flag(0);char ch=getchar(); 5 while(!isdigit(ch)) flag^=ch=='-',ch=getchar(); 6 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 7 flag?x=-x:0; 8 }
第4行的flag是用来判断输入负号的,我顺手将其用static修饰,幻想它能卡一点常数,结果显然:
(听取WA声一片……)
这个快读读取正数是没有错误的,读取一个负数也可以,但读完一个负数继续正数就错了,后面的符号全变负
简单查了下static的用法,很快就找到了答案。
修饰局部变量时,表明该变量的值不会因为函数终止而丢失。
显然,若读进的第一个数为负,则flag就变为1
快读结束时,flag由于static的作用,不会像普通变量一样退出函数就被销毁
因此再读第二个数时,已经存在的flag就不会被新的声明影响,仍保持1的值,所以同样会读成负数。。。
解决方案:
将static去掉就可以啦。
那么对于快写:
1 template<typename type> 2 inline void write(type x,bool mode) 3 { 4 x<0?x=-x,putchar('-'):0;static short Stack[50],top(0); 5 do Stack[++top]=x%10,x/=10; while(x); 6 while(top) putchar(Stack[top--]|48); 7 mode?puts(""):putchar(' '); 8 }
为什么这里用static就没事呢?
很简单,因为对于每次快写的调用,都能保证栈空和top为0,重复声明、赋值与否,都不会对结果造成影响。
这时,用static关键字就可以跳过无用的二次声明、赋值阶段,从而节省运行时间。
总结:
对于很多陌生的关键字,
不要乱用!
不要乱用!!
不要乱用!!!