简体   繁体   English

C ++内存指针练习中的未知崩溃

[英]Unknown crash in a C++ Memory Pointers Exercise

I recently wrote a program to help me understand the basics of memory pointers in C++, I chose a simple prime number finder. 我最近写了一个程序来帮助我理解C ++中的内存指针的基础,我选择了一个简单的质数查找器。

I finally got it to work. 我终于得到它的工作。 (yay for debugging!) (是的,用于调试!)

And I let it run to see how far it goes, it gets to prime #815389 with my verbose tells me is the 65076th prime, I get an app crash. 我让它运行以查看进展情况,它达到素数#815389,我的冗长告诉我是65076素数,我遇到了应用程序崩溃。 The one thing I could think of was my ints overflowing so I changed them to longs, it gets stuck at the same place. 我能想到的一件事是我的整数溢出,所以我将它们更改为多头,它卡在同一位置。

Would someone be able to help explain what limitation is causing this? 有人能够帮助解释造成这种情况的限制吗?

comp: WinVista 64-bit Home Premium, 6GB ram AMD 4800+ X2 program crashes at 4,664K memory usage comp:WinVista 64位家庭高级版,6GB ram AMD 4800+ X2程序在4,664K内存使用时崩溃

Source: 资源:

#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;
};

(Nevermind the username it's just an alias I use so I can keep track of all my posts with google) (不要管用户名,它只是我使用的别名,所以我可以通过Google跟踪我的所有帖子)

Stack overflow? 堆栈溢出? I see that check is recursive. 我看到check是递归的。

I'd put a guess on the fact that two.nxt isn't initialized. 我猜出two.nxt没有初始化的事实。 In C, primitive datatypes aren't initialized, meaning they have the value of whatever happened to be in whatever memory it's now occupying. 在C语言中,原始数据类型不会被初始化,这意味着它们具有现在正在占用的任何内存中发生的任何事情的值。 That means that more than likely, in main(), two.nxt = true, which causes check() to be run on an invalid pointer. 这意味着在main()中更可能是two.nxt = true,这将导致check()在无效指针上运行。 Try explicitly setting it to false and see if that works for you. 尝试将其显式设置为false,看看是否适合您。

[edit] If this is the issue, the more important initialization would be when you allocate the new num in check(). [edit]如果这是问题所在,则更重要的初始化是在check()中分配新的num时。

Sean is right, two.nxt is never initialised. 肖恩是正确的,two.nxt从未初始化。 In fact, num.nxt is never initialised for any instance of num. 实际上,从未为num的任何实例初始化num.nxt。 The member nxt is unnecessary if the class is made more robust. 如果使类更健壮,则成员nxt是不必要的。 The nxt pointer can be used instead: 可以使用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 << ", ";
        }
     }
};

Of course, the recursive nature is probably the main culprit, the initialisation issue was hidden as you were probably running a debug build. 当然,递归性质可能是主要的罪魁祸首,因为您可能正在运行调试版本,所以隐藏了初始化问题。 Converting the recursive form to the iterative form is left as an exercise. 练习是将递归形式转换为迭代形式。

Couple of problems I can see: 我可以看到几个问题:

  • You're allocating a bunch of nums, but you're not checking for a std::bad_alloc exception. 您正在分配一堆数字,但没有检查std :: bad_alloc异常。 You might simply be running out of memory... 您可能只是内存不足而已...
  • You're not checking anywhere if nxtnum is != 0, even though I think it's safe to do so as the only places where you dereference it are guarding. 即使我认为这样做是安全的,因为您取消引用nxtnum的唯一位置在保护,但您不会在任何地方检查nxtnum是否为!= 0。 Nevertheless, it's not that great a practise. 然而,这并不是一个很好的实践。
  • As Sean Edwards mentions, the num class doesn't have a constructor, so the members of a newly created num are filled with pretty much random junk. 正如肖恩·爱德华兹(Sean Edwards)所提到的那样,num类没有构造函数,因此新创建的num的成员中充满了几乎是随机的垃圾。 And that random junk might include nxt being set to a nonzero value. 而且该随机垃圾可能包括将nxt设置为非零值。 I'd add the following constructor to give it a set of safe defaults: 我将添加以下构造函数以为其提供一组安全的默认值:

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

  • You don't really need the boolean value, I'd just check for nxtnum being non-zero. 您实际上并不需要布尔值,我只是检查nxtnum是否为非零。

  • As Jeff Yates says, you might suffer from a stack overflow as the recursive function is getting nested too deep, but it doesn't look like it'll recurse that deep. 正如Jeff Yates所说的那样,由于递归函数嵌套太深,您可能会遭受堆栈溢出的困扰,但是看起来递归函数似乎并没有那么深。

Incidentally, if you're using a Microsoft compiler, int and long are the same size when targeting x64. 顺便说一句,如果您使用的是Microsoft编译器,则在定位x64时int和long的大小相同。 You also have an infinite loop in your main function, as 1 will always be <= 1000001. 您的主要功能中也有一个无限循环,因为1总是<= 1000001。

I've got it working, thank you Skizz 我已经开始运作了,谢谢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;
};

For Those Interested 对于那些有兴趣的人

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM