首页 > 其他分享 >奇怪的错误:关于函数重载,头文件使用和新手避坑的小科普

奇怪的错误:关于函数重载,头文件使用和新手避坑的小科普

时间:2024-10-19 21:49:24浏览次数:3  
标签:__ 头文件 int pow 避坑 long printf 重载 return

奇怪的错误:关于函数重载,头文件使用和新手避坑的小科普

题目描述


        $ n $个小球排成一排,现在有$k$种不同颜色的油漆,给每个小球都涂色。如果相邻两个小球的颜色必须不同,那么共有多少种涂法?

输入


        一行,两个整数$ n $,$k$

输出


        一行,一个整数,为满足题意条件的整数。


这应该是道简单到不能再简单的数学题了(至少我猜是的),根据往年情形,起码不应该在CSP-J的模拟题当中吧。


分析:


第一个球可以刷··种颜色,后面··个球都是各能刷··种颜色,于是答案就是··。本来以为这题是道高精快速幂,但是,根据数据范围,保证答案\le2^{31}-1。。。
所以只需要将答案

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

相关文章

  • 运算符重载
    基础概念运算符重载使用了一个名为operator的关键字,重载运算符后,在使用时会调用重载后的方法,使用这种方法可以实现对象之间自定义+-操作。可重载运算符:一元运算符:+,-,!,~,++,--算术运算符:+,-,*,/,%比较运算符:==,!=,<,>,<=,>=代码示例此段代码重载了+,==......
  • Vue快速嵌入百度地图,避坑提效指南
    Vue快速嵌入百度地图,避坑提效指南在Vue项目中引用百度地图并没有高德地图那么方便,但是项目要用,这里分享下找到的方法,方便使用到的时候能快速接入,避雷避坑!新建bmap.js文件exportdefault{init:function(){constAK="这里是你申请的百度AK";cons......
  • 叉积法判断三点共线+重载运算符
    https://ac.nowcoder.com/acm/contest/92687/G#include<bits/stdc++.h>#defineendl'\n'#defineintlonglong#definelowbit(x)(x&-x)usingnamespacestd;constdoublepi=acos(-1);typedefpair<int,int>pii;piioperator-(piia,......
  • 对带有指针类型的切片进行循环时避坑
    func(sp*scrapePool)sync(targets[]*Target){//加锁 sp.mtx.Lock() defersp.mtx.Unlock() var(//target标记 uniqueTargets=map[uint64]struct{}{}//采集周期 interval=time.Duration(sp.config.ScrapeInterval)//采集超时时间 timeout......
  • 八要点助你精准挑选沙发,确保家装避坑!
    沙发可以称作是家里的第二张床,舒适是必不可少的要素。但是现在市场上的沙发种类繁多、鱼目混珠,挑选起来让人头大。那么,应该怎么选择一款优质的沙发呢?我们应该从以下八个方面进行选择。沙发材质:经济预算充足,可以选择真皮沙发,记住要选择头层皮,不要选二层皮。预算少的可以选择棉麻......
  • C++ 面向对象、特征、重载和重写、构造和析构、向上和向下转型、深浅拷贝。
    什么是面向对象(Object-OrientedProgramming,OOP)1.面向对象是一种编程范式,它通过将软件系统的设计和开发分解为“对象”(Object)的方式来实现更好地组织代码。面向对象的核心思想是将程序的结构分为对象,这些对象包含数据和操作这些数据的函数(即方法)。每个对象是类的实例,而类定......
  • c++中的函数重载
    C++中的 函数重载(FunctionOverloading)是一种多态性特性,允许在同一作用域内定义 多个同名函数,只要这些函数的参数列表不同(参数的类型、数量或顺序不同)。编译器根据函数调用时传递的参数类型和数量来决定调用哪个函数。1. 函数重载的规则C++编译器通过以下规则来区分重载的......
  • 【C++】类和对象(3)(默认成员函数--拷贝构造&赋值重载)
    引言前文介绍了C++中默认成员函数中的构造函数和析构函数,相信已经对它们的功能与用法有了基本认识,本文接着介绍也很常见的拷贝构造函数和赋值重载函数,便于对C++进一步的学习。拷贝构造函数补充知识:深浅拷贝深拷贝和浅拷贝是C++中对象拷贝的两种不同方式。浅拷贝是指将......
  • C++ day04(友元 friend、运算符重载、String字符串)
    目录【1】友元friend1》概念2》友元函数 3》友元类 4》友元成员函数 【2】运算符重载1》概念2》友元函数运算符重载 ​编辑 3》成员函数运算符重载4》赋值运算符与类型转换运算符重载 5》注意事项【3】String字符串类【1】友元friend1》概念定义:......
  • C#中函数重载的说明
    一.函数重载的基本概念C#中的函数重载是指在同一个类中定义多个同名的函数,但这些函数的参数类型、参数个数、参数顺序等不同,以便适应不同的调用需求,增加代码的兼容性。二.函数重载的作用2.1定义多个相类似的函数,减少函数的数量,避免命名空间的相互干扰导致的误解;2.2提升程......