0

我最近写了一个程序来帮助我理解 C++ 中内存指针的基础知识,我选择了一个简单的素数查找器。

我终于让它工作了。(是的调试!)

我让它运行看看它走了多远,它到达了 #815389,我的详细信息告诉我是第 65076 个素数,我遇到了应用程序崩溃。我能想到的一件事是我的整数溢出,所以我将它们改为长整数,它卡在同一个地方。

有人可以帮助解释是什么限制导致了这种情况吗?

comp:WinVista 64 位家庭高级版,6GB ram AMD 4800+ X2 程序在 4,664K 内存使用时崩溃

来源:

#include <cstdlib>

#include <iostream>

\\\\(Backslashes added for readability)

using namespace std;

long number;
long numnum;

class num;

class num {

  public:

         long i;
         void check();
         bool nxt;
         num* nxtnum;
};

void num::check() {

 if (number % i != 0) {
            if (nxt == true) {
                    (*nxtnum).check();
            } else {
                   nxtnum = new num();
                   (*nxtnum).i = number;
                   numnum++;
                   cout << numnum << ":" << number << ", ";
                   nxt = true;
            };
 };
};


int main(long argc, char *argv[]){

  numnum = 1;
  cout << numnum << ":" << 2 << ", ";
  num two;
  two.i = 2;
  for (number = 3; 1<=1000001; number++) {
    two.check();
  };
  cout << endl;
  system("PAUSE");
  return EXIT_SUCCESS;
};

(不要介意用户名,这只是我使用的别名,因此我可以使用 google 跟踪我的所有帖子)

4

6 回答 6

7

堆栈溢出?我看到这check是递归的。

于 2009-01-16T14:06:12.493 回答
4

我猜想 two.nxt 没有初始化。在 C 中,原始数据类型没有被初始化,这意味着它们的值与它现在占用的内存中发生的任何内容相同。这意味着在 main() 中,two.nxt = true 很可能会导致 check() 在无效指针上运行。尝试将其显式设置为 false,看看是否适合您。

[编辑] 如果这是问题,更重要的初始化将是当您在 check() 中分配新的 num 时。

于 2009-01-16T14:06:14.443 回答
2

肖恩是对的,two.nxt 从未初始化。事实上,num.nxt 从未为任何 num 实例初始化。如果类变得更健壮,则不需要成员 nxt。可以使用 nxt 指针代替:

class num
{
private:
    long i;
    num *nxtnum;
public:
    num (long value) : i (value), nxtnum (0) { }
    void check ()
    {
      if (number % i != 0)
      {
        if (nxtnum)
        {
          nxtnum->check ();
        }
        else
        {
          nxtnum = new num (number);
          cout << ++numnum << ":" << number << ", ";
        }
     }
};

当然,递归性质可能是罪魁祸首,初始化问题被隐藏了,因为您可能正在运行调试版本。将递归形式转换为迭代形式留作练习。

于 2009-01-16T14:22:33.193 回答
1

我可以看到几个问题:

  • 您正在分配一堆数字,但您没有检查 std::bad_alloc 异常。您可能只是内存不足...
  • 如果 nxtnum 为 != 0,则您不会在任何地方进行检查,即使我认为这样做是安全的,因为您取消引用它的唯一地方是保护它。然而,这并不是一个很好的练习。
  • 正如 Sean Edwards 所提到的, num 类没有构造函数,因此新创建的 num 的成员充满了几乎随机的垃圾。并且该随机垃圾可能包括将 nxt 设置为非零值。我将添加以下构造函数来为其提供一组安全的默认值:

    num::num() : i(0), nxt(false), nxtnum(0) {}

  • 你真的不需要布尔值,我只是检查 nxtnum 是否非零。

  • 正如 Jeff Yates 所说,由于递归函数嵌套太深,您可能会遇到堆栈溢出,但看起来它不会递归那么深。
于 2009-01-16T14:20:54.163 回答
0

顺便说一句,如果您使用的是 Microsoft 编译器,则 int 和 long 在针对 x64 时的大小相同。您的 main 函数中还有一个无限循环,因为 1 将始终 <= 1000001。

于 2009-01-16T15:23:26.767 回答
0

我已经成功了,谢谢 Skizz

#include <cstdlib>
#include <iostream>
#include <windows.h>

using namespace std;

long number;
long numnum;
class num;
num *two;
num *nn;
num *bre;

class num
{
    private:
        long i;
        num *nxtnum;
    public:
        num (long value) : i (value), nxtnum (0) { }
        void *check ()
        {
          if (number % i != 0)
          {
            if (nxtnum)
            {
              //nxtnum->check ();
              nn = nxtnum;
            }
            else
            {
              nxtnum = new num(number);
              cout << ++numnum << ":" << number << ", ";
              nn = bre;
            }
         }else{nn=bre;}
        }
};

int main(long argc, char *argv[])
{
    numnum = 1;
    cout << numnum << ":" << 2 << ", ";
    two = new num(2);
    nn=two;
    for (number = 3; 1<=1000001; number++) {
        while (nn!=bre){
                nn->check();
                Sleep(0);
                }
        nn=two;
    };
    cout << endl;
    system("PAUSE");
    return EXIT_SUCCESS;
};

对于那些有兴趣的人

于 2009-01-16T16:34:34.657 回答