Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
#1

Проблема с указателем на строку - C++

15.05.2012, 13:05. Просмотров 588. Ответов 17
Метки нет (Все метки)

Пишу класс Строка на Visual Studio. Проблема с функцией-оператором + ( Он у меня только на добавление символа, так как мне большего на данный момент и не надо, так что не ругайтесь)
При попытке записать в конец строки символ выдает ошибку о "Нарушении прав доступа при записи".
Не ругайтесь, что у меня нет конструктора и длина не вычисляется)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class String
{
private:
    char* FirstSymbol;
    int LengthString;
public:
    int GetLengthString() { return LengthString; };
    void String::operator+(char Add);
    int ComparisonString();
    int DeleteSymbol();
    int PrintString();
    void InputString(char*);
};
//!!!! Та самая функция!
void String::operator+(char Add)
{
    char* Symbol=FirstSymbol;
    while (*Symbol!=0)
    {
        Symbol++;
    }
    *(Symbol)=Add; //!!!!!!!!!!! вот он, камень преткновения)
    Symbol++;
    *Symbol=0;
}
 
void String::InputString(char* Add)
{
    FirstSymbol=Add;
}
Чуть не забыла..
C++
1
2
3
class String Cl1;
Cl1.InputString("ClassMyFirst");
Cl1+Symbols[0];
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.05.2012, 13:05     Проблема с указателем на строку
Посмотрите здесь:

C++ функция с указателем
C++ Работа с указателем.
C++ Калькулятор с указателем
C++ Цикл с указателем
Перевернуть строку. В чем проблема? C++
C++ Работа с указателем
C++ функция с указателем
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
15.05.2012, 14:04     Проблема с указателем на строку #2
В данном случае принято перегружать +=.
Далее по коду:
C++
1
while ( Symbol != 0 )
или
C++
1
while (*Symbol != '\0' )
И тут:
C++
1
*Symbol = '\0';
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
15.05.2012, 14:09  [ТС]     Проблема с указателем на строку #3
Цитата Сообщение от Toshkarik Посмотреть сообщение
В данном случае принято перегружать +=.
Ну, принято да) Я по старинке (по паскалевски), мне так понятнее.
Цитата Сообщение от Toshkarik Посмотреть сообщение
Далее по коду:
C++
1
while ( Symbol != 0 )
или
C++
1
while (*Symbol != '\0' )
И тут:
C++
1
*Symbol = '\0';
Нет, цикл он проходит верно. Я ставила счетчик. 12 символов, как и положено. И выходит из него. В варианте первом, как у Вас, он зацикливается. Я же смотрю на значение по адресу, конец строки -0 записывается по адресу. А не адрес конца строки меняется на 0.
vetal10
35 / 35 / 5
Регистрация: 25.05.2010
Сообщений: 211
15.05.2012, 14:13     Проблема с указателем на строку #4
Проблема в том что ты пытаешься редактировать строковую константу!
Если хочешь что бы у тебя работала , то тебе следует копировать передаваемую строку ну и тогда ты сможешь ее редактировать.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
15.05.2012, 14:14     Проблема с указателем на строку #5
С первым циклом поспешил, спать нужно ложится. В данном случае все верно, Вы не используете динамическую память. Вы присваиваете своему указателю адрес константного строкового литерала. В методе InputString попробуйте так:
void String::InputString(char* Add)
{
FirstSymbol= new char [ strlen( Add ) + 1 ];
strcpy( FirstSymbol, Add );
}
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
15.05.2012, 14:15  [ТС]     Проблема с указателем на строку #6
Цитата Сообщение от vetal10 Посмотреть сообщение
Проблема в том что ты пытаешься редактировать строковую константу!
Если хочешь что бы у тебя работала , то тебе следует копировать передаваемую строку ну и тогда ты сможешь ее редактировать.
Я изменяю только указатель, который создала сама. И больше ничего.
vetal10
35 / 35 / 5
Регистрация: 25.05.2010
Сообщений: 211
15.05.2012, 14:17     Проблема с указателем на строку #7
Ну или передавай массивы.

