2014-09-17 3 views
0

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

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

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

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

Теперь я хочу, чтобы установить значение по умолчанию («1234») на мой PIN-код. Я пробовал очень простой способ:

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++/OOP, и иногда я все еще запутался указателями.

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

+4

Вам нужно сделать 'Pin' точку массив 'char', на который вы можете написать. Кстати, это не имеет ничего общего с ООП. – juanchopanza

+1

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

+2

Почему вы не используете 'std :: string' или' boost :: optional ', если вам нужно отличить строку от пустой строки? В любом случае ... если вы хотите использовать указатель, вам нужно указать его на некоторый массив символов 'new'-ed - или, возможно, класс-член класса, - прежде чем пытаться перезаписать его. –

ответ

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

Как вы выделили dynamicaly блок памяти, вы всегда должны освободить его, когда он не нужен больше. Чтобы сделать это, вы должны добавить деструктор в класс:

GSM::~GSM() 
{ 
    delete [] Pin; 
} 
+0

почему i + 1? i уже увеличивается – sajas

+0

Потому что он хочет «1234», а не «0123». Вы также можете изменить цикл for для достижения того же. – GHugo

+1

Вы должны добавить примечание о том, что класс теперь требует деструктора. Также может быть лучше выделить дополнительный символ, чтобы строка была завершена с нулевым символом, а затем null прекратить ее. –

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; где-то тоже (как правило, в деструкторе класса, но в зависимости от того, как он используется, он может понадобиться в других местах, таких как оператор присваивания, и вы должны также напишите копию-конструктор, см. Rule Of Three).

В правильной 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 для рекомендации 'std :: string'. – utnapistim

0

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

Вместо того, чтобы использовать кучу (newdelete) просто выделить место в своем классе на четыре символа штифт:

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 Спасибо, я обновил свой ответ. – Baldrickk