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

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

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

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

15.05.2012, 13:05. Просмотров 626. Ответов 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];
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.05.2012, 13:05
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Проблема с указателем на строку (C++):

Проблема с указателем на функцию - C++
Доброго времени суток, пишу приложение, которое реализует все функции АТД (двусвязный список). Есть стандартная библиотека, есть функция...

Проблема с указателем на элемент вектора - C++
Всем доброго времени суток. Не могу никак выкрутиться) Допустим, у нас есть класс "А" с параметрами: std::vector <TNode*> nodes; И...

В чем разница между указателем и указателем на указатель? - C++
int x, *p, *q; x=10; p=&x; q=p; cout<<*q; int x, *p, **q; x=10; p=&x; q=&p;

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

Переделать функцию c указателем на int, на функцию с указателем на void - C++
Есть рабочий код qsort для int: void qsort(int *base, int n) { // Прекратить если количество элементов меньше либо равно единице....

Перевернуть строку. В чем проблема? - C++
#include <iostream> using namespace std; void swapstr(char* str) { for(int i=0; i<strlen(str)/2-1;i++) { char...

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

Добавлено через 1 минуту
Вам каждый раз нужно будет при добавлении или удалении символов/подстроки пересоздавать таким образом массив.
1
Герц
524 / 341 / 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. Пока печатал, появилась куча новых сообщений.
Вам каждый раз нужно будет при добавлении или удалении символов/подстроки пересоздавать таким образом массив.
Все же стоит как-то заранее резервировать несколько лишних байт под символы, каждый раз пересоздавать массив и копировать - не лучший вариант.
1
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 Посмотреть сообщение
Вам каждый раз нужно будет при добавлении или удалении символов/подстроки пересоздавать таким образом массив.
Мм, поясните пожалуйста) Добавлении/удалении.. Попробовала добавить несколько символов, все в порядке. ^^
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 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; //освобождаем память, которая была выделена для старой строки
1
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, так как, мы что-то подобное сами должны реализовать. Как я понимаю) Нет ли другого способа копирования?
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.05.2012, 20:42
Привет! Вот еще темы с ответами:

Непоняток с указателем - C++
Объясните пожалуйста надпись. Вот простенький пример. include <iostream> using namespace std; int cubeV (int *n) { *n = *n *...

Работа с указателем - C++
#include <ntddk.h> NTSTATUS PsLookupProcessByProcessId(__in HANDLE ProcessId, __out PEPROCESS *Process); static VOID...

Работа с указателем - C++
Есть такой указатель: char *s="n1=1&n2=2&name=test&sername=test2"; Нужно выделить с этой стоки значение name, то есть "test" и...

Массив с указателем - C++
при формировании выходной строки каждый символ должен дублироваться. Например дана abc, а при выходе aabbcc/ Все это должно быть...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
16.05.2012, 20:42
Ответ Создать тему
Опции темы

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