Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.01.2011, 08:06   #21
An1ka
C++,DirectX/OpenGL
Форумчанин
 
Регистрация: 09.01.2011
Сообщений: 422
Радость

Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
На кой чёрт буфер делать глобальным? Область видимости должна быть минимально необходимой. В остальном то же, что я написал в предыдущем посте. На разве что в реализации метода вместо метода getline использован оператор сдвига влево.
Глобальный буфер - просто для наглядности !!! Вдруг захочется еще где-нибудь его использовать в других функциях. В остальном у меня именно это и было написано где-то страницу назад, но без буфера !
Вообще, да. Нуль-символ правильнее тут говорить. Хотя нуль-символ сам по себе и является нуль-строкой ( пустой строкой, если хотите или строкой разделителем).
И вообще попрошу не придираться к словам в 7 утра
An1ka вне форума Ответить с цитированием
Старый 20.01.2011, 10:49   #22
S1av0k
Пользователь
 
Регистрация: 26.11.2009
Сообщений: 87
По умолчанию

Цитата:
Не знаю чему вас там учат !! Вот смотри, всё работает и никаких "друзей" и констант не надо !! Ты ведь записываешь в память !
И про высвобождение динамической памяти не забывай
Допустим, что нас там не учат, а я сам учусь И по-моему, это вполне логично, что у меня появляются вопросы Так что не стоит возмущаться В конце концов я не спрашиваю то, что я смог прочитать где бы то ни было.
А за советы спасибо, попробую.

Из данной ситуации вышел, как мне кажется, довольно элегантно:
Код:
istream& operator >> (istream& s,String& qw)	
	{
		if (qw.mass)
			delete [] qw.mass;
		qw.mass = new char [s.rdbuf()->in_avail()];
		s >> qw.mass;
		return s;	
	}
Всем спасибо!
Помог - жми весы

Последний раз редактировалось Stilet; 22.01.2011 в 13:59.
S1av0k вне форума Ответить с цитированием
Старый 20.01.2011, 14:03   #23
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Лучше вместо if(qw.mass) использовать if(qw.mass != NULL). Это лишь этическая сторона вопроса. Так читабельней.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su
Obey-Kun вне форума Ответить с цитированием
Старый 20.01.2011, 14:19   #24
S1av0k
Пользователь
 
Регистрация: 26.11.2009
Сообщений: 87
По умолчанию

Вот конечный код программы:
Код:
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
using std::istream;
#include "string.h"

class String
{
	private:
		char *mass;
	public:
		String();
		String(char[]);
		String(const String&);
		~String(){delete []mass;}								//деструктор
		friend ostream& operator << (ostream&,const String&);
		friend istream& operator >> (istream&,String&);
		String& operator += (const char a);
		String& operator += (const char* a);	
		String& operator = (const String&);
};

String::String()
	{	
		mass = NULL;
	}

String::String(char p[])
	{
		int length = strlen(p);
		int i = 0;
		mass = new char [length];
		while(p[i])
			{
				mass[i] = p[i];	
				++i;
			}
		mass[i] = '\0';
	}	
	
String::String(const String& qw)									//копирующий конструктор
	{
		if (this != &qw)
			{
				int length = strlen(qw.mass);
				delete [] mass;
				mass = new char[length];
				strcpy(mass,qw.mass);
			}	
	}	
	
ostream& operator << (ostream &s,const String &qw)
	{
		if (qw.mass)
			s << qw.mass;	
		return s;
	}	
	
istream& operator >> (istream& s,String& qw)	
	{
		if (qw.mass)
			delete [] qw.mass;
		qw.mass = new char [s.rdbuf()->in_avail()];
		s >> qw.mass;
		return s;	
	}
	
String& String::operator += (const char a)
	{
		int length;
		
		if (mass) length = strlen(mass);
		else length = 0;
		
		int i = 0;
		char* ptr = mass;
		
		mass = new char [length+1];
		
		if (ptr)
			strcpy(mass,ptr);
		delete [] ptr;
		mass[length] = a;
		mass[length+1] = '\0';
		return *this;
	}	
	
