В моем классе у меня есть, среди прочего, указатель:
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 здесь, и мне не разрешено использовать его.
Вы должны дать 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
и компилятор выполняет эту работу за вас.
delete
должно появиться в деструкторе, не так ли? Я полагаю, что это может быть и в других случаях; до тех пор, пока указатель ( Pin
) установлен в нуль после освобождения памяти, это не вызовет никаких проблем.
Вам нужно выделить блок памяти для хранения "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;
}
Вместо того, чтобы использовать кучу (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;
}
const int
будет лучше, чем определение препроцессора, учитывая отсутствие области видимости с последним. Вы оставили место для NUL (то есть \0
а не /0
), но не добавили его в setDefaultValue()
.
Pin
указывал на массивchar
вы можете писать. Кстати, это не имеет абсолютно никакого отношения к ООП.