Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: AnsiString.Length() почему ноль?  (Прочитано 25130 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Arct
Участник

ru
Offline Offline
Пол: Мужской
Злое


« : 02-01-2010 13:09 » 

Туплю,  Здесь была моя ладья... что-то:почему всегда ноль?
      
Код:
AnsiString in="";
        char key=0;
        do
        {
                cout<<"Enter a number and press <Enter>:"<<endl;
                cin>>in.c_str();
                if(in.Length()==0)
                        }
                        cout<<"You have not entered the number!\a"<<endl;
                        continue;
                        }
                ...

         }while(key)
Причем значение введенное выводится нормально
То есть:
Код:
cout<<in.c_str();
Выводит то, что введено Здесь была моя ладья...
Ткните мордой лица в ошибку, пожалуйста. Скромно так...
« Последнее редактирование: 02-01-2010 15:04 от Arct » Записан

Пройди свой путь, ты не сумеешь назад всё вернуть...
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 02-01-2010 19:43 » 

c_str() предназначено для вывода, а не для ввода. Строка просто не знает, что ты в её буфер что-то записываешь.
Не знаю, можно ли прочитать сразу в AnsiString. возможно, придётся читать через std::string
Код:
std::string str;
std::cin >> str;
AnsiString in = str;
или типа того.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 02-01-2010 20:41 » 

Arct, у тебя грубая ошибка! Метод c_str() возвращает указатель на константную строку (char*), но это не буфер ввода.
Ознакомься с документацией на AnsiString.

Код:
char* __fastcall c_str() const;
Цитата
The c_str method is intended primarily for reading the value of the AnsiString. To modify the string’s value, use the [] operator or AnsiString methods such as Insert and Delete.
« Последнее редактирование: 02-01-2010 20:47 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Arct
Участник

ru
Offline Offline
Пол: Мужской
Злое


« Ответ #3 : 03-01-2010 07:01 » 

Arct, у тебя грубая ошибка! Метод c_str() возвращает указатель на константную строку (char*), но это не буфер ввода.
Ознакомься с документацией на AnsiString.

Код:
char* __fastcall c_str() const;
Цитата
The c_str method is intended primarily for reading the value of the AnsiString. To modify the string’s value, use the [] operator or AnsiString methods such as Insert and Delete.
Т.е. c_str() возвращает указатель на значение объекта AnsiString?
Тогда почему выводит? Здесь была моя ладья... Если это константа?
Видимо все так не константное значение...
Ладно возьму лопату Улыбаюсь

Да, возвращает указатель, на константную строку, единственное предположение которое возникает, что область памяти выделенная под эту строку, не затирается по этому и выводит, но почему компилятор позволяет применять к ней запись?
« Последнее редактирование: 03-01-2010 08:10 от Arct » Записан

Пройди свой путь, ты не сумеешь назад всё вернуть...
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #4 : 03-01-2010 11:47 » 

Arct,
Цитата
Т.е. c_str() возвращает указатель на значение объекта AnsiString?
да.

Цитата
Тогда почему выводит?  Если это константа?
Видимо все так не константное значение...
Есть инструкция по эксплуатации, компилятор с линкером обязуются (в меру своих сил Улыбаюсь ) дать правильный результат, но при условии соблюдения программистом правил (инструкций, стандартов и т.д.). Если ты правила не соблюдаешь - это твоя проблема! Дело в том, что скорее всего тебе вернули не просто данные абъекта, а ВНУТРЕННИЙ БУФЕР! (это го не гарантировано документацией, но реализация на 99% такова). Ты как варвар, в этот буфер напрямую что-то пишешь (заметь AnsiString о твоем коварстве даже не догадывается, ты ж ему не говоришь что ты там такое творишь). Таким образом, AnsiString в полной уверенности, что его буфер ПУСТОЙ, о чем он тебе и рапортует значением in.Length()==0. При этом если ты просишь AnsiString показать тебе свой буфер, то он тебе его и возвращает (заметь он ничего в нем не поменял, поскольку ты никаких действий, по мнению AnsiString с ним не производил), ну понятно, что там лежит то, что ты туда запихнул. Кстати, чисто для эксперимента, если ты после своего насилия над константным буфером легально запишешь в AnsiString данные ну например "hello", а потом вызовешь in.c_str(), то я на 99% уверен, что он вернется тебе только "hello", без тех данных, что ты туда нелегально засунул.

Цитата
но почему компилятор позволяет применять к ней запись?
если компилятор позволяет писать в константный буфер без преобразования его к неконстантному (подобные преобразования уже лежат на совести программиста), то это просто плохой компилятор (правильный компилятор не даст)
Записан

С уважением Lapulya
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #5 : 03-01-2010 14:35 » 