Добавлено через 2 минуты
Ты изменяешь указатель который указывает на константу.
Вот делай так
C++
1
2
3
4
5
 class String Cl1;
    char s[30]="ClassMyFirst";
    Cl1.InputString(s);
    Cl1+'a';
    Cl1.PrintString();
и все будет работать.
Предварительно реализуй принт)
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
15.05.2012, 14:21  [ТС]     Проблема с указателем на строку #8
Цитата Сообщение от Toshkarik Посмотреть сообщение
С первым циклом поспешил, спать нужно ложится. В данном случае все верно, Вы не используете динамическую память. Вы присваиваете своему указателю адрес константного строкового литерала.
А это плохо?) То есть поле класса у меня в данном случае константа и я, что, не могу его использовать?)

Добавлено через 3 минуты
Цитата Сообщение от vetal10 Посмотреть сообщение
Ну или передавай массивы.

Добавлено через 2 минуты
Ты изменяешь указатель который указывает на константу.
Вот делай так
C++
1
2
3
4
5
 class String Cl1;
    char s[30]="ClassMyFirst";
    Cl1.InputString(s);
    Cl1+'a';
    Cl1.PrintString();
и все будет работать.
Предварительно реализуй принт)
Print у меня реализован, я его просто за ненадобностью не кидала. Вот теперь я поняла, что Вы хотели сказать, и почему иначе нельзя..не хочется через массив строки писать совсем, но я поняла. Спасибо.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
15.05.2012, 14:24     Проблема с указателем на строку #9
Цитата Сообщение от vetal10 Посмотреть сообщение
class String Cl1;
* * char s[30]="ClassMyFirst";
* * Cl1.InputString(s);
* * Cl1+'a';
* * Cl1.PrintString();
И что же это получится? Что указатель объекта класса будет указывать на внешний массив? Смысл тогда в этом классе? У Вас изначально не правильно сложилось представление о динамических данных.

Вообще такие вещи в конструкторе делаются, или в операторе присваивания.
Так же придется еще и в Вашем операторе + сделать:
C++
1
2
3
4
5
void String::InputString(char* Add)
{
   FirstSymbol= new char [ strlen( Add ) + 1 ];
   strcpy( FirstSymbol, Add );
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void String::operator+(char Add)
{
    char* temp = FirstSymbol;
 
    FirstSymbol = new char [ strlen( temp ) + 2 ];
 
    strcpy( FirstSymbol, temp );
 
    char *end = FirstSymbol;
 
    while (  *end != '\0' )
       end++;
    *end = Add;
    *( end + 1 ) = '\0';
 
   delete [] temp;
}
Или создавайте заведомо большой статический массив в классе, в чем опять же нет смысла.
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
15.05.2012, 14:29  [ТС]     Проблема с указателем на строку #10
Toshkarik, Отлично, получилось) Только у меня вопрос, почему мы выделяем область памяти +1, еще один символ - для нуля?
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
15.05.2012, 14:31     Проблема с указателем на строку #11
Цитата Сообщение от Sweet_Sleep Посмотреть сообщение
еще один символ - для нуля?
Именно так. strlen возвращает размер строки без учета ноль-символа.

