为什么我不能在C++中使用这段代码?

问题描述:

#include <iostream> 
#include <time.h> 

using namespace std; 

int main() 
{ 
    const int number = 1000000; 

    //Chain Vars------------------- 
    int chainLength = 0; 
    int startingNumber = 0; 
    int chain = 0; 
    int n = 0; 
    //---------------------------- 


    // start Time----------------- 
    clock_t startTime = clock(); 
    double duration; 
    //--------------------------- 


    //Cache----------------------------- 
    int* cache = new int[number+1]; 

    for (int i = 0; i < number+1; i++) 
    { 
     cache[i] = -1; 
    } 
    cache[1] = 1; 
    //--------------------------------- 


    for (int i = 2; i <= 1000000; i++) 
    { 
     n = i; 
     chain = 0; 

     while (n != 1 && n >= i) 
     { 
      chain++; 
      if ((n % 2) == 0) 
      { 
       n = n/2; 
      } 
      else 
      { 
       n = n * 3 + 1; 
      } 
     } 

     //Store the chain length in cache 
     cache[i] = chain + cache[n]; 
     //------------------------------- 

     if (cache[i] > chainLength) 
     { 
      chainLength = cache[i]; 
      startingNumber = i; 
     } 
    } 


    //----------------------------------------------------------------------------------------------- 
    duration = ((clock() - startTime)/(double)CLOCKS_PER_SEC); 
    cout << "Starting Number is: " << startingNumber << " with a length of: " << chainLength << endl; 
    cout << "Duration = " << duration << endl; 
    //----------------------------------------------------------------------------------------------- 

    getchar(); 

    return 0; 
} 

所以我的错误发生在第54行,并说我没有权限访问这个内存。在C#中相同的代码工作得很好。为什么我不能在C++中使用这段代码?

+5

Pastebin:糟糕 - 在SO上发布代码:很好。发布所有代码:错误 - 发布与问题相关的代码:很好 –

+2

*在c#中的相同代码工作得很好。* - ** C#不是C++ ** – PaulMcKenzie

+1

关闭一个错误。数组的索引从零开始,而不是从1开始。如果它在C#中起作用,那么您很幸运 - 即使它看起来适用于您选择的测试用例,C#中的代码也会有缺陷。 – Peter

在你for循环,你这样做:

for (int i = 2; i <= 1000000; i++) 
{ 
    n = i; 
    chain = 0; 

    while (n != 1 && n >= i) 
    { 
     chain++; 
     if ((n % 2) == 0) 
     { 
      n = n/2; 
     } 
     else 
     { 
      n = n * 3 + 1; 
     } 
    } 

    //Store the chain length in cache 
    cache[i] = chain + cache[n]; 
    //------------------------------- 

    if (cache[i] > chainLength) 
    { 
     chainLength = cache[i]; 
     startingNumber = i; 
    } 
} 

在某些时候while (n != 1 && n >= i)最有可能与n大于1000000结束。然后你会访问cache(当你做cache[n])出界(它是[0:1000000])。

while循环之前加std::cout << "i is " << i << std::endl;。之后添加 std::cout << "n is " << n << std::endl;。运行程序,你会得到(几秒钟后):

... 
i is 113381 
n is 85036 
i is 113382 
n is 56691 
i is 113383 
n is -1812855948 
Erreur de segmentation (core dumped) 

你在这里。现在,您可以使用调试器,识别错误,修复错误(最有可能重做您的循环),并使其工作! ;-)

提示:由于n变为负值,可能达到了int的最大值...然后只需使用类型(如long long int或uint64_t)。然后,你很可能不会有任何溢出(除非你让number秽物)。

C#不会像C++那样管理内存。如果在这里访问数组超出范围(或者,如上所述,您刚刚获得幸运),则可能不会出现错误。我不熟悉C#。访问数组必须总是被避免,它可能有不确定的行为(可能导致或不能导致崩溃)。

+0

我没有自己运行它,但我可以100%确定在循环退出后,n将为== 1或

+0

我认为“ n!= 1“只会结束,如果它是1 ...我会如何解决这个问题?我似乎无法找到修复:/ – sLowDowN

+0

@sLowDowN - 或..如果'n'得到否定的 - 请参阅我的文章:) –

运行和调试程序后:

//Store the chain length in cache 
    cache[i] = chain + cache[n]; 

n似乎是0x93f20374(在i113383),这是负-1812855948,或将利好2482111348 - 但溢出成为-1812855948

while (n != 1 && n >= i) 

环路负n结束,导致cache[n]崩溃。

+0

n如何得到负面?因为n只能被2除或乘以3 +1 ......这应该是一个非常简单的解决方案,但是我看不到它:D – sLowDowN

+0

@sLowDowN - 因为它溢出了'n'是一个带符号的int,并且到+ 2482111348(unsignedded),用int替换为-1812855948。 –

像jpo38说:

提示:当n为负,也许它达到INT的最大值...使用调试器来验证,只需做,while循环之前:

这是我的问题,然后我将“int n”改为“long long n”,因为“long n”仍然很小,现在它给了我正确的答案。谢谢大家:)这么简单,但有时它是你看不到的小事。

+0

该死的......我提到了我的帖子中的溢出,但为什么我没有得到更多的声誉! :-( – jpo38

+0

这让我想到:在数学上证明当你使用64位整数时n不会溢出? –