Непонятная лшибка при выполнении программы
Есть код:
{
int srchandl;
int desthandl;
int srclength;
int destlength;
char *buf;
int qw;
//-=-------------------------
if(OpenDialog1->Execute())
{
srchandl=FileOpen(OpenDialog1->FileName,fmOpenRead);
srclength=FileSeek(srchandl,0,2);
FileSeek(srchandl,0,0);
buf=new char [srclength+3];
buf="";
qw=FileRead(srchandl,buf,srclength);
FileClose(srchandl);
int q=1;
int k=0;
for(int i=0; i<srclength-1;i++)
{
if(((int)buf)!=10)
{
StringGrid1->Cells[k][q]=buf;
StringGrid1->Cells[k][q+1]=(int)buf;
k++;
}
else
{
q+=2;
k=0;
}
}
}
else
{
}
}
Смысл такой: при нажатии на эту кнопку открывается окно выбора файла, выбираем файлик (*.txt)и обрабатываем то что в нем лежит. Ошибка возникает когда в файле больше 101 символа, если меньше, то все функционирует нормально, если больше то выскакивает сообщение:
Project raised exception class EAccessViolation with message 'Access Violation at address 46303644. Read Of Address 46303644'.
Кто может подсказать почему?
Вот этой строкой, вы не обнуляете строку, как того хотите, а заставляете buf указывать совсем на другую область памяти.
зачем buf=""?
сделал new, читай спокойно строчку из файла.
И еще замечание - обычно лучше использовать такую конструкцию:
{
//Делаем чтото если пользователь не выбрал файл
ShowMessage("Отменено пользователем");
return
}
//делаем все остальное
Данную функцию можно переписать следующим образом:
int srchandl=FileOpen(OpenDialog1->FileName,fmOpenRead);
int srclength=FileSeek(srchandl,0,2);
FileSeek(srchandl,0,0);
char* buf=new char[srclength+1];
if(!FileRead(srchandl,buf,srclength)){
ShowMessage("Error");
return;
}
FileClose(srchandl);
int q=1;
int k=0;
while(int tmp= (int)*buf++)
if(tmp!=10){
StringGrid1->Cells[k][q]=(char)tmp;
StringGrid1->Cells[k][q+1]=tmp;
k++;
}
else{
q+=2;
k=0;
}
delete[] buf;
Код содержит ошибку. Какую и как ее избежать? :)
Код содержит ошибку. Какую и как ее избежать? :)
Это ты кого щас спрашиваешь? :D
Код содержит ошибку. Какую и как ее избежать? :)
я в этом деле дилетант, но мне кажется что здесь косяк в том что
1. При попадании нескольких символов с кодом "10", в гриде будте пропускаться несколько строк подряд (для моей проги - это ошибка :) )
2.
Эх, опередил :D
Нужно перед циклом сохранять указатель на начало памяти, а затем его востанавливать.
Вторая ошибка - коде производится проверка на количество прочитаных байт, но не проводится проверка на то что файл собственно открыт. Но то о чем сказал aks не верно. Почему? Потому что функции File* не боросают исключений, а оператор new исключения не сгенерирует. Если бы мы предположили что в массиве есть хотябы один элемент и обратились к нему напрямую - то возможно получили бы меморилик (но такое само по себе является ошибкой).
Третья ошибка - проверка количества прочитаных байт. Функции File* возвращают при ошибке -1. Наша проверка этого не учитывает.
Но на самом деле последние две ошибки не существенны и в принципе (по крайней мере в контексте заявленного уровня вопроса для начинающих) их можно не учитывать, тем более что это не языковые ошибки, а особенности конкретной среды разработки.
Кроме того, в коде не проверяется успешность выделения памяти, но это опять же - далеко не уровень начинающего и зависит от требований к коду.
Таким образом исправленый код:
int srchandl=FileOpen(OpenDialog1->FileName,fmOpenRead);
if(srchandl == -1){
ShowMessage("Error open file");
return;
}
int srclength=FileSeek(srchandl,0,2);
if(srclength == -1){
ShowMessage("Error seek file");
return;
}
FileSeek(srchandl,0,0);
char* buf=new char[srclength+1];
char* first = buf;
//Используем единообразный подход
int srccount = FileRead(srchandl,buf,srclength);
if(srccount == -1){
ShowMessage("Error read file");
return;
}
FileClose(srchandl);
int q=1;
int k=0;
while(int tmp= (int)*buf++)
if(tmp!=10){
StringGrid1->Cells[k][q]=(char)tmp;
StringGrid1->Cells[k][q+1]=tmp;
k++;
}
else{
q+=2;
k=0;
}
buf = first;
delete[] buf;
first = NULL;
Это кстати к тому, что к борландовским примерам из справки надо обязательно прикладывать свою голову - и учитывать, что примеры зачастую делались калькой с делфей - ну а делфи это ацтой, что подтверждают множество холиваров.
[/holywar]
:):):)
if(srccount == -1){
ShowMessage("Error read file");
return;
}
Если чтение файла вернет ошибку, мы выйдем из функции, не удалив выделенную память.
Не лучшая на мой вгляд идея определять размер выдяемой памяти из внешнего источника (как размер файла). Хотя это скорее не мой взгляд, цитата из Саттера :)
И еще файлик размером больше numeric_limits<int>::max() байт мы обработать не сможем. Хотя здесь скорее надо обратиться к первому пункту. :)
Хотя конечно в этой конкретной задаче это имеет мало значения.
if(srccount == -1){
ShowMessage("Error read file");
return;
}
Если чтение файла вернет ошибку, мы выйдем из функции не удалив выделенную память.
Да. Зарапортовался. Спасибо.
По поводу выделения памяти на основании внешнего источника - саттеровская рекомендация верна, так же как верна рекомендация "никогда не прыгайте с высоты, что бы не поломать ногу". Что делать в этом случае парашютистам? :) Правильно, для парашютиста опасность поломать ногу - это часть того, чем он занимается.
Точно так же и здесь - если вы читаете нечто извне - некоторые параметры будут определяться не вами. Либо - второй подход - использовать фиксированные размеры буфера (например читать блоками по 4К). Либо... Все зависит от уровня паранойи в вашей задаче.
Тут кстати надо понимать, что есть определенная грань - ведь по сути можно сказать - "нафига все эти навороты, если можно использовать например auto_ptr?" Но, если продолжить аналогию с парашютным спортом, более безопасно прыгать тендемом - все проблемы ложаться на инструктора. Но тогда зачем вообще прыгать с парашютом? :) Т.е. зачем использовать С++, когда есть более безопасные языки? Правильный ответ - должно определяться задачей.
QUOTE]
Не верно то что там потенциальный меморилик? Да есть он там. Уж не знаю что там функция вернет, которая в условии стоит, но внутри условного оператора есть. Остальной код не смотрел - ибо не хочется разбираться в отрыве от контекста и не используемых мной либ. =)
Насколько моих познаний хватает... этот цикл будет выполнятся, до тех пор пока...в в переменной buf что-то есть? так? т.е. еслt на очередной итерации эелемент buf окажется пустым цикл закончится?
Утечка памяти. Тоесть выделили, а удалить забыли. Может быть еще и утечка ресурсов - когда системный ресурс у ОС запросили, а не освободили.
Насколько моих познаний хватает... этот цикл будет выполнятся, до тех пор пока...в в переменной buf что-то есть? так? т.е. еслt на очередной итерации эелемент buf окажется пустым цикл закончится?
Цикл будет выполняться, пока не встретит элемент массива равный нулую. =)
подождите, но ведь в условии нету сравнения с нулем. есть только присваивание переменной tmp очередного значения buf. Блин, ваще понять не могу. Понимаю что все проще паренной репы, а все равно не пойму:mad:
по сути while (tmp != 0) (только ессна тут tmp меняется)
Цикл будет выполняться, пока не встретит элемент массива равный нулую. =)