Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Класс для работы со строками. 
:(
    Опции темы
Mal Hack
Дата 14.5.2006, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 2
Всего: 261



Задание написать класс вот такой:
Код
class String
{
//    private:

    public:
        int       Len;
        char * Str;
        String( void );
        String( char ch );
        String( char * s );
        String( char & s );

        char & operator [] ( int index );
        String & operator =  ( String & s );
        String & operator += ( String & s );
        String & operator +  ( String & s );
        // operator char * ();

        bool operator == ( String & s );
        bool operator <= ( String & s );
        bool operator >= ( String & s );
        bool operator <  ( String & s );
        bool operator >  ( String & s );

        char * GetString( void );
        int GetLength( void );
        String SubString( int StartIndex );
        String SubString( int StartIndex , int Length );
        int IndexOf( String & s );

        ~String();
};


Вот что есть:
Код
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>

class String
{
//    private:

    public:
        int       Len;
        char * Str;
        String( void );
        String( char ch );
        String( char * s );
        String( char & s );

        char & operator [] ( int index );
        String & operator =  ( String & s );
        String & operator += ( String & s );
        String & operator +  ( String & s );
        // operator char * ();

        bool operator == ( String & s );
        bool operator <= ( String & s );
        bool operator >= ( String & s );
        bool operator <  ( String & s );
        bool operator >  ( String & s );

        char * GetString( void );
        int GetLength( void );
        String SubString( int StartIndex );
        String SubString( int StartIndex , int Length );
        int IndexOf( String & s );

        ~String();
};

String::String( void )
{
    this -> Str = "";
    this -> Len = 0;
}

String::String( char ch )
{
    this -> Str = ( char * )ch;
    this -> Len = 1;
}

String::String( char * s )
{
    this -> Str = ( char * ) s;
    this -> Len = this -> GetLength();
}

String::String( char & s )
{
    this -> Str = & s;
    this -> Len = this -> GetLength();
}

int String::GetLength( void )
{
    return strlen( this -> Str );
}

char * String::GetString( void )
{
    return this -> Str;
}

bool String :: operator == ( String & s )
{
    return ( this -> Str == s.Str ) ? true : false;
}

bool String :: operator >= ( String & s )
{
    return ( this -> Str >= s.Str ) ? true : false;
}

bool String :: operator <= ( String & s )
{
    return ( this -> Str <= s.Str ) ? true : false;
}

bool String :: operator > ( String & s )
{
    return ( this -> Str > s.Str ) ? true : false;
}

bool String :: operator < ( String & s )
{
    return ( this -> Str < s.Str ) ? true : false;
}

String String::SubString( int StartIndex )
{
    String * s = new String( this -> GetString() );
    
    int i;

    this  -> Str = "";

    for( i = StartIndex ; i < s -> Len ; i++ )
    {
        this -> Str += s -> Str[ i ];
    }

    this -> Len = this -> GetLength();

    return * this;
}

String String::SubString( int StartIndex , int Length )
{
    int i;

    for( i = StartIndex ; i < Length ; i++ )
    {
        this -> Str[ i - StartIndex ] = this -> Str[ i ];
    }

    this -> Str[  this -> Len - StartIndex ] = '\0';
    this -> Len = this -> GetLength();

    return * this;
}

int String::IndexOf( String & s )
{
    return 0;
}

char & String::operator [] ( int index )
{
    if( index < 0 || index > this -> Len )
    {
        printf( "Неверный индекс i = %d" , index );
        exit( 0 );
    }

    return this -> Str[ index ];
}
/*
String::operator char * ()
{
    return this -> Str;
}
*/

String & String::operator + ( String & s )
{
    int i;

    for( i = 0 ; i < this -> Len ; i++ )
    {    s . Str[ i + s . Len ] = this -> Str[ i ];    }

    s . Len += this -> Len;

    return s;
}

String & String::operator += ( String & s )
{
    int i;

    String * st = new String( s . Str );

    for( i = 0 ; i < this -> Len ; i++ )
    {    s . Str[ i ] = this -> Str[ i ];    }

    for( i = 0 ; i < st -> Len ; i++ )
    {    s . Str[ i + this -> Len ] = st -> Str[ i ];    }

    s . Len += this -> Len;

    return s;
}

String & String::operator = ( String & s )
{
    s . Str = this -> Str;
    s . Len = this -> Len;

    return s;
}

String::~String()
{
    delete [] Str;
}

void main()
{
    String * Str1 , * Str2 , * Str3;

    Str1 = new String( "123456789" );
    Str2 = new String( "abcdefghi" );
    Str3 = new String();

    Str1 +=  Str2;

    printf( "Str1 = %s\nStr2 = %s\nStr3 = %s\n\n" , Str1 -> GetString() , Str2 -> GetString() , Str3 -> GetString() );

    //Str1 -> SubString( 5 );
    //Str2 -> SubString( 1 , 5 );

    //printf( "Str1 SubString( 5 ) = %s\nStr2 SubString( 1 , 5 ) = %s\n" , Str2 -> GetString() , Str3 -> GetString() );

    getch();
    exit(0);

    //Str3 += (char & ) "12345";

    //printf( "Str3 += 12345 = %s\n" , Str3 -> GetString() );

    //Str2 = Str2 + ( char * ) ( ( char & ) "12345" );

    //printf( "Str3 += 12345 = %s\n" , Str3 -> GetString() );

    getch();
}


Видимо я, ввиду того, что впервые с VS.NET работаю и с С++ на таком уровне, не могу понять как грамтно сделать перегрузку. Т.е. идет несоответствие типов. Начиная с +=, + и SubString.
Выдает: Access Violation или 
1> error C2297: '+=' : illegal, right operand has type 'String *'
1> error C2114: '+=' : pointer on left; needs integral value on right
На строке 
    Str1 +=  Str2;

Как правильно сделать? Вроде бы с примерами из книжки Поплавской совпадает... 
PM ICQ   Вверх
chipset
Дата 14.5.2006, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4071
Регистрация: 11.1.2003
Где: Seattle, US

Репутация: 27
Всего: 164



Цитата(Mal Hack @  14.5.2006,  07:43 Найти цитируемый пост)
1> error C2297: '+=' : illegal, right operand has type 'String *'
1> error C2114: '+=' : pointer on left; needs integral value on right
На строке 
    Str1 +=  Str2;

Прибавляешь указатель к указателю. Нужно так: (*Str1) += (*Str2) либо как-нибудь вот так
Str1->operator +=(*Str2);   


--------------------
Цитата(Jimi Hendrix)
Well, I stand up next to a mountain
And I chop it down with the edge of my hand
PM MAIL WWW   Вверх
Mal Hack
Дата 14.5.2006, 18:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 2
Всего: 261



ВОт функция перегрузки оператора +=
Код
String & String::operator += ( String & s )
{
    int i;

    String * st = new String( s . Str );

    //printf("%s" , s[5] );
    //getch();
    for( i = 1 ; i < this->Len ; i++ )
    {    
        //s.Str[ i ] = this[ i ];     <<<<<<<<<<<<<<<<<<<
        printf( "%s\n", s . Str[ i ] );
        getch();
    }
    for( i = 0 ; i < st -> Len ; i++ )
    {    s . Str[ i + this -> Len ] = st -> Str[ i ];    }

    s . Len += this -> Len;

    return s;
}

В помеченной строчке возникает ошибка при запуске:
Код
Unhandled exception at 0x10227c2f (msvcr80d.dll) in String.exe: 0xC0000005: Access violation reading location 0x00000066.

При этом, символы, если обращаться как  s[5] или this[i] читаются.
Но записать я не могу. В чем я ошибаюсь? 
PM ICQ   Вверх
bsa
Дата 14.5.2006, 21:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Ты неправильно определяещь этот метод, надо:
Код
String & String::operator += ( const String & s )

Таким образом ты не имеешь права менять переменную справа от оператора. Не забывай, что String & s  и String s - это разные вещи.
Этот метод я бы реализовал так:
Код
String& String::operator += (const String & s ) {
     Str = (char*) realloc( Str, s.Len + Len);
     memcpy(Str + Len, s.Str, s.Len);
     Len += s.Len;
     return *this;
}
  

Это сообщение отредактировал(а) bsa - 14.5.2006, 21:11
PM   Вверх
Joss
Дата 14.5.2006, 21:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 103
Регистрация: 19.3.2006

Репутация: 1
Всего: 1



А почему модифицируется s? Ведь S1 += S2 - сокращенная запись S1 = S1 + S2.  А вообще лучше написать так:

Код

String & String::operator += ( const String & s )
{
    *this = *this + s;
    return *this;
}


При этом дотжны быть перегружены операции = и +.

А ошибка, на мой взгляд, вот почему: в выделеной строке индексируется указатель на String. Его сначала нужно разыменовать:
Код

  (*this)[i]         //может так?


Кстати обращаться через this не обязательно. Можно просто Str[i]. 
PM MAIL   Вверх
Mal Hack
Дата 14.5.2006, 21:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 2
Всего: 261



bsa, вся проблема в том, что сделать надо жестко по заданию... Хотя я уже давно понял, что оно - корявое. 
PM ICQ   Вверх
MAKCim
Дата 14.5.2006, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



Код

String& operator+(String& s)

не верен семантически
лучше operator+ (-,...) реализовывать через operator+= (-=,...)
и делать friend-ом если невозможно работать через интерфейс
+лучше параметры передавать по const-ссылке

Добавлено @ 21:23 
Joss опередил 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
bsa
Дата 14.5.2006, 21:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Mal Hack, у тебя в задании реализация записана?!? Это вряд ли. Если же ты про const, то можно его опустить, но ты должен иметь в виду, что += в данном контексте не должна менять свой параметр. А ты пытался его поменять, тем более, что переменная цикла i у тебя шла по диапазону допустимому для this, но не для s.
И вообще, зачем так мудрить? Алгоритм сложный, перегруженый. А работы всего на 4 строчки: выделить дополнительную память, скопировать добавляемую строку в конец, увеличить размер текущей строки, вернуть ссылку на себя. 
PM   Вверх
bel_nikita
Дата 14.5.2006, 22:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Эксперт
Сообщений: 2304
Регистрация: 12.10.2003
Где: Поезд №21/22 ( ст . Прага )

Репутация: 21
Всего: 47



Mal Hack,
может на реализацию MFC CString взгляни ( ...\MFC\SRC\STRCORE.CPP ).
и вместо for(i=...) старайся memcpy использовать 


--------------------
user posted image — регистрация доменов от 150 руб.
PM MAIL WWW ICQ   Вверх
MAKCim
Дата 15.5.2006, 07:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



Цитата

может на реализацию MFC CString взгляни

или std::string  smile  


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
UnrealMan
Дата 15.5.2006, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Ужас-то какой... Констукторы написаны неправильно, операторы сравнения тоже. Тут вам и утечки памяти и удаление несуществующей... Короче, полный комплект. Наверно, проще не исправлять здешние ошибки, а написать заново весь класс. 
PM MAIL   Вверх
UnrealMan
Дата 16.5.2006, 09:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Код
class String
{
    char *pData; // данные строки
    int len; // длина строки
    int size; // Размер памяти, выделенной под строку.
    // можно было б обойтись len, но тогда работать всё это будет медленно

    char *Allocator();
    char *Allocator(int);
    void Deallocator();

public:
    String();
    String(const String &s);
    String(const char *s);
    String(char ch);

    ~String();

    char &operator [](int index);
    char &operator *();

    String &operator =(const String &s);
    String &operator +=(const String &s);

    String operator +(const String &s);

    bool operator ==(const String &s);
    bool operator !=(const String &s);
    bool operator <=(const String &s);
    bool operator >=(const String &s);
    bool operator <(const String &s);
    bool operator >(const String &s);

    char *GetString();
    int GetLength();
    String SubString(int startIndex);
    String SubString(int startIndex, int length);
    int IndexOf(const String &s);
};

Код
// функция, контроля и выделения дополнительной памяти
// под данные строки
char *String::Allocator()
{
    return len<size ? pData : (pData = Realloc_(pData, size=len*2, char));
    // если памяти не хватает, выделяем примерно вдвое больше, чем требуется.
    // такая стратегия позволяет в ряде случаев избежать многократного вызова
    // realloc, что может существенно сэкономить время выполняемых вычислений
}

// функция выделения памяти под данные строки
char *String::Allocator(int)
{
    return MAlloc_(pData, size=len+1, char);
}

// функция освобождения памяти, занятой под данные строки
void String::Deallocator()
{
    Free_(pData);
}


String::String()
{
    len = 0;
    *Allocator(0) = 0; // обнуление строки
}

String::String(const String &s)
{
    len = s.len;
    strcpy(Allocator(0), s.pData); // выделение памяти под строку с
    // последующим копированием данных из строки s в текущую (this)
    // cтроку
}

String::String(const char *s)
{
    len = strlen(s);
    strcpy(Allocator(0), s); // аналогично пред.
}

String::String(char ch)
{
    len = 1;
    *Allocator(0) = ch; // выделение памяти под строку с
    // последующим назначением нулевому элементу pData значения ch
    pData[1] = 0; // обнуление 1-го элемента pData
    // (всякая строка должна оканчиваться нулём)
}

String::~String()
{
    Deallocator();
}

char &String::operator [](int index)
{
    return 0<=index && index<len ? pData[index] : pData[len];
    // при допустимом индексе возвращается pData[index]
    // при недопустимом индексе возвращается 0
}

char &String::operator *()
{
    return *pData;
}

String &String::operator =(const String &s)
{
    len = s.len;
    strcpy(Allocator(), s.pData); // см. конструктор для const String &s
    return *this;
}

String &String::operator +=(const String &s)
{
    len += s.len;
    strcpy(Allocator()+len-s.len, s.pData); // выделение по необходимости доп. памяти
    // и копирование строки s в конец текущей
    return *this;
}

String String::operator +(const String &s)
{
    String result = *this;
    return result += s;
}

bool String::operator ==(const String &s)
{
    return len==s.len && !strcmp(pData, s.pData);
    // здесь сначала сравниваются длины строк
    // если они не совпадают, то возвращается false;
    // ежели совпадают, то сравниваются сами строки
    // (посредством strcmp), результат strcmp отрицается
    // (поскольку эта ф-я истинна, когда строки не совпадают)
    // и возвращается return
}

bool String::operator !=(const String &s)
{
    return len!=s.len || strcmp(pData, s.pData);
    // здесь сначала сравниваются длины строк
    // если они не совпадают, то возвращается true;
    // ежели совпадают, то сравниваются сами строки
    // и результат strcmp возвращается return
}

bool String::operator <=(const String &s)
{
    return len<=s.len && !strncmp(pData, s.pData, len);
    // strncmp подобно strcmp тоже сравнивает строки, но не
    // целиком, а только то количество начальных символов строк,
    // что задано в её третьем параметре
}

bool String::operator >=(const String &s)
{
    return len>=s.len && !strncmp(pData, s.pData, s.len);
}

bool String::operator <(const String &s)
{
    return len<s.len && !strncmp(pData, s.pData, len);
}

bool String::operator >(const String &s)
{
    return len>s.len && !strncmp(pData, s.pData, s.len);
}

char *String::GetString()
{
    return pData;
}

int String::GetLength()
{
    return len;
}

String String::SubString(int startIndex)
{
    String result;
    if (startIndex<0 || len<=startIndex)
        return result; // при недопустимом startIndex возвращается пустая строка

    result.len = len - startIndex;
    strcpy(result.Allocator(), pData+startIndex);
    // выделяем нужное кол-во памяти под данные строки result,
    // копируем в память, на которую указывает result.pData, содержимое
    // текущей (this) строки со смещением startIndex.
    return result;
}

String String::SubString(int startIndex, int length)
{
    String result;
    if (startIndex<0 || len<startIndex+length || length<0)
        return result; // при недопустимой паре (startIndex, length)
    // возвращается пустая строка

    result.len = length;
    strncpy(result.Allocator(), pData+startIndex, length);
    result.pData[length] = 0;
    return result;
}

int String::IndexOf(const String &s)
{
    int cmpMaxStartIndex = len-s.len;
    for (int i=0; i<=cmpMaxStartIndex; i++)
        if (!strncmp(pData+i, s.pData, s.len)) // как только обнаруживаем вхождение s
            // в текущую строку
            return i; // возвращаем индекс символа
    return -1; // если вхождений нет, то возвращается -1
}

Код
#define MAlloc_(p, size, T) \
    ( p = (T *)malloc((size)*sizeof(T)) )
#define Realloc_(p, newSize, T) \
    (T *)realloc(p, (newSize)*sizeof(T))
#define Free_(p)  free(p)
   

Это сообщение отредактировал(а) UnrealMan - 16.5.2006, 21:29
PM MAIL   Вверх
Mal Hack
Дата 16.5.2006, 19:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 2
Всего: 261



UnrealMan, это учебная прога и сдавать ее не мне... Человек этого  не объяснит... 
PM ICQ   Вверх
bsa
Дата 16.5.2006, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



А то что есть - работать не будет. Придется выбирать. smile 
PM   Вверх
UnrealMan
Дата 16.5.2006, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Добавил чуток комментариев. Может, так понятней будет :-) 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0973 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.