String& String::operator += (const char* a)	
	{
		int length1 = strlen(a);
		int length2 = strlen(mass);
		char *ptr = mass;
		
		if (mass) length2 = strlen(mass);
		else length2 = 0;
		
		mass = new char [length1 + length2];
		char* temp = ptr;
		char* mptr = mass;
		while (ptr && *ptr)
			{
				*mptr = *ptr;
				++mptr;
				++ptr;	
			}
		delete [] temp;
		int i = 0;
		while (a[i] && mptr)
			{
				*mptr = a[i];	
				++i;
				++mptr;
			}
		mass[length1 + length2] = '\0';	
		return *this;
	}
	
String& String::operator = (const String& qw)	
	{
		int length;
		if (qw.mass)
			{
				length = strlen(qw.mass);
				delete [] mass;
				mass = new char [length];
				strcpy(mass,qw.mass);
			}	
		else
			{
				length = 0;
				mass = new char [length];
				mass[length] = '\0';
			}			
		return *this;
	}
	

		
int main (int argc, char *argv[])
{
	String str1;
	char p[80];
	cout << "Введите строку: ";
	cin.getline(p,80);
	String str2 = p;
	
	
	String str3 = str2;
	
	cout << str1 << endl;
	cout << str2 << endl;
	cout << str3 << endl;
		
	str1 = str2;
	cout << str1 << endl;
	
	cout << "Введите символ: ";
	char a;
	cin >> a;
	str1 += a;
	cout << str1 << endl;
	
	String str4;
	cout << "Введите строку: ";
	cin >> str4;
	cout << str4 << endl;
	
	char* qwe = new char [80];
	cout << "Введите строку: " << endl;
	cin >> qwe;
	str1 += qwe;
	delete [] qwe;
	cout << str1 << endl;
	
	return 0;
}
Так как я учусь самостоятельно, хотелось бы услышать какие-нибудь мнения/предпочтения относительно него, только, пожалуйста, обоснованные.

И момент, который я отчаянно недопонимаю: если вот этот код
Код:
char* qwe = new char [80];
заменить на
Код:
char qwe[80];
программа удачно компилится, однако её исполнение заканчивается крахом. Среда MonoDevelop, OС Gentoo, если это имеет значение...
Помог - жми весы
S1av0k вне форума Ответить с цитированием
Старый 20.01.2011, 14:40   #25
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Цитата:
using std::cin;
using std::cout;
using std::endl;
using std:stream;
using std::istream;
О___О
На самом деле, лучше вообще using по чужим пространствам имён не использовать. Вернее, в учебных проектах-то можно, для краткости. Но в нормальных проектах так никогда не делают, лучше пиши вызовы целиком. Но хотелось бы отметить, что твой подход лучше, чем using namespace std.

Что ещё хотелось бы отметиь... Слишком часто делается new. Как я выше сказал, лучше выделять памяти с запасом. Для этого надо сделать отдельный метод setData(char*), который заботился бы о выделении памяти. То есть скажем изначально ты выделяешь 16 символов. Если при очередной операции не хватает этого запаса, выделяешь 32. И так далее. Тогда и читабельность упростится, опять же. Не говоря уж о скорости работы (теоретической).

Теперь насчёт отступов и прочего. Смотрится страшновато. Можешь почитать http://techbase.kde.org/Policies/Kdelibs_Coding_Style
Сравни:
Код:
String::String(const String& qw)									//копирующий конструктор
	{
		if (this != &qw)
			{
				int length = strlen(qw.mass);
				delete [] mass;
				mass = new char[length];
				strcpy(mass,qw.mass);
			}	
	}
Код:
/**
 * Копирующий конструктор.
 */
String::String(const String &qw)
{
    if (this != &qw) {
        int length = strlen(qw.mass);
        delete [] mass;
        mass = new char[length];
        strcpy(mass,qw.mass);
    }	
}
Что лучше читается? Но на самом деле, все описания методов лучше делать в объявлении, а не в реализации. Это делается потому, что так проще разобраться в классе при разделении объявления и реализации по файлам. И обрати внимание, что я комментарий начал как "/**", а не "/*". Это связано с системой документации кода Doxygen (можешь почитать в википедии), а также с тем, что многие IDE подсвечивают такие блоки особым цветом, так что ты сможешь отделять пояснения к коду от пояснений к объявлениям (как-то я коряво сказал не выспался).

Далее... поля класса лучше именовать как m_название. То есть станет не mass, а m_mass. Это позволяет избежать путаницы и делает код более читабельным.

Так... слово насчёт инклюдов. У тебя:
Код:
#include "string.h"
А лучше:
Код:
#include <cstring>
Не помню, почему именно так лучше делать, но ведь как минимум лучше читается, согласен? Сразу ясно, что это string из C.

Далее... operator<<(...), а не operator << (...). То же касается прочих. Так принято.

int main и так возвращает 0 в случае завершения, так что избавься от return 0 там.

Крах, о котором ты сказал... установи, на какой строке он происходит.

upd.
Попробовал запустить твой код. Падает.
Цитата:
Введите строку: 32342
*** glibc detected *** ./a.out: double free or corruption (out): 0x00007fec24b2e230 ***
======= Backtrace: =========
...
Если разбить String str2 = p; на String str2; str2 = p; то всё работает. Почему именно, я пока не разбирался. Очень голоден, убежал есть.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su

Последний раз редактировалось Obey-Kun; 20.01.2011 в 15:03.
Obey-Kun вне форума Ответить с цитированием
Старый 20.01.2011, 14:51   #26
S1av0k
Пользователь
 
Регистрация: 26.11.2009
Сообщений: 87
По умолчанию

Ох, спасибо за советы, приму к сведению
В main() строка девятая снизу, если Вы про ту строчку кода. Причем аварийная остановка случается сразу же после нажатия интер при вводе первой строки, что, казалось бы, к изменению строки кода отношения не имеет...(как минимум очевидного для меня)
Помог - жми весы

Последний раз редактировалось S1av0k; 20.01.2011 в 14:54.
S1av0k вне форума Ответить с цитированием
Старый 20.01.2011, 15:11   #27
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Ой, вот ещё что!!! Важная штука. Ты когда делаешь delete для указателя, его значение не обнуляется. Приведу пример.

Код:
int *a = new int(5); //а указывает на ячейку, где лежит int, который равен пяти
delete a; //удаляем тот int
//а всё ещё указывает на ту ячейку!!!
a = NULL; //а теперь не указывает
Короче, не забывай обнулять указатели после удаления памяти.
Что такое NULL и почему его надо использовать для указателей -- http://google-styleguide.googlecode....ULL#0_and_NULL. Вкратце — использование NULL сразу даёт нам понять (визуально), что мы работаем с указателем. То есть повышается читабельность кода, опять же.

Прости за сумбурность изложения, эту ночь не спал.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su

Последний раз редактировалось Obey-Kun; 20.01.2011 в 15:15.
Obey-Kun вне форума Ответить с цитированием
Старый 20.01.2011, 16:19   #28
S1av0k
Пользователь
 
Регистрация: 26.11.2009
Сообщений: 87
По умолчанию

Ну да, я использовал NULL в пустом конструкторе, например. В остальных случаях "занулять" указатели (в приведенном коде) считаю если не излишним, то не необходимым...
Помог - жми весы
S1av0k вне форума Ответить с цитированием
Старый 20.01.2011, 16:30   #29
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Виноват. В твоём коде это действительно не нужно.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su
Obey-Kun вне форума Ответить с цитированием
Старый 20.01.2011, 16:34   #30
S1av0k
Пользователь
 
Регистрация: 26.11.2009
Сообщений: 87
По умолчанию

Цитата:
Если разбить String str2 = p; на String str2; str2 = p; то всё работает. Почему именно, я пока не разбирался.
А происходит это потому, что в первом случае вызывается инициализирующий конструктор, который почему-то работает неверно.....
Помог - жми весы
S1av0k вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как обойти "преобразование типа из "string" в "float" невозможно" lexluter1988 Помощь студентам 1 07.08.2010 12:23
классы вида for="..." и class="A B C" Darkstar100 HTML и CSS 5 19.01.2010 20:06
при вводе на листе "магазин"- код товара появлялось "описание" товара из "склада" с "продажной ценой" aleksei78 Microsoft Office Excel 13 25.08.2009 12:04