Неизвестный сбой в упражнении с указателями памяти C ++ - PullRequest
0 голосов
/ 16 января 2009

Я недавно написал программу, которая поможет мне понять основы указателей памяти в C ++, я выбрал простой искатель простых чисел.

Я наконец получил его на работу. (ура за отладку!)

И я позволил ему бегать, чтобы посмотреть, как далеко он заходит, он добирается до пика. # 815389 с моим подробным сообщением, что это 65076-е простое число, я получаю сбой приложения. Единственное, о чем я мог думать, - это переполнение моих входных данных, поэтому я изменил их на длинные, они застряли в одном месте.

Может ли кто-нибудь помочь объяснить, какое ограничение вызывает это?

комп: WinVista 64-bit Home Premium, 6 ГБ оперативной памяти AMD 4800+ X2 сбой программы при использовании памяти в 4664 КБ

Источник:

#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)

Ответы [ 6 ]

7 голосов
/ 16 января 2009

переполнение стека? Я вижу, что check рекурсивно.

4 голосов
/ 16 января 2009

Я бы предположил, что two.nxt не инициализирован. В C примитивные типы данных не инициализируются, то есть они имеют значение того, что было в той памяти, которую он сейчас занимает. Это означает, что в main () более чем вероятно два.nxt = true, что приводит к запуску check () для недопустимого указателя. Попробуйте явно установить для него значение false и посмотрите, подходит ли вам это.

[править] Если это проблема, более важная инициализация будет при назначении нового числа в check ().

2 голосов
/ 16 января 2009

Шон прав, 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 << ", ";
        }
     }
};

Конечно, рекурсивный характер, вероятно, является основным виновником, проблема инициализации была скрыта, поскольку вы, вероятно, выполняли отладочную сборку. Преобразование рекурсивной формы в итеративную форму оставлено в качестве упражнения.

1 голос
/ 16 января 2009

Пара проблем, которые я вижу:

  • Вы выделяете кучу чисел, но не проверяете исключение std :: bad_alloc. Возможно, вам просто не хватает памяти ...
  • Вы нигде не проверяете, равен ли nxtnum! = 0, хотя я думаю, что это безопасно, поскольку единственные места, где вы обращаетесь к нему, охраняют. Тем не менее, это не очень хорошая практика.
  • Как упоминает Шон Эдвардс, у класса num нет конструктора, поэтому члены вновь созданного num заполнены почти случайным мусором. И этот случайный мусор может включать nxt, установленный в ненулевое значение. Я бы добавил следующий конструктор, чтобы задать ему набор безопасных значений по умолчанию:

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

  • Вам действительно не нужно логическое значение, я бы просто проверил, что nxtnum не равен нулю.

  • Как говорит Джефф Йейтс, вы можете страдать от переполнения стека, поскольку рекурсивная функция становится слишком глубокой, но не похоже, что она будет такой глубиной .
0 голосов
/ 16 января 2009

У меня это работает, спасибо 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;
};

Для тех, кто заинтересован

0 голосов
/ 16 января 2009

Кстати, если вы используете компилятор Microsoft, int и long имеют одинаковый размер при таргетинге на x64. У вас также есть бесконечный цикл в вашей основной функции, так как 1 всегда будет <= 1000001. </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...