Добавлено через 1 минуту
Вам каждый раз нужно будет при добавлении или удалении символов/подстроки пересоздавать таким образом массив.
Герц
523 / 340 / 4
Регистрация: 05.11.2010
Сообщений: 1,077
Записей в блоге: 1
15.05.2012, 14:32     Проблема с указателем на строку #12
Toshkarik, не осилил, что ты написал.
Не вижу здесь никакого выделения памяти под char* FirstSymbol, но очевидно, что выделяется ровно столько, символов, сколько нужно для хранения строки, переданной в InputString. Таким образом, вы пытаетесь добавить +1 символ к строке, не выделяя под него место, выходите за границы символьного массива, нарушаете права доступа.
Несколько советов:
1. Это не функции, это методы, в крайнем случае - функции-члены.
2. Давайте полям класса префиксы для быстрой идентификации в коде, то есть не FirstSymbol, а например m_firstSymbol (m от Method).
3. В том стиле именования, которого Вы, видимо, хотели придерживаться, принято давать классам имена, начинающиеся с заглавной буквы и в верблюжьем стиле, String в данном случае верно название. А вот методам и полям класса - с прописной буквы, тоже в верблюжьем стиле: не GetLengthString, а getLengthString.
P.S. Пока печатал, появилась куча новых сообщений.
Вам каждый раз нужно будет при добавлении или удалении символов/подстроки пересоздавать таким образом массив.
Все же стоит как-то заранее резервировать несколько лишних байт под символы, каждый раз пересоздавать массив и копировать - не лучший вариант.
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
15.05.2012, 14:42  [ТС]     Проблема с указателем на строку #13
Цитата Сообщение от Герц Посмотреть сообщение
Toshkarik, не осилил, что ты написал.
Не вижу здесь никакого выделения памяти под char* FirstSymbol, но очевидно, что выделяется ровно столько, символов, сколько нужно для хранения строки, переданной в InputString. Таким образом, вы пытаетесь добавить +1 символ к строке, не выделяя под него место, выходите за границы символьного массива, нарушаете права доступа.
Несколько советов:
1. Это не функции, это методы, в крайнем случае - функции-члены.
2. Давайте полям класса префиксы для быстрой идентификации в коде, то есть не FirstSymbol, а например m_firstSymbol (m от Method).
3. В том стиле именования, которого Вы, видимо, хотели придерживаться, принято давать классам имена, начинающиеся с заглавной буквы и в верблюжьем стиле, String в данном случае верно название. А вот методам и полям класса - с прописной буквы, тоже в верблюжьем стиле: не GetLengthString, а getLengthString.
Свою ошибку я поняла. Поступила, как мне советовал Toshkarik.
За советы спасибо. Буду исправляться.

