Работа с доступом к нулевому указателю

0

В моем классе у меня есть, среди прочего, указатель:

Class GSM
{
//...
private:
    char *Pin;
//...
}

Мой конструктор инициализирует его как:

GSM::GSM()
{
//...
    Pin = NULL; 
//...
}

Теперь я хочу установить значение по умолчанию ("1234") для моего ПИН-кода. Я пробовал очень простой способ:

bool GSM::setDefaultValue()
{
    lock();
    Pin = "0";
    for (uint8 i =0; i < 4; ++i)
    {
        Pin[i] = i+1;
    }
    unlock();
    return true;
}

Но это не сработало. Когда я запускаю свою программу (я использую Visual Studio 2010), возникает ошибка:

Access violation writing location 0x005011d8

Я попытался удалить строку

Pin = "0";

Но это не помогло. Я должен инициализировать его как NULL в конструкторе. Это часть более крупного проекта, но я думаю, что код выше, что заставляет меня беспокоиться. Я все еще довольно новичок в C++/ООП, и иногда меня все еще путают указатели.

Что я должен сделать, чтобы улучшить свой код и то, как я думаю?
EDIT: по запросу я должен добавить, что я не могу использовать std :: string. Я стажер в компании, проект довольно большой (например, тысячи файлов), и я не видел никакого std здесь, и мне не разрешено использовать его.

  • 4
    Вам нужно сделать так, чтобы Pin указывал на массив char вы можете писать. Кстати, это не имеет абсолютно никакого отношения к ООП.
  • 1
    Почему вы игнорируете предупреждения вашего компилятора и переходите прямо к переполнению стека? Существует множество автоматических средств диагностики, которые могут помочь вам, не требуя внимания человека.
Показать ещё 4 комментария
Теги:
pointers
oop
nullpointerexception
null

3 ответа

4

Вы должны дать Pin память. Что-то вроде этого:

Pin = new char[5];  // To make space for terminating '\0';
for(...)
{
   Pin[i] = '0' + i + 1;
}
Pin[4] = '\0';      // End of the string so we can use it as a string.

...

Затем вы должны использовать delete [] Pin; где-то тоже (как правило, в деструкторе класса, но в зависимости от того, как он используется, он может понадобиться в другом месте, например, оператор присваивания, и вам также нужно написать конструктор-копию, см. правило три).

В правильном C++ вы должны использовать std::string вместо этого, и тогда вы можете:

Class GSM
{
//...
private:
    std::string Pin;
....

Pin = "0000";
for (uint8 i =0; i < 4; ++i)
{
    Pin[i] += i+1;
}

Использование std::string позволяет избежать большинства проблем выделения/освобождения памяти и "просто работает" при копировании, назначении или уничтожении класса, поскольку реализация std::string и компилятор выполняет эту работу за вас.

  • 0
    delete должно появиться в деструкторе, не так ли? Я полагаю, что это может быть и в других случаях; до тех пор, пока указатель ( Pin ) установлен в нуль после освобождения памяти, это не вызовет никаких проблем.
  • 0
    @JonathanLeffler: обновлено.
Показать ещё 1 комментарий
1

Вам нужно выделить блок памяти для хранения "1234". Этот блок памяти будет указываться указателем Pin. Можешь попробовать:

bool GSM::setDefaultValue()
{
    lock();
    Pin = new char[4];
    for (uint8 i =0; i < 4; ++i)
    {
        Pin[i] = '0' + (i + 1);
    }
    unlock();
    return true;
}

Поскольку вы выделили динамический блок памяти, вы всегда должны выпускать его, когда вам это больше не нужно. Для этого вы должны добавить деструктор в свой класс:

GSM::~GSM()
{
    delete [] Pin;
}
  • 0
    почему я + 1? я уже увеличен
  • 0
    Потому что он хочет «1234», а не «0123». Вы также можете изменить цикл for для достижения того же.
Показать ещё 6 комментариев
0

Простой ответ:

Вместо того, чтобы использовать кучу (new delete), просто выделите место в своем классе для четырехзначного вывода:

Class GSM
{
//...
private:
    char Pin[5];
//...
}

Длина фиксируется в 5 (чтобы разрешить пробел для 4 символов и завершение null ('\0'), но до тех пор, пока вам нужно хранить максимум 4 символа, вы в порядке.

Конечно, если вы хотите, чтобы это было легко изменить в будущем:

Class GSM
{
//...
private:
    const int pin_length = 4;
    char Pin[pin_length+1];
//...
}

Ваша функция для установки значения будет выглядеть так:

bool GSM::setDefaultValue()
{
    lock();
    for (char i = 0; i < pin_length; ++i)
    {
        Pin[i] = i+1;
    }
    Pin[pin_length]=0;
    unlock();
    return true;
}

или даже:

bool GSM::setDefaultValue()
{
    lock();
    strcpy(Pin,"1234");  //though you would have to change this if the pin-length changes.
    unlock();
    return true;
}
  • 0
    const int будет лучше, чем определение препроцессора, учитывая отсутствие области видимости с последним. Вы оставили место для NUL (то есть \0 а не /0 ), но не добавили его в setDefaultValue() .
  • 0
    @TonyD Спасибо, я обновил свой ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню