奇怪的错误:关于函数重载,头文件使用和新手避坑的小科普
题目描述
个小球排成一排,现在有种不同颜色的油漆,给每个小球都涂色。如果相邻两个小球的颜色必须不同,那么共有多少种涂法?
输入
一行,两个整数,。
输出
一行,一个整数,为满足题意条件的整数。
这应该是道简单到不能再简单的数学题了(至少我猜是的),根据往年情形,起码不应该在CSP-J的模拟题当中吧。
分析:
第一个球可以刷··种颜色,后面··个球都是各能刷··种颜色,于是答案就是··。本来以为这题是道高精快速幂,但是,根据数据范围,保证答案。。。
所以只需要将答案
k*pow(k-1,n)
输出即可。
但是!
我的初稿犯了一个愚蠢的错误:
#include <bits/stdc++.h>//pow 在cmath里,对于不同类型参数使用不同pow函数
using namespace std;
typedef long long ll;
int main()
{
ll n,k;
scanf("%lld%lld",&n,&k);
printf("%lld\n",(k*(pow(k-1,n))));
return 0;
}
如果还没看出来,再瞅一眼printf的格式!在头文件中,printf函数是这样定义的:
int printf (const char *__format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __mingw_vprintf( __format, __local_argv );
__builtin_va_end( __local_argv );
return __retval;
}
注意,出现在后面实参列表中的,是地址!在使用变量(不要管引用或指针)而未使用取地址符时,C++的反应有两种:
1:
[Error]Cannot convert int to int*
2:
Process exited after 1.733 seconds with return value 3221225477
然而,对于
k*(pow(k-1,n))
这样的具体数值,编译器会直接将这个值当做地址看待,它就成了一个野指针,访问的地方可能是域外或是未定义的地方。在域外时,如这个程序输入2 2时,“cout<<x”会输出2,错误输出是4611686018427387904。当然,也有更不幸的(由x的取值决定),那就是
Process exited after 1.733 seconds with return value 3221225477
因为它访问了域外地址,这是禁止的,所以程序终结了。
换作OJ,它大概率会RE,即runtimeError,由这个错误的访问导致。
那这样是不是就对了呢?
#include <bits/stdc++.h>//pow 在cmath里,对于不同类型参数使用不同pow函数
using namespace std;
typedef long long ll;
int main()
{
ll n,k;
scanf("%lld%lld",&n,&k);
int x = (k*(pow(k-1,n)));
printf("%lld\n",&x);
return 0;
}
还是不对。
我们会发现,答案是 7470588 !
其实,分析原因,只是因为pow函数定义的重载问题。按住Ctrl,挪到cmath头文件上,单击一下,就可以跳转进去了。搜索(Ctrl+f)pow函数,得到完整重载:
using ::pow;
#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
inline _GLIBCXX_CONSTEXPR float
pow(float __x, float __y)
{ return __builtin_powf(__x, __y); }
inline _GLIBCXX_CONSTEXPR long double
pow(long double __x, long double __y)
{ return __builtin_powl(__x, __y); }
#if __cplusplus < 201103L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 550. What should the return type of pow(float,int) be?
inline double
pow(double __x, int __i)
{ return __builtin_powi(__x, __i); }
inline float
pow(float __x, int __n)
{ return __builtin_powif(__x, __n); }
inline long double
pow(long double __x, int __n)
{ return __builtin_powil(__x, __n); }
#endif
#endif
template<typename _Tp, typename _Up>
inline _GLIBCXX_CONSTEXPR
typename __gnu_cxx::__promote_2<_Tp, _Up>::__type
pow(_Tp __x, _Up __y)
{
typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
return pow(__type(__x), __type(__y));
}
这里有很多同名函数,都叫POW,然而参数列表不同。 如果它选错了:
强制转换,C++有时会报错:
[Error]Cannot convert int to int*
但是,也有的时候它不报错,但就是给你错误的转换。 输出:7470588
我们改了一下参数,然后呢?(初学者最容易犯的错误复现)
#include <bits/stdc++.h>
#include <stdio.h>
#include <cmath>
using namespace std;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
int x = (int)k * (int)pow((int)k-1,(int)n);
cout<<n<<" "<<k<<" "<<x<<endl;
cout<<sizeof(x)<<endl;
printf("%d",x);
return 0;
}
输出:
7470588
。。。
带上
cout<<n<<k<<x<<endl<<sizeof(x);
输出为:
2 2 2
4
7470588
所以,x值是没有问题的,问题出在了输出上。
是这样的,printf
函数的调用方式不正确。在 printf
函数中,%d
格式化说明符用于输出整数,但是在调用 printf
时,传递的参数是 &x
,这是 x
的地址,而不是 x
的值。因此,printf
实际上输出的是 x
变量的内存地址,而不是 x
的值。
AC_code
#include <bits/stdc++.h>
#include <stdio.h>
#include <cmath>
using namespace std;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
int x = (int)k * (int)pow((int)k-1,(int)n);
cout<<n<<" "<<k<<" "<<x<<endl;
cout<<sizeof(x)<<endl;
printf("%d",x);
return 0;
}
标签:__,头文件,int,pow,避坑,long,printf,重载,return
From: https://blog.csdn.net/weixin_73139914/article/details/143084388