Добавлено через 5 минут
Цитата Сообщение от Toshkarik Посмотреть сообщение
Вам каждый раз нужно будет при добавлении или удалении символов/подстроки пересоздавать таким образом массив.
Мм, поясните пожалуйста) Добавлении/удалении.. Попробовала добавить несколько символов, все в порядке. ^^
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
15.05.2012, 22:41     Проблема с указателем на строку #14
Цитата Сообщение от Sweet_Sleep Посмотреть сообщение
Мм, поясните пожалуйста) Добавлении/удалении.. Попробовала добавить несколько символов, все в порядке.
У Вас есть некая строка, допустим Вы ее инициализировали в конструкторе при создании объекта.
Конструктор примерно должен выглядеть так:
C++
1
2
3
4
String::String( const char *str )
   : stringLength( strlen( str )), FirstSymbol( new char [ stringLength + 1 ]) {
      strcpy( FirstSymbol, str );
}
Само создание объекта:
C++
1
String someString( "This is string" );
Очевидно, что мы выделили память лишь под "This is string". Если вы хотите добавить какой то новый символ в конец строки или присоединить другую строку, то, опять же, очевидно, что нужно выделить память для нового символа/присоединяемой строки. Все примерно выглядит так:
C++
1
2
3
4
char *temp = FirstSymbol; //Создаем в перегружаемом операторе временный указатель и присваиваем ему значение указателя нашей строки
stringLength + strlen( addString ); // увеличиваем переменную содержащую размер нашей строки на 1 если это символ или на strlen( addString ) если присоединяем строку.
FirstSymbol = new char [ stringLength + 1 ]; //выделяем новую память размер которой равен размеру предыдущей строке + размер символа/присоединяемой строки
strcpy( FirstSymbol, temp ); //копируем исходную строку в новый массив
если нам нужно присоединить лишь символ
C++
1
2
*( FirstSymbol + stringLength - 1 ) = addSymbol;
*( FirstSymbol + stringLength ) = '\0';
если же нужно добавить строку
C++
1
strcpy( FirstSymbol + strlen( temp ), addString ); //FirstSymbol + strlen( temp ) тут служит указателем на конец старой строки в только что выделенной памяти.
Теперь осталось освободить память, которую мы выделяли на исходную строку
C++
1
delete [] temp; //освобождаем память, которая была выделена для старой строки
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
16.05.2012, 20:42  [ТС]     Проблема с указателем на строку #15
Спасибо за столь подробные объяснения) Есть несколько замечаний/вопросов.
Цитата Сообщение от Toshkarik Посмотреть сообщение
C++
1
2
3
4
String::String( const char *str )
   : stringLength( strlen( str )), FirstSymbol( new char [ stringLength + 1 ]) {
      strcpy( FirstSymbol, str );
}
Это я понимаю, что должно быть в конструкторе) Я просто делала наспех. Как в голову взбредет...
Цитата Сообщение от Toshkarik Посмотреть сообщение
Само создание объекта:
C++
1
2
3
4
char *temp = FirstSymbol; //Создаем в перегружаемом операторе временный указатель и присваиваем ему значение указателя нашей строки
stringLength + strlen( addString ); // увеличиваем переменную содержащую размер нашей строки на 1 если это символ или на strlen( addString ) если присоединяем строку.
FirstSymbol = new char [ stringLength + 1 ]; //выделяем новую память размер которой равен размеру предыдущей строке + размер символа/присоединяемой строки
strcpy( FirstSymbol, temp ); //копируем исходную строку в новый массив
Зачем нам при выделении памяти указатель temp? Может быть Вы имели в виду, что
C++
1
Temp=new char[StringLength+1]
(А не FirstSymbol=..)
И еще...Странно использовать функции из string.h, так как, мы что-то подобное сами должны реализовать. Как я понимаю) Нет ли другого способа копирования?
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.05.2012, 21:47     Проблема с указателем на строку #16
Цитата Сообщение от Sweet_Sleep Посмотреть сообщение
Зачем нам при выделении памяти указатель temp?
Указатель temp указывает на старую строку, то есть в данном случае он будет указывать на строку "This is string". А нашему указателю, который является элемент-данными класса, мы присваиваем новую выделенную память для хранения новой строки, после чего копируем из старой строки на которую указывает temp, в новую, на которую уже указывает наш указатель класса. После чего мы в новую строку дописываем прибавляемый символ или строку. А старую удаляем, командой delete [] temp;
Цитата Сообщение от Sweet_Sleep Посмотреть сообщение
Странно использовать функции из string.h
Ничего странного, данные функции более низкоуровневы, класс же String более удобен ( по замыслу ). Но вы можете копировать и в ручную, если от Вас требуют.
C++
1
2
for ( char *s1 = FirstSymbol, *s2 = temp; *s1 = *s2; s1++, s2++ )
   ;
Sweet_Sleep
10 / 10 / 0
Регистрация: 04.11.2009
Сообщений: 147
16.05.2012, 21:53  [ТС]     Проблема с указателем на строку #17
Toshkarik, Нет, от меня ничего не требуют) Для моей задачи хватило и вчерашней Вашей помощи, когда все-таки работало без постоянного перевыделения памяти)
Спасибо, что объяснили) Кажется понятно... Мне всё равно довольно сложна эта работа с указателями, я возьмусь (обязательно) за книжку. А то пишу всё равно на паскале=)
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.05.2012, 22:46     Проблема с указателем на строку
Еще ссылки по теме:

Функция с указателем и индексом(Удаляет в строке лидирующие пробелы. Возвращает указатель на преобразованную строку.) C++
C++ Проблема с указателем на функцию
Непоняток с указателем C++
C++ Проблема с указателем на элемент вектора
Работа с указателем C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.05.2012, 22:46     Проблема с указателем на строку #18
Цитата Сообщение от Sweet_Sleep Посмотреть сообщение
работало без постоянного перевыделения памяти
Без перевыделения памяти никак не обойтись в любом случае. Вы скорей всего записываете данные за пределы массива. Последствия непредсказуемы в данном случае.
Yandex
Объявления
16.05.2012, 22:46     Проблема с указателем на строку
Ответ Создать тему
Опции темы

Текущее время: 07:50. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru