Строка как указатель на char = путаница. Помогите разобраться

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
fromkharkov
Сообщения: 1
Зарегистрирован: 24 авг 2009, 11:09

Всем привет!

У меня задача: создать меню, в которое можно добавлять различные блюда. Обеспечить произвольную размерность структуры за счет использования в объекте динамических структур данных. Реализовать вывод меню в файл, чтение из файла.
Создаю класс dish с полями Название, Цена и Тип. Название блюда задаю как указатель на char. Потом создаю класс menu, у него одно из полей - объект класса dish. В конструкторе класса menu создаю массив объектов dish d[num], вводя данные с клавиатуры.
Проблема: при вводе с клавиатуры Название блюда сохраняется только последнее введенное, и у всех предыдущих d название заменяется на последнее введенное. (Цена и тип сохраняются для каждого d успешно) - это я вижу при отладке.
Подскажите плиз в чем может быть проблема. (ВСЕ ВРЕМЯ ПУТАЮСЬ С УКАЗАТЕЛЯМИ НА СТРОКИ).
Всем заранее ОЧЕНЬ благодарен

Код: Выделить всё

class dish
	{
	private:
		char *name;
		double price;
		dish_typ type;
	public:
		dish();
		dish(char * name, double price, dish_typ type);
		void set(char * name, double price, dish_typ type); 
};
class menu
{
private:
	dish d;
	fstream f;
public:
	menu();
};
dish::dish()
{
	name="";
	price=0.00;
	type=cold;
}
dish::dish(char * name, double price, dish_typ type)
{
	this->name=name;
	this->price=price;
	this->type=type;	
}

void dish::set(char * name, double price, dish_typ type)
{
	this->name=name;
	this->price=price;
	this->type=type;
}
void dish::dish_prn()
{
		setlocale(LC_ALL,"Russian");
	char* s;
		if (type==cold)
			s="cold";
		if (type==hot)
			s="hot";
		if (type==sweet)
			s="sweet";
	cout<<"------------\nНазвание блюда  Тип    Цена\n";
	cout<<name<<"   "<<s<<"   $"<<price<<endl;
}
menu::menu()
{
	setlocale(LC_ALL, "Russian");
	char name[25];
	double price;
	int type;
	short num;
	f.open("menu2.txt", ios_base: :o ut|ios_base::trunc|ios_base::binary);
//использую бинарный файл
	cout<<"How many dishes do you want in the menu?\n";
	cin>>num;
	cin.get();
	//dish * d=new dish[num];
	dish d[10];
	dish k;
	for (int i=0; i<num; i++)
	{
		cout<<"Введите название блюда, его цену и тип (горячее/холодное/десерт)\n";
		cin.getline(name, 30);
		(cin>>price).get();
		(cin>>type).get();
		d[i].set(name, price, (dish_typ)type);
		f.write((char*)&d[i], sizeof d[i]);
	}
	f.close();
	f.open("menu2.txt", ios_base::in|ios_base::binary);
	f.seekg(sizeof d[0] );
	f.read( (char*)&k, sizeof d[1] );
	k.dish_prn();
	f.close();
}
void main()
{
	menu m;
}
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Вместо указателья char* name используй символьный массив char name[40];
Тогда в конструкторе вместо оператора присваивания нужно будет использовать функцию копирования строки, типа strncpy().

Другой вариант: вместо символьного массива использовать класс строки, типа std::string.
Тогда оператор присваивания строки в конструкторе будет работать правильно.
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

Используй std::string и не будет путаницы.
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Decoder писал(а):Вместо указателья char* name используй символьный массив char name[40];
Либо оставить объяление как есть, но при присвоении наименования выделять динамическую память:

Код: Выделить всё

dish::dish(char * p_name_, double p_price, dish_typ p_type)
{
    this->name = new char [lstrlen (p_name)];
    if (this->name != null)
      lstrcpy (this->name, p_name);

    this->price=p_price;
    this->type=p_type;
};

void dish::set(char * p_name, double p_price, dish_typ p_type)
{
    delete [this->name];
    this->name = new char [lstrlen (p_name)];
    if (this->name != null)
      lstrcpy (this->name, p_name);
    this->price=p_price;
    this->type=p_type;
};
А в деструкторе не забыть почистить память:

Код: Выделить всё

void dish::~dish ()
{
    delete [this->name]; this->name = null;
};
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

&quot писал(а):

Код: Выделить всё

void dish::~dish ()
{
   delete [this->name];
   this->name = null;
};
Более правильно так:

Код: Выделить всё

void dish::~dish ()
{
   delete [] this->name;
   this->name = NULL;
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Romeo писал(а):Более правильно так:

Код: Выделить всё

............
Разумеется. Бес попутал. :( Подтолкнул под руку, скобка не там и закрылась :)
_SG
Сообщения: 53
Зарегистрирован: 28 фев 2009, 10:43
Откуда: Севастополь

ужос... простейшие весчи делаются немыслимо большим и запутанным кодом. ненавижу ООП и иже с ним(((
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Действительно, замысел хороший, но слишком громоздкая реализация.
Для этого лучше использовать функцию strdup() в консткукторе и функцию free() в деструкторе.
В методе set() сначала вызывается free(), а потом strdup().
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

WinMain писал(а):Действительно, замысел хороший, но слишком громоздкая реализация.
Для этого лучше использовать функцию strdup() в консткукторе и функцию free() в деструкторе.
В методе set() сначала вызывается free(), а потом strdup().
Если использовать std::string, то не надо будет ничего деть в конструкторе и деструкторе. Кроме того, когда используются динамические переменные, нужно в классе определять оператор копирования. Т.к. он произодит почленное копирование, по-умолчанию, а это не подходит, т.к. там указатель.
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Ответить