Цитата
если компилятор позволяет писать в константный буфер без преобразования его к неконстантному

а никто, кстати, и не делал возвращаемый указатель констаетным тут
Цитата
Код:
char* __fastcall c_str() const;
указатель то вернётся изменяемый, но из функции, которую разрешено вызывать для константного объекта. Вот тут и кроется ошибка разработчиков (хотя, им так могло понадобиться, и никак иначе)

Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 03-01-2010 18:07 » 

Леш, никакой ошибки тут нет: сказано же, что указатель на константное значение и менять его нельзя.
Быстрее всего, компилятор ругается (warning - не error!), но в настройках проекта не все сообщения разрешены для вывода.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Arct
Участник

ru
Offline Offline
Пол: Мужской
Злое


« Ответ #7 : 04-01-2010 14:25 » 

Быстрее всего, компилятор ругается (warning - не error!), но в настройках проекта не все сообщения разрешены для вывода.
В настройках проекта "full debug", т.е. warning - all.
Так что, не ругается он Здесь была моя ладья...
Записан

Пройди свой путь, ты не сумеешь назад всё вернуть...
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 04-01-2010 14:58 » 

Проверил на BCB6: удивительно, но компилятор молчит. Если переключить режим совместимости на любой другой, кроме Borland, то не выпадают множественные ошибки в заголовках - до компиляции проблемного места даже не доходит, т.к. компиляция останавливается после 26 ошибок. Если же создать консольное приложение, не использовать VCL библиотек (создал char const *s = "12345" и пытался модифицировать данные) и переключиться на совместимость с ANSI, то получаем:

Цитата
E2024 Cannot modify a const object
« Последнее редактирование: 04-01-2010 15:00 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #9 : 04-01-2010 16:06 » 

погодите, погодите... если мембер объявлен как (я чего-то внимания не обратил)
Код:
char* __fastcall c_str() const;
так он возвращает не константную строку, поэтому компилятор и молчит, все чин чинарем, просто тот, кто эту функцию писал, обязан был возвращать константную строку (но он этого не сделал, ну да его проблемы, хотя во-первых надо делать защиту от "дурака", а во-вторых не очень хорошо, что класс имеет этот метод как константный + возвращает СВОЙ буфер и возвращает его не константным... имхо не кузяво). Главное что в документации написано, что буфер можно только читать, то что возвращаемое значение не защитили это отдельная песня.

ЗЫ в С# ваще нет модификатора const в том смысле, в котором мы его обсуждаем и ничего... народ стонет, но пишет...
Записан

С уважением Lapulya
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 04-01-2010 16:19 » 

Константным может быть как указатель, так и данные.

char * - неконстантый указатель на неконстантые данные. Делать с ними можно что угодно.
const char *  - указатель на константные данные. Указатель менять можно, но данные через этот указатель менять нельзя.
char * const - константный указатель. Данные менять можно, указатель - нельзя.
const char * const  - константный указатель на константные данные. Менять ничего нельзя.

Как я выше написал, компилятор Борланда по умолчанию работает по своим собственным соглашениям "Borland C++" и подобные махинации не считает недопустимыми. При переключении его в совместимость с ANSI C++ он начинает ругаться при несоответствии объявлений и действий.

Т.е. по соглашению Borland изменять буфер AnsiString можно, но для этого надо:
1. Задать размер AnsiString.
2. Получить указатель на буфер и модифицировать его содержимое в пределах его размера.
3. Перезадать размер AnsiString по размеру реальных данных. При этом указатель, полученный в п.2. становится недействительным.

Важно помнить, что AnsiString не является аналогом std::string. Это аналог паскалевской строки, облаченной в классовую оболочку. В Delphi (откуда родом AnsiString и WideString), это тип-строка и не более, а все манипуляции осуществляются набором функций, не связанных ни с каким классом. В BCB они порешили объединить их в класс.
« Последнее редактирование: 04-01-2010 16:32 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #11 : 04-01-2010 16:46 » 

RXL,
Цитата
Константным может быть как указатель, так и данные.

char * - неконстантый указатель на неконстантые данные. Делать с ними можно что угодно.
const char *  - указатель на константные данные. Указатель менять можно, но данные через этот указатель менять нельзя.
char * const - константный указатель. Данные менять можно, указатель - нельзя.
const char * const  - константный указатель на константные данные. Менять ничего нельзя.
да кто бы спорил... я ж про конкретный случай говорю, а там как раз не константная строка, и при этом константный мембер класса, вот же
Код:
char* __fastcall c_str() const;

. хотя я не понял как вяжется это
Цитата
Т.е. по соглашению Borland изменять буфер AnsiString можно, но для этого надо:
1. Задать размер AnsiString.
2. Получить указатель на буфер и модифицировать его содержимое в пределах его размера.
3. Перезадать размер AnsiString по размеру реальных данных. При этом указатель, полученный в п.2. становится недействительным.
и это
Цитата
The c_str method is intended primarily for reading the value of the AnsiString. To modify the string’s value, use the [] operator or AnsiString methods such as Insert and Delete.
?
на мой взгляд одно другому противоречит...
« Последнее редактирование: 04-01-2010 16:49 от lapulya » Записан

С уважением Lapulya
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 04-01-2010 16:51 » 

мне тоже непонятно, зачем написали использовать [] и одновременно объявили

char* __fastcall c_str() const;

вместо

const char* __fastcall c_str() const;


загадка )) Или очепятка
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 04-01-2010 19:22 » 

Извиняюсь, вначале попутал и утверждал неверное. Да, c_str() возвращает константный указатель на неконстантные данные.

Вяжется просто:
1. Использовать строку c_str() кроме как для чтения не рекомендуется согласно доке.
2. Компилятор это не запрещает. Он не запрещает и изменять указатель...

Я дал пример, как более-менее корректно реализовать вопрос темы.
Другой вариант, полностью корректный - создать отдельный буфер в стиле Си и потом уже присвоить его объекту AnsiString.

Код:
AnsiString str;
char * buffer = new char(100 + 1);

// ввод нуль-терминированной строки.

str = AnsiString(buffer);
delete[] buffer;
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #14 : 04-01-2010 20:43 » 

RXL,
Цитата
Да, c_str() возвращает константный указатель на неконстантные данные.
а где там константный указатель?
Код:
char * f() const;
это насколько я помню константный мембер класса, не более того... или Borland тут "на высоте"?

тут дело не в том позволяет это компирел или нет, а в том "законно" ли такое действо или нет, ну типичный пример вызываем c_str(), получаем буфер, допустим он ан 50 символов и пишем в него 60, как результат имеем ЖОПУ, стало быть так делать зельзя!!!, то что компилер этого не запрещает, так он вообще много чего не запрещает. В доку написано для чтения - значит только для чтения, в доке ничего не написано , что это внутренний буфер объекта, стало быть это вообще левая память может быть.... временно одолженная у аллокатора и т.д. и т.п. Итого, так писать нельзя (если в доке не написано обратного, но я этого пока не видел)
Записан

С уважением Lapulya
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 04-01-2010 21:03 » new

lapulya, убедил Улыбаюсь

Буфер в любом случае необходимо брать достаточный, и ввод ограничивать этими пределами. Либо брать многократно больший буфер и молиться, что не будет переполнения.

Замечу, в их доке много чего не написано. На практическом опыте подтверждаю, что c_str действительно возвращает внутренний буфер. Он валиден до удаления или изменения объекта.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #16 : 04-01-2010 21:13 » 

RXL, да, не... геморрой это... то что на практике сегодня, не на практике завтра... не комильфо это, подписываться на текущую реализацию чего бы то ни было, что не в твоей власти(о не на описание, тут вроде четко сказано как менять значение строки).
Записан

С уважением Lapulya
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 04-01-2010 21:18 » 

lapulya, если ты работаешь на разных версиях BCB, то несомненно опираться на недокументированные возможности нельзя. У меня ситуация проще: используются компоненты, не работающие с BCB выше 6 и рости некуда (да и нет необходимости).
Даже используя все компоненты и классы строго по доке, не удастся застраховаться от различия от версии к версии. Например, 3 года назад переносил проект из BCB5 в BCB6 и поведение TComboBox изменилось - пришлось по всем модулям пробежаться и подправить логику.
« Последнее редактирование: 04-01-2010 21:21 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #18 : 04-01-2010 23:27 » 

RXL, но это частный подход (т.е. в тепличных условиях это работает и то с оглядкой, я ж еще перед тем как в этот буфер писать должен удостовериться, что в нем необходимое место есть, а если нет, то тут совсем другой подход...), а если кто пишет что-то что потом будет компилиться под другие компиляторы/версии или будет куда портировать... т.е. фактически это хардкод, что не есть гуд.

на самом деле я тут высказываю свое мнение, но можно поступать как угодно Улыбаюсь я ж не заставляю...
Записан

С уважением Lapulya
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #19 : 05-01-2010 15:41 » 

Программы под Borland существуют в своем замкнутом мирке и напрямую не портируются. Была одна попытка сделать что-то совместимое - библиотека CLX (как замена VCL), архитектурно совместимая с ранними версиями Qt, но почему-то провалилась.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #20 : 05-01-2010 20:22 » 

Хммм, ну ладно... делайте что хотите  А черт его знает...
Записан

С уважением Lapulya
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines