Правильно или нет?
От: gbush  
Дата: 07.11.02 22:35
Оценка:
hi
        long nRowNum = m_dArRetX.size();
        for(long i=0;i<nRowNum;i++)
        {
            char *bufX = new char[10];
            char *bufY = new char[10];
            char *bufStep = new char[10];
            sprintf(bufY,"%f",m_dArRetY[i]);
            m_pListCtrl->InsertItem(i,_T(bufY));
            sprintf(bufX,"%f",m_dArRetX[i]);
            m_pListCtrl->SetItemText(i,1,_T(bufX));
            sprintf(bufStep,"%d",i);
            m_pListCtrl->SetItemText(i,2,_T(bufStep));
            delete []bufX;
            delete []bufY;
            delete []bufStep;
        }

и почему?
Best regards?
Все хорошо кончается, что кончается ещё лучше...
Re: Правильно или нет?
От: Андрей Тарасевич Беларусь  
Дата: 07.11.02 23:07
Оценка:
Здравствуйте gbush, Вы писали:

G>hi

G>
G>        long nRowNum = m_dArRetX.size();
G>        for(long i=0;i<nRowNum;i++)
G>        {
G>            char *bufX = new char[10];
G>            char *bufY = new char[10];
G>            char *bufStep = new char[10];
G>            sprintf(bufY,"%f",m_dArRetY[i]);
G>            m_pListCtrl->InsertItem(i,_T(bufY));
G>            sprintf(bufX,"%f",m_dArRetX[i]);
G>            m_pListCtrl->SetItemText(i,1,_T(bufX));
G>            sprintf(bufStep,"%d",i);
G>            m_pListCtrl->SetItemText(i,2,_T(bufStep));
G>            delete []bufX;
G>            delete []bufY;
G>            delete []bufStep;
G>        }
G>

G>и почему?

Во-первых, если буферы у тебя известного на стадии компиляции размера, то зачем выделять их в динамисеской памяти? Почему не в автоматической?

Во-вторых, если буферы никогда не используются одновременно, то зачем нужно три? Достаточно одного.

В-третих, применение макро '_T' к чему-либо, кроме строкового или символьного литерала — полная бессмыслица.
Best regards,
Андрей Тарасевич
Re: Правильно или нет?
От: Klestov  
Дата: 07.11.02 23:33
Оценка:
Здравствуйте gbush, Вы писали:

G>hi

G>
G>        long nRowNum = m_dArRetX.size();
G>        for(long i=0;i<nRowNum;i++)
G>        {
G>            char *bufX = new char[10];
G>            char *bufY = new char[10];
G>            char *bufStep = new char[10];
G>            sprintf(bufY,"%f",m_dArRetY[i]);
G>            m_pListCtrl->InsertItem(i,_T(bufY));
G>            sprintf(bufX,"%f",m_dArRetX[i]);
G>            m_pListCtrl->SetItemText(i,1,_T(bufX));
G>            sprintf(bufStep,"%d",i);
G>            m_pListCtrl->SetItemText(i,2,_T(bufStep));
G>            delete []bufX;
G>            delete []bufY;
G>            delete []bufStep;
G>        }
G>

G>и почему?
G>Best regards?

Какой тип имеет сзачение m_dArRetY[i].
1) double : sprintf(bufY,"%lf",m_dArRetY[i]);
2) float : sprintf(bufY,"%f",m_dArRetY[i]);

И еще — корректнее писать вменсто sprintf(bufStep,"%d",i); — sprintf(bufStep,"%ld",i);
хотя long и int имеют один и тотже размер
Re: Правильно или нет?
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 08.11.02 07:09
Оценка:
Здравствуйте gbush, Вы писали:

Продолжая все выше сказанное:
G> char *bufX = new char[10];
...
G> sprintf(bufX,"%f", m_dArRetX[i]);
...
G> delete []bufX;


Предположим, что m_dArRetX[i] содержит некую переменную типа double. По правилу обработки формат спецификатора %f размер результата может заметно превышать 9 + 1 символ. Таким образом, если sprintf вернет число больше, чем (размер буффера -1), то ты попал Оператор delete[] уже эту память удалить не сможет, а, соответственно, ты получишь какой-нибудь AV.
Алексей Кирдин
Re[2]: Правильно или нет?
От: gbush  
Дата: 08.11.02 08:23
Оценка:
Здравствуйте Андрей Тарасевич, Вы писали:

АТ>Во-первых, если буферы у тебя известного на стадии компиляции размера, то зачем выделять их в динамисеской памяти? Почему не в автоматической?


Нет буферы не извесны на стадии компиляции.

АТ>В-третих, применение макро '_T' к чему-либо, кроме строкового или символьного литерала — полная бессмыслица.

Вдруг полезут иероглифы.
Далее я периписал и боюсь, что опять не правильно

        size_t nRowNum = m_dArRetX.size();
        for(long i=0;i<nRowNum;i++)
        {
            char *strbuf = new char;
            sprintf(strbuf,"%lf",m_dArRetY[i]);
            m_pListCtrl->InsertItem(i,strbuf);
            sprintf(strbuf,"%lf",m_dArRetX[i]);
            m_pListCtrl->SetItemText(i,1,strbuf);
            sprintf(strbuf,"%ld",i);
            m_pListCtrl->SetItemText(i,2,strbuf);
            delete strbuf;
        }
Все хорошо кончается, что кончается ещё лучше...
Re[2]: Правильно или нет?
От: Павел Кузнецов  
Дата: 08.11.02 08:51
Оценка:
Здравствуйте Klestov, Вы писали:

K>Какой тип имеет сзачение m_dArRetY[i].

K>1) double : sprintf(bufY,"%lf",m_dArRetY[i]);
K>2) float : sprintf(bufY,"%f",m_dArRetY[i]);

Эта рекомендация не имеет никакого смысла:

1) флаг l перед спецификаторами a, A, e, E, f, F, g, или G игнорируется; не игнорируется флаг L, но Lf означает, что аргумент имеет тип long double; просто f означает double (см. ISO/IEC 9899:1999 7.19.6.1/7);

2) аргумент типа float при передаче в функцию с переменным числом параметров всегда преобразуется к double (см. ISO/IEC 14882:1998 п. 5.2.2/7 или ISO/IEC 9899:1999 6.5.2.2/6).
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Правильно или нет?
От: Klestov  
Дата: 08.11.02 15:33
Оценка:
Здравствуйте gbush, Вы писали:

G>Здравствуйте Андрей Тарасевич, Вы писали:


АТ>>Во-первых, если буферы у тебя известного на стадии компиляции размера, то зачем выделять их в динамисеской памяти? Почему не в автоматической?


G>Нет буферы не извесны на стадии компиляции.


АТ>>В-третих, применение макро '_T' к чему-либо, кроме строкового или символьного литерала — полная бессмыслица.

G>Вдруг полезут иероглифы.
G>Далее я периписал и боюсь, что опять не правильно

G>
G>        size_t nRowNum = m_dArRetX.size();
G>        for(long i=0;i<nRowNum;i++)
G>        {
G>            char *strbuf = new char;
G>            sprintf(strbuf,"%lf",m_dArRetY[i]);
G>            m_pListCtrl->InsertItem(i,strbuf);
G>            sprintf(strbuf,"%lf",m_dArRetX[i]);
G>            m_pListCtrl->SetItemText(i,1,strbuf);
G>            sprintf(strbuf,"%ld",i);
G>            m_pListCtrl->SetItemText(i,2,strbuf);
G>            delete strbuf;
G>        }
G>



char *strbuf = new char;

Массив из одного элемента

Length = XXX
char *strbuf = new char [Length];
Re[4]: Правильно или нет?
От: gbush  
Дата: 08.11.02 20:27
Оценка:
Здравствуйте Klestov, Вы писали:

K>

K>char *strbuf = new char;

K>Массив из одного элемента


K>Length = XXX

K>char *strbuf = new char [Length];
Да я согласен, что это бред, но почему в ListGrid я вижу полное значение чисел из нескольких символов.
И пожалуйста научите, как выделить память ровно столько, сколько нужно под эти значения чисел. И главное экономно и правильно.
Да и м.б ссылку где указатели хорошо разобраны.
Ничего, что я так?
Все хорошо кончается, что кончается ещё лучше...
Re[2]: Правильно или нет?
От: Andrew S Россия http://alchemy-lab.com
Дата: 08.11.02 22:20
Оценка:
А при чем здесь delete? В этом случае он получит AV (или int3) еще при попытке sprintf записать в невыделенную память...

Kaa>Предположим, что m_dArRetX[i] содержит некую переменную типа double. По правилу обработки формат спецификатора %f размер результата может заметно превышать 9 + 1 символ. Таким образом, если sprintf вернет число больше, чем (размер буффера -1), то ты попал Оператор delete[] уже эту память удалить не сможет, а, соответственно, ты получишь какой-нибудь AV.


Kaa>
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: Правильно или нет?
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 09.11.02 09:39
Оценка:
Здравствуйте Andrew S, Вы писали:

AS>А при чем здесь delete? В этом случае он получит AV (или int3) еще при попытке sprintf записать в невыделенную память...


На практике (моей) выяснено, что не получит. Перезапись, как и перечтение — очень коварный зверь, который достаточно трудно бывает отловить. Часто такие примерно рабоатющие куски кода приводят к помешательству программиста, просмотру всех исходников, потому как являются причиной неработоспособности релизной версии (часто, не всегда), при работающей дебажной. При этом перечтения содержатся и там, и там, но и релизная версия при некоторых условиях умудряетс япроезжать (на этой неделе 2 таких поймал ).

Проведи эксперимент, если не веришь. Падение происходит при перечтении/записи (ну, при нежесткой, пару байт, там, 10 байт) часто только при высвобождении памяти. (Ну, я про винду, а не вообще )
Алексей Кирдин
Re[4]: Правильно или нет?
От: Andrew S Россия http://alchemy-lab.com
Дата: 09.11.02 13:58
Оценка:
На самом деле это сильно зависит от компилятора и виндовс. На 9х можно и килобайтом обшибиться — они не заметят. На 2000-х у меня обычно отлавливается и один байт сразу при записи/чтении... А для пущего удовольствия есть Bounds Checker.


Kaa>Проведи эксперимент, если не веришь. Падение происходит при перечтении/записи (ну, при нежесткой, пару байт, там, 10 байт) часто только при высвобождении памяти. (Ну, я про винду, а не вообще )
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[5]: Правильно или нет?
От: GvozdodeR  
Дата: 09.11.02 21:56
Оценка:
Здравствуйте gbush, Вы писали:

G>Здравствуйте Klestov, Вы писали:


K>>

K>>char *strbuf = new char;

K>>Массив из одного элемента


K>>Length = XXX

K>>char *strbuf = new char [Length];
G>Да я согласен, что это бред, но почему в ListGrid я вижу полное значение чисел из нескольких символов.
G>И пожалуйста научите, как выделить память ровно столько, сколько нужно под эти значения чисел. И главное экономно и правильно.
G>Да и м.б ссылку где указатели хорошо разобраны.
G>Ничего, что я так?

самый правильный способ для C++:

#include <sstream>

    long nRowNum = m_dArRetX.size();
    for(long i=0;i<nRowNum;i++)
    {
        std::ostringstream sstr;
        sstr << m_dArRetY[i];
        m_pListCtrl->InsertItem(i,sstr.str().c_str());
        sstr.str(std::string());

        sstr << m_dArRetX[i];
        m_pListCtrl->SetItemText(i,1,sstr.str().c_str());
        sstr.str(std::string());

        sstr << i;
        m_pListCtrl->SetItemText(i,2,sstr.str().c_str());
    }
Re[3]: Правильно или нет?
От: Аноним  
Дата: 10.11.02 07:53
Оценка:
Здравствуйте Andrew S, Вы писали:

AS>А при чем здесь delete? В этом случае он получит AV (или int3) еще при попытке sprintf записать

> в невыделенную память...

подобные вещи генерируются, когда получается выход за пределы памяти, с которой работает "железо":
сегменты, страницы. В случае же с new и malloc,alloc etc память выделяется меньшими блоками из
предварительно выделенного бОльшего хипа. В этом случае возможна ситуация, когда произойдет
"перезаписывание" или "наползание" на некоторую рабочую структуру runtime библиотеки или же
на другие данные приложения, но выхода за пределы аппаратно контролируемой памяти не произойдет. Соответственно ошибка вылезет не сразу, а потом, при обращении к "покалеченным" данным
runtime'а (обращение к функциям работы с памятью) или же "покалеченным" данным приложения.
В случае с sprintf память скорее всего уже выделена.
т.е. если написать
char *pc_buffer = new char[ 4 ];
strcpy( pc_buffer, "0123456789" );
delete pc_buffer;
ошибка возникнет не на strcpy, а на delete или еще позже.

немного коряво получилось... но вроде все обстоит именно так
Re[4]: Правильно или нет?
От: Andrew S Россия http://alchemy-lab.com
Дата: 10.11.02 14:19
Оценка:
Немного не так. На самом деле в дебаговой версии рантайм делает еще некие телодвижения для проверки правильности использования памяти. Но даже не в этом дело.

А>В случае с sprintf память скорее всего уже выделена.

А>т.е. если написать
А> char *pc_buffer = new char[ 4 ];
А> strcpy( pc_buffer, "0123456789" );
А> delete pc_buffer;
А>ошибка возникнет не на strcpy, а на delete или еще позже.

А вот тут ошибка скорее всего в ДНК — delete должно быть с [].
http://www.rusyaz.ru/pr — стараемся писАть по-русски
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.