Вопрос № 28856: У меня имеется файл Input.txt, в нем содержаться числа типа Float (число чисел заранее не известен). Нужно написать программу, которая читает все эти числа и заполняет ими массив.
P.S. у меня вызывает затруднее организация массива, ведь разм...Вопрос № 28874: Здравствуйте уважаемые эксперты. Изучаю C++ и столкнулся с такой проблемой. При присваивании одного объекта, использующего динамическую память, другому происходит ошибка. Как я выяснил ошибка происходит при вызове деструктора одного из объектов. Он п...Вопрос № 28877: Уважаемые эксперты! Помогите разобраться в ситуации с исключениями. Упорно
не хочет генерироваться исключение bad_alloc, в том числе в примере из MSDN. Блок if выполняется, а catch - нет :(. как заставить работать catch?
// bad_alloc.cpp<br...
Вопрос № 28.856
У меня имеется файл Input.txt, в нем содержаться числа типа Float (число чисел заранее не известен). Нужно написать программу, которая читает все эти числа и заполняет ими массив.
P.S. у меня вызывает затруднее организация массива, ведь размер мы его не знаем......
Отвечает: Bob Johnson
Здравствуйте, Liger Dennis!
Используй динамические массивы, например vector из STL.
Ответ отправил: Bob Johnson (статус: Академик)
Отправлен: 03.11.2005, 20:03
Отвечает: estiGi
Здравствуйте, Liger Dennis!
Ну, удобнее конечно было бы, если бы первым числом в файле было количество чисел.
Если все же так не получается, то тебе стоит делать как делают обычные массивы. Т.е. выделять заранее кусок памяти, потом, если мало, перевыделять.
См. приложение (условимся, что функция ReadNext возвращает следующее число из файла)
Прототип ReadNext:
bool ReadNext (float & num);
если она возвращает false, значит чисел в файле больше нету
функция ReAlloc перевыделяет массив, увеличивая его на передаваемый размер, FillArray непосредственно заполняет массив, с нее начинается работа
Приложение:
Ответ отправил: estiGi (статус: 5-ый класс)
Отправлен: 03.11.2005, 20:52
Отвечает: VampSergey
Здравствуйте, Liger Dennis!
Надо использовать динамическое распределение памяти. Например с помощью операторов new и delete:
float* lpArray = new float[size];
delete[] lpArray; // освободим память
,где size - это число элементов массива, которые все-же лучше знать перед чтением самих значений float. Например в том же файле разместить инфу по кол-ву чисел...
Но для понимания(и нормального использования) стоит взять книгу и найти там динамическое распределение памяти! От этого никуда не деться ;)
Ответ отправил: VampSergey (статус: 2-ой класс)
Отправлен: 03.11.2005, 21:17
Отвечает: Raptor1
Здравствуйте, Liger Dennis!
Как вариант выполнять задачу в два прохода - в первом парсить строки и считать количество чисел, потом выделить нужный объем с помощью new и вторым проходом заполнять массив, а можно использовать std::vector<float> или CArray из MFC в который и добавлять числа с помощью insert или Add
Ответ отправил: Raptor1 (статус: 9-ый класс)
Отправлен: 05.11.2005, 10:01
Отвечает: Rusland
Здравствуйте, Liger Dennis!
В вашем случае удобно использовать vector или list. Удачи.
--------- Пресловутое недостающее звено между обезьяной и цивилизованным человеком - это как раз мы. (Конрад Лоренц)
Ответ отправил: Rusland (статус: Практикант)
Отправлен: 07.11.2005, 09:02
Вопрос № 28.874
Здравствуйте уважаемые эксперты. Изучаю C++ и столкнулся с такой проблемой. При присваивании одного объекта, использующего динамическую память, другому происходит ошибка. Как я выяснил ошибка происходит при вызове деструктора одного из объектов. Он пытается освободить уже освобожденную память. Попытался решить проблему написанием конструктора копирования, но он не вызывается при присваивании одного объкета другому (собственно это написано во всех литературных источниках). Как решить проблему? Привожу пример
неработающего кода.
Приложение:
Отправлен: 03.11.2005, 23:47
Вопрос задал: Domian (статус: Посетитель)
Всего ответов: 5 Мини-форум вопроса >>> (сообщений: 0)
Отвечает: estiGi
Здравствуйте, Domian!
Тебе нужно перегрузить оператор равно (operator=) и в нем копировать значение, на которое указывает указатель. А так ты просто копируешь указатель, его адрес.
А конструктор копирования вызовется в следующем случае:
myclass a (10);
myclass b = a;
А чтобы память не удалялась дважды, когда на нее указывают два удаляемых указателя, пиши так:
delete ptr;
ptr = NULL;
Ответ отправил: estiGi (статус: 5-ый класс)
Отправлен: 03.11.2005, 23:59
Отвечает: VampSergey
Здравствуйте, Domian!
Перед удалением указателя надо его обнулить:
ptr = NULL;
delete ptr;
Удачи!
Ответ отправил: VampSergey (статус: 2-ой класс)
Отправлен: 04.11.2005, 10:17
Отвечает: sergey2nk
Здравствуйте, Domian!
В каждом пользовательском классе в разных ситуациях автоматически используется 4 метода:
class myclass {
myclass(); // конструктор по умолчанию
myclass(const myclass & myobj); // констркутор копирования
~myclass(); // деструктор
myclass & operator=(const myclass & myobj); // оператор присваивания
};
В случае если класс использует внешние ресурсы (в вашем случае память), о важности определения этих методов нужно как минимум помнить. Ну, а определять вы можете только те из них которые используются (явно или не явно).
И еще, по поводу выражения (ptr = NULL;) в предыдущих ответах - это не решает проблему, поскольку влияет только на переменную в одном из объектов класса, остальные ссылки на эту память (в других экземплярах (объектах) класса) сохранят значение и тоже попытаются освободить ту же память. А предложение присваивать переменной ptr = NULL перед освобождением памяти - это конечно смелое решение проблемы, но сообщение об освобождении несуществующего сегмента памяти (памяти по адресу 0L) будет сгенерировано тем же оператором
delete, а еще останется так и не освобожденная память, на которую указывала переменная ptr. Так что с логической стороны это решение (мягко говоря) неправильно.
Решать проблему копирования объектов работающих с памятью можна несколькими способами. Самые простые из них:
1) просто выделять память в новом (или изменяемом оператором = ) объекте и копировать в нее содержимое копируемого объекта;
2) если нужно чтобы несколько объектов действительно работали с одной и той же памятью, желательно организовать счетчик ссылок на память.
Как делается счетчик ссылок можна посмотреть тут:
http://infobez.net.ru/cpp/art/zart196.php
можна поискать в инете статьи об "умных указателях".
Примеры их реализации можна посмотреть в STL-классах: std::auto_ptr, а так же в реализации класса std::string
Желаю удачи.
Ответ отправил: sergey2nk (статус: 1-ый класс)
Отправлен: 04.11.2005, 12:20
Отвечает: _DM_
Здравствуйте, Domian!
Насколько я понял вашу проблему Domian дело в следующем. Оператор присваивания = по умолчанию побитово копирует один объект в другой, в таком случае если вы применяете его для классов с динамически выделенными данными вы получаете две копии одного класса, таким образом два деструктора по очереди пытаются освободить один участок памяти. Выход: вам необходимо перегрузить оператор присваивания, привожу пример в приложении, может быть с ошибками, но вы в любой книге найдете подобный, или в интернете.
Приложение:
Ответ отправил: _DM_ (статус: 2-ой класс)
Отправлен: 04.11.2005, 18:54
Отвечает: Raptor1
Здравствуйте, Domian!
Если ты собираещься выполнять присваивание тебе нужно обязательно перегрузить конструктор копий и оператор присваивания:
class myclass
{
int *ptr;//указатель
public:
myclass(myclass& objSrc);
myclass(int);
~myclass();
myclass& operator=(myclass& objSrc);
Ответ отправил: Raptor1 (статус: 9-ый класс)
Отправлен: 05.11.2005, 10:00
Вопрос № 28.877
Уважаемые эксперты! Помогите разобраться в ситуации с исключениями. Упорно не хочет генерироваться исключение bad_alloc, в том числе в примере из MSDN. Блок if выполняется, а catch - нет :(. как заставить работать catch?
Отвечает: Jadd
Здравствуйте, thunderbird!
А и не должен туда попадать. Под исключениями подразумевается стандартный интерфейс для обнаружения и обработки необычных, непредвиденных и исключительных состояний или событий. Чтего ж исключительного в Вашем коде? Если не терпится поймать оное(если само не происходит), нужно его сгенерировать. Делается это вызовом функции throw внутри блока try{...}catch(...){}. Например:
try
{
LPSTR szMsg = "Exception";
throw szMsg;
}
catch(...)//ловим все исключения, но Вы можете свой класс исключаний, а можете фильтровать с помощью __except
{
AfxMessageBox("Exception");
}
Удачи.
--------- Если в сердце дверь закрыта, нужно в печень постучаться
Ответ отправил: Jadd (статус: Практикант)
Отправлен: 04.11.2005, 08:33 Оценка за ответ: 4 Комментарий оценки: Это все понятно, смысл был именно в генерации исключения bad_alloc. блок if был вставлен только для контроля... как я понял, для этого throw не надо?
Отвечает: _DM_
Здравствуйте, thunderbird!
Могу ошибаться, но разве невозможность выделить память вызывает какое нить исключение? Если да, то может у ебя это исключение дебаггер VC перехватывает ? По крайней мере в Билдере дебаггер обрабатывает исключения раньше блока catch, попробуй для проверки запусть готовый exe.
Ответ отправил: _DM_ (статус: 2-ой класс)
Отправлен: 04.11.2005, 19:04
Отвечает: Raptor1
Здравствуйте, thunderbird!
Надо установить вызываемую функцию (см. Q167733 MSDN):
#include<new>
#include <new.h>
#include<iostream>
using namespace std;
int my_new_handler(size_t)
{
throw std::bad_alloc();
return 0;
}
int main(int argc, char* argv[])
{
_PNH _old_new_handler;
_old_new_handler = _set_new_handler(my_new_handler);
char* ptr;
try
{
// ptr = new(std::nothrow) char[~size_t(0)/2]; // так catch не выполняется
ptr = new char[~size_t(0)/2]; // а так выполняется
if(!ptr)
cout<<"Fail"<<endl;
delete[ ] ptr;
}
catch(bad_alloc &ba)
{
cout <<"from catch: "<< ba.what( ) << endl;
};
_set_new_handler(_old_new_handler);
return 0;
}
Ответ отправил: Raptor1 (статус: 9-ый класс)
Отправлен: 05.11.2005, 09:59