Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  11:57[Войти] | [Зарегистрироваться]
Ответ на вопрос № 45926

17-10-2006 02:00
День добрый.

Прошу простить меня за наглость, что задаю такой бестолковый вопрос, но я немогу найти решения.

В чем здача?
Есть структруры:

  TDTime = record
    {$A1+}
    FMin    : Byte;
    FHour  : Byte;
    FMs    : Byte;
    FSec    : Byte;
    FYear  : Word;
    FDay    : Byte;
    FMonth  : Byte;
    {$A1-}
  end;

  TParameter = record
    {A1+}
    FCode  : Word;
    FValue  : Single;
    FStatus : Word;
    {A1-}
  end;


Мне надо выделить буфер который будет равным SizeOf(TDTime) + (SizeOf(TParameter) * CountParams) в байтах,где CountParams число описывающее кол-во параметров и оно всегда разное. Т.е. буфер надо создавать динамически!
Формат буфера:
Сначала 1 объект структуры TDTime, а после CountParams объектов структуры TParameter.

Хотелось бы породить буфер в байтах, а после присвоить нужные значения указателю на TDTime и указателю на массив TParameter.

В чем сложности, я сделал:


var
dt : TDTime
param : array of TParameter;
tmp : Pointer;
begin
  p := SizeOf(TDTime) + (SizeOf(TParameter) * CountParams);
  td := p;
  param := Pointer(Integer(p) + SizeOf(TParameter));


но при чтении из файла с помощью АПИшки ReadFile работа с буферами с программными конструкциями вида:


td.FYears;
td.FMin;

for I to CountParams - 1 then
begin
  param[I].FCode;
  param[I].FValue;
end;


не получается!

Прошу подсказать мне, буду рад за любую оказанную помощь!

зы: Книги читаю! :))) Intuit.ru - на курс по паскалю записался, но мне срочно надо!

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

21-11-2006 01:20 | Комментарий к предыдущим ответам
Согласен с Ins'ом, то, как ведет себя Loki свидетельстует о том, что он либо не умеет признавать свои ошибки, либо до сих пор не понимает, что ему пытались объяснить - если второй вариант имеет место быть, то это уже слишком долго для кратковременного заблуждения. Следовательно, переубедить его не представляется возможным, да и смысла нет. Объективно он неправ. То, что он не принесет своих извинений это точно, он ему не надо. И хотя я недолюбливаю Антона Григорьева все равно могу беспристрастно признать, что в его постах в этом топике не содержится погрешностей, они абсолютно соответсвуют действительности. Каждый кто разбирается в расммотренных ниже вопросах с этим согласится и не обратит внимания на выпады Loki, а для тех, кто не понимает думаю будет достаточно сравнить стили общения оппонентов. Так, что никакого урона достоинству и авторитету никому, кроме Loki эта дискуссия не принесла.

20-11-2006 11:07 | Комментарий к предыдущим ответам
Антон Григорьев
А может ну его? Закрывайте это обсуждение, оно всех уже достало. Этот человек просто не хочет понять и признать свою неправоту. И извиняться он тоже не станет. Ему кажется, что таким поведением он добьется уважения к себе. Все, кто видел или еще увидет эту дискуссию, понимает, кто здесь прав, а кто нет, так что его сомнения в ваших (и в наших) умственных способностях вряд ли отразятся на вашем авторитете.

20-11-2006 08:05 | Комментарий к предыдущим ответам
У меня есть предложение: тему закрыть за очевидной ненадобностью, а дальнейшую переписку вести по e-mail-у

Я возражаю. Мои умственные способности и образованность были поставлены под сомнения публично, поэтому я хочу добиться публичных же опровержений. Частная переписка меня не устраивает.

20-11-2006 08:01 | Комментарий к предыдущим ответам
Loki:

Забыл написать в своём прошлом сообщении:

В то время как в ответе почему то всплывают какие то непонятные простые типы, про которые в моем ответе речи даже не шло.

Если вы не помните, что вы писали, то хотя бы попытайтесь это скрыть. Вот цитата из вашего сообщения от 25-10-2006 06:59

Хотелось бы отметить такой факт, что, например, процедура New только резервирует память для переменной, но не очищает ее. Для простых типов это, как правило, не страшно

Как видите, термин "простые типы" придумали вы, до вас его тут никто не употреблял, так что теперь не надо говорить, что они вам непонятны.

Теперь перехожу к новому сообщению.

Да ну? Не буду ничего изобретать нового, просто цитата:

Но функцией New можно инициализировать только предопределенные типы указателей. Типы pointer - увы! - она не инициализирует, потому что не знает, сколько памяти нужно под нее отводить. Проверьте сами - указатель типа pointer после использования этой функции равен nil.

Или скажете, что вы какой-то другой вопрос имели ввиду?


У меня такое ощущение, что теперь я наконец-то понимаю, что вы хотели этим сказать. Только если вы хотите, чтобы вас понимали быстрее, нужно использовать правильные термины. Например, под инициализацией все понимают первоначальное присваивание нулевого (или условно нулевого) значения, а New (равно как и GetMem и AllocMem) делает совсем другое - выделяет память и заносит указатель на выделенный блок в переданную переменную. Из-за того, что вы неправильно употребили этот термин, вас никто не понял - все подумали, что вы имеете ввиду поля типа "указатель", размещённые в записи, память для которой выделяется с помощью New. Отсюда и вся путаница.

Я в очередной раз ловлю вас на передергивании фактов: я говорил про ПЕРЕМЕННУЮ, а вовсе не про ее реализацию. Все, что имелось ввиду, так это то, что под переменную в памяти отводится 12 байт, а указатель указывает на первый из них, а вовсе не на первый символ. Разница была только в том, что поля длины и ссылок выделяются при создании строки, а не так как я думал. Вот и все. Не понять этого вы не могли, как бы вам не хотелось это представить.

Несмотря на ваши слова, я этого по-прежнему не понимаю. Я не знаю никаких указателей, которые указывали бы на сами переменные, за исключением тех, которые программист заводит явно. Из-за этого вся приведённая выше фраза представляется мне бессмысленным набором слов.

А ведь вы лукавите, заявляя, что я оставил без внимания ваши аргументы:


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


Вы считаете это достаточным ответом на мой разбор ваших аргументов? Напоминаю, о чём шла речь: что переменные типа "динамический массив" и "строка", а также поля структур, имеющие данные типы, автоматически инициализируются. Вы привели кучу аргументов против этого, в которых речь шла совсем о другом - об инициализации статических массивов структур, содержащих только нефинализируемые типы. Моё главное утверждение заключалось в том, что приведённые вами ссылки относятся совсем не к тем ситуациям, о которых идёт речь. Именно это утверждение вы не прокомментировали. Вы должны были либо согласиться с тем, что приведённые вами примеры к делу не относятся, либо осоприть это утверждение и попытаться доказать, что относятся. Вы не сделали ни того, ни другого.

Скажите, Антон, у вас никогда не возникала при работе в Delphi ситуация, когда вы собираетесь произвести компиляцию, а вместо того вдруг выскакивает сообщение об ошибке в какой-то дельфийской библиотеке с рекомендацией сохранить файлы и перезагрузить среду программирования? Или, например, при попытке сохранить проект выскакивает примерно такое же сообщение? Вопрос этот имеет прямое отношение к FillChar исходя из тезы о наличии ошибок в среде программирования, признанных даже разработчиками системы. Вы старательно обошли этот вопрос, как, впрочем, и некотоые другие, что однозначно говорит о вашем нежелани ни под каким соусом признавать свою неправоту.

Было несколько раз. Вот только логика у вас хромает. Дано: в программе есть некоторая ошибка. Вывод: надо было использовать FillChar. Блестяще! Чем вы можете обосновать то, что эта ошибка связана именно с неиспользованием FillChar, а не с чем-то другим? Вот мой опыт показывает, что такие ошибки чаще всего бывают связаны с обращением к объекту, который уже удалён. Но всё равно я не стану утверждать, что в каком-то конкретном случае проблема заключается именно в этом, пока не разберусь с этим случаем детально.

Скажите, Антон Григорьев, у вас никогда ны было такого, чтобы синие точки трассировки оказывались расположены не в тех местах, где находятся операторы? У меня (думаю, что и не только у меня) даже были случае, когда точки оказывались вообще расположены на пустых строках или на заголовках процедур. Как вы думаете, почему?

Что, неужели тоже из-за FillChar? И вы берётесь доказать это?

Если в вашем лексиконе преобладают слова "дебил", "недоумок", "придурок" и прочие - и как вы можете потом обижаться на "детей лейтенанта Шмидта" и (уж тем более!) "юношу"? Вас никогда не обвиняли в лицемерии?

Между мной и вами есть огромная разница. Вы уже употребили "детей" и т.п. по отношению к оппонентам, а я лишь предложил вам рассмотреть гипотетическую ситуацию с употребленим таких слов. При этом я никогда не утверждал (и не утверждвю сейчас), что вы таких слов заслуживаете. Неужели программист не может понять разницу между конкретной ситуацией, и ситуацией, рассмотриваемой абстрактно?

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

Нет, это не переход на личности. Переход на личности - это оценка личности в целом, а даже очень негативная оценка отдельного высказывания ещё не характеризует личность в целом. Самые умные представители человечества за свою жизнь сказали немало глупых фраз. Так что когда говорят, что ваша фраза глупа, под этим совсем не обязательно подразумевается, что вы в целом тоже глупы.

Что касается использования нецензурной лексики - я видел здесь только один случай - в сообщении Banderas'а от 01-11-2006 07:32. Он получил за это предупреждение - см. моё сообщение от 04-11-2006 01:24, предпоследний абзац. Если вам известны другие случая использования ненормативной лексики, которые я вдруг пропустил - ткните меня носом, и я немедленно приму меры.

Вообще то я уже сказал, что отвлекся по работе и сформулировал вопрос не правильно. Но сейчас уже не помню, что именно хотел спросить.

Вы не просто хотели спросить, вы спросили. Спросили в своём сообщении от 30-10-2006 08:49 со слов "Однако как вы объясните следующее". Я дал своё объяснение в ответе от 31-10-2006 04:06, со слов "Я тоже проверил, и получил другой результат". Можете освежить память.

Вообще то я уже несколько раз указывал вам на ваши недостатки, однако вы так упорно не хотите их признавать, что имеете ли право требоувать этого от других?

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

Кстати, не ответив на мой вопрос 30056, переведя стрелки на какую то "грязноту", вы тем самым просто показали, что ваш опыт работы с Дельфи не в пример меньше моего.

А у вас, видимо, не в пример меньше моего опыта в использовании формальной логики. Да, я не сталкивался с такой ситуацией, которую вы описали. Но делать из этого такие глобальные выводы - это очень смело. Думаю, если покопаться, то и я мог бы привести вам не один десяток ситуаций, с которыми я сталкивался, а вы - нет. Только это тоже ничего не докажет, а потому заведомо бессмысленно.

А для приведения примеров мне придется копаться в своих старых искходниках, дело это малоблагодарное. Не хотите верить - не верьте, дело ваше. Но я уже не раз указывал, что СНАЧАЛА НЕ ИСПОЛЬЗОВАЛ FILLCHAR пока не нарвался на глюки, которые удалось исправить именно филчаром).

Видите ли, если кто-то вам скажет нечто, что противоречит всему вашему опыту (например, что человек может летать без каких-либо приспособлений), вы в это сразу поверите? Или всё-таки захотите получить какие-то доказательства? Вот и я так же. Я знаю из документации, что ни динамические массивы, ни строки инициализировать вручную не надо. Я не сталкивался ни с одной ситуацией, когда это правило не выполнялось бы. Поэтому пока не увижу сам, всё равно не поверю. Поймите, со стороны вы сейчас выглядите как человек, который убеждает, что умеет летать, но показывать отказывается.

И зря вы думаете, что я вам не верю, будто FillChar может помочь в описываемых вами ситуациях. Я не верю, что причина - в ошибке компилятора, а не в чём-либо другом. Рассмотрим такой код:

type
  TStruct=record
    S:string;
    I:Integer
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  St:TStruct;
  B:Byte;
begin
  PInteger(@B)^:=$7FFFFFFF; {*}
  //FillChar(St,SizeOf(St),0);
  St.S:='abc'; {**}
end;



При его выполнении вы получите Access violation в строке {**}. Но стоит убрать комментарий с FillChar, и - о чудо! - ошибка исчезает (проверено в Delphi 7). Только происходит это не потому, что компилятор забыл проинициализировать St, а потому, что в строке {*} мы выполнили некорректную операцию и залезли в область памяти, занимаемой переменной St. Я слишком много видел случаев, когда собственные ошибки программист сваливает на неправильный компилятор. Просто хочу убедиться, что в вашем случае этого не происходит, и виноват действительно компилятор.

20-11-2006 07:55
У меня есть предложение: тему закрыть за очевидной ненадобностью, а дальнейшую переписку вести по e-mail-у

20-11-2006 06:30 | Комментарий к предыдущим ответам

Ну и что? В теме вопроса вообще не было New. New впервые упомянуто в ответе Крокодила от 17-10-2006 03:19, и там же было предложено заменить нетипизированный указатель на типизированный. Так что использование New по отношению к нетипизированному указателю - это уже ваши личные фантазии.


Да ну? Не буду ничего изобретать нового, просто цитата:


Но функцией New можно инициализировать только предопределенные типы указателей. Типы pointer - увы! - она не инициализирует, потому что не знает, сколько памяти нужно под нее отводить. Проверьте сами - указатель типа pointer после использования этой функции равен nil.


Или скажете, что вы какой-то другой вопрос имели ввиду?
Если самый первый - то в нем вообще не упоминались никакие подобные операторы.


Я бы указал, конечно :))) Но раз уж вы признали, что ошибались, когда утверждали, что такая переменая занимает 12 байт, считаю некорректным лишний раз напоминать об этом. Хотя, конечно, странно видеть, как быстро вы об этих своих утверждениях забыли.


Я в очередной раз ловлю вас на передергивании фактов: я говорил про ПЕРЕМЕННУЮ, а вовсе не про ее реализацию. Все, что имелось ввиду, так это то, что под переменную в памяти отводится 12 байт, а указатель указывает на первый из них, а вовсе не на первый символ. Разница была только в том, что поля длины и ссылок выделяются при создании строки, а не так как я думал. Вот и все. Не понять этого вы не могли, как бы вам не хотелось это представить.


На мою шутку вы разразились длиннющим комментарием, зато ту часть ответа, где я разбирал ваши "аргументы" по существу, вы совершенно оставили без внимания. И что я должен думать о таких методах ведения спора?


Скажите, вы понимаете только свои шутки? Шутки других людей вам сразу же кажутся оскорбительными? А ведь вы лукавите, заявляя, что я оставил без внимания ваши аргументы:


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


Скажите, Антон, у вас никогда не возникала при работе в Delphi ситуация, когда вы собираетесь произвести компиляцию, а вместо того вдруг выскакивает сообщение об ошибке в какой-то дельфийской библиотеке с рекомендацией сохранить файлы и перезагрузить среду программирования? Или, например, при попытке сохранить проект выскакивает примерно такое же сообщение? Вопрос этот имеет прямое отношение к FillChar исходя из тезы о наличии ошибок в среде программирования, признанных даже разработчиками системы. Вы старательно обошли этот вопрос, как, впрочем, и некотоые другие, что однозначно говорит о вашем нежелани ни под каким соусом признавать свою неправоту.


Если вы знаете другие, приведите их здесь, обсудим. Это действительно будет интересно. А подозревать компилятор, не имея конкретных фактов...


Скажите, Антон Григорьев, у вас никогда ны было такого, чтобы синие точки трассировки оказывались расположены не в тех местах, где находятся операторы? У меня (думаю, что и не только у меня) даже были случае, когда точки оказывались вообще расположены на пустых строках или на заголовках процедур. Как вы думаете, почему?


Надеюсь, вы не обидитесь, если я в очередной раз назову ваши обещания пустым трёпом? Я просто не знаю менее обидных слов, которые подошли бы к данной ситуации.


Добавим в эту копилку слово "трус", и однозначно идентифицируем ваш интеллектуальный уровень.


Очень грязный приём ведения спора. Вопрос №30056 не имеет отношения к тому, что здесь обсуждается. А вы хотите подвести это к формуле: "раз там ничего не понимаете, то и здесь вас слушать нечего". Повторяю: очень грязный приём.


Интересно, а к какому приему можно отнести фразу про треп и трусость? Да вы - верх честности и добропорядочности!


А ещё я знаю фильмы, в которых персонажи называют друг друга идиотами, кретинами, недоумками, дебилами и т.п. Если я применю одно из этих обращений к вам, а потом скажу, что это якобы просто цитата из фильма, вы сочтёте такое моё поведение корректным?

Вопрос не риторический, жду ответа.


Смотрите мой предыдущий ответ. Если в вашем лексиконе преобладают слова "дебил", "недоумок", "придурок" и прочие - и как вы можете потом обижаться на "детей лейтенанта Шмидта" и (уж тем более!) "юношу"? Вас никогда не обвиняли в лицемерии?


Ошибаетесь. В том ответе оценивались ваши слова. Перехода на личности в них не было. Вы же, назвав оппонентов детьми лейтенанта Шмидта, по сути дела назвали их мошенниками, т.к. всем известно, откуда эта фраза и что она означает.


Читайте мои предыдущие овтеты. Добавлю только: а на счет откровенного тыкания с заявлением о глупости или бредовости высказываний, с употреблением нецензурной лексики - это не переход на личности?


Я ответил, что уже дал объяснение, и после этого у вас эту тему как отрезало: несмотря на мои неоднократные напоминания и прямые обвинения вас в трусости и некомпетентности вы так и не соизволили ответить по существу. Странно, правда?


Вообще то я уже сказал, что отвлекся по работе и сформулировал вопрос не правильно. Но сейчас уже не помню, что именно хотел спросить. Этого неужели вам недостаточно? Я должен пасть ниц, воздеть руки к небу и воскликнуть: "О, великий Антон Григорьев! Каюсь, был не прав!" или еще что-то в этом роде? Вообще то я уже несколько раз указывал вам на ваши недостатки, однако вы так упорно не хотите их признавать, что имеете ли право требоувать этого от других? В отличие от вас некотоыре свои ошибки я все-таки признал.
(Кстати, не ответив на мой вопрос 30056, переведя стрелки на какую то "грязноту", вы тем самым просто показали, что ваш опыт работы с Дельфи не в пример меньше моего.И именно поэтому некотоыре выши высказывания, в частности, в отношении FillChar, я в серьез не воспринимаю. Впрочем, это уже личное ваше дело. А для приведения примеров мне придется копаться в своих старых искходниках, дело это малоблагодарное. Не хотите верить - не верьте, дело ваше. Но я уже не раз указывал, что СНАЧАЛА НЕ ИСПОЛЬЗОВАЛ FILLCHAR пока не нарвался на глюки, которые удалось исправить именно филчаром).


Просто потому, что вы слишком сильно на меня нападали в начале, чтобы я теперь мог просто забыть об этом вопросе.


Я? Нападал? Когда? Где?

20-11-2006 02:49
Loki:

Так что и библиотека VCL не всегда может являться истиной в последней инстанции.

Не путайте истину в последней инстанции и образец для подражания. Если вы хотите выяснить, как именно работает тот или иной участок кода VCL, можете ли вы назвать более надёжный источник получения информации, чем изучение этого кода? Другими словами, если из некоторого источника X вы получили информацию о том, что VCL работает так-то и так-то, а непосредственное изучение кода показывает, что это не так, то можете ли вы назвать такой X, которому вы в такой ситуации поверите?

В теме вопроса четко был указан НЕТИПИЗИРОВАННЫЙ указатель

Ну и что? В теме вопроса вообще не было New. New впервые упомянуто в ответе Крокодила от 17-10-2006 03:19, и там же было предложено заменить нетипизированный указатель на типизированный. Так что использование New по отношению к нетипизированному указателю - это уже ваши личные фантазии.

Укажите мне хоть одно место, где я бы утверждал, что реализация переменной-массива представляет собой что-то, отличное от указателя.

Я бы указал, конечно :))) Но раз уж вы признали, что ошибались, когда утверждали, что такая переменая занимает 12 байт, считаю некорректным лишний раз напоминать об этом. Хотя, конечно, странно видеть, как быстро вы об этих своих утверждениях забыли.

Во-первых, FillChar в чужом коде сам по себе ничего не доказывает - его могли поставить просто по незнанию. В вопросах иногда такое пишут! Так что я не стал бы вообще ссылаться на такие сомнительные авторитеты :))))

Здорово, как только появляются доказательства противного, они сразу объявляются неавторитетными!


Оченб интересно. Мой ответ содержал этот двухстрочный полушутливый комментарий. Затем шёл догий разбор приведённых вами ссылок по существу. По каждому упомянотому вами вопросу я детально написал, почему я не могу признать его аргументом, почему он не имеет отношения к нашему разговору. И что я вижу? На мою шутку вы разразились длиннющим комментарием, зато ту часть ответа, где я разбирал ваши "аргументы" по существу, вы совершенно оставили без внимания. И что я должен думать о таких методах ведения спора?

И, если вы считаете себя достаточно умными, ответьте, пожалуста на вопрос №30056.

Очень грязный приём ведения спора. Вопрос №30056 не имеет отношения к тому, что здесь обсуждается. А вы хотите подвести это к формуле: "раз там ничего не понимаете, то и здесь вас слушать нечего". Повторяю: очень грязный приём.

Почему вы проигнорировали мой вопрос на счет вашей уверенности в том, что компилятор всегда генерирует один и тот же код?

Потому что считаю его некорректным. Есть такое понятие - бремя доказательства. Доказывать нужно наличие эффекта, а не его отсутствие. Если вы утверждаете, что компилятор в каком-то случае работает не так, как это документировано, вы и должны привести пример такого случая. Потому что я могу сказать одно: пока я не столкнусь с конкретным случаем, в котором компилятор работает неправильно, я буду думать, что он работает правильно. А до сих пор единственный случай, который мне известен - это вот: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=759 Если вы знаете другие, приведите их здесь, обсудим. Это действительно будет интересно. А подозревать компилятор, не имея конкретных фактов... Ну, так можно начать подозревать компилятор, что он неверно выполняет сложение, присваивание и все прочие операции. Так вот, я утверждаю, что подозревать в чём-то компилятор, не имея конкретных фактов, просто глупо. А лично я таких фактов не имею.

Впрочем, я уже не в первый раз прошу вас предоставить мне конкретные примеры неправильного поведения компилятора. И вы даже сами вызвались это сделать - см. ваше сообщение от 01-11-2006 07:01. И где эти примеры? Надеюсь, вы не обидитесь, если я в очередной раз назову ваши обещания пустым трёпом? Я просто не знаю менее обидных слов, которые подошли бы к данной ситуации.

Вообще то все это – цитаты из фильмов, жаль, что вы этого не знаете.

Знаю. А ещё я знаю фильмы, в которых персонажи называют друг друга идиотами, кретинами, недоумками, дебилами и т.п. Если я применю одно из этих обращений к вам, а потом скажу, что это якобы просто цитата из фильма, вы сочтёте такое моё поведение корректным?

Вопрос не риторический, жду ответа.

Ко мне, кстати, некоторые товарищи тут куда как грубее обращались, возьмите самый первый абзац сего комментария,

Ошибаетесь. В том ответе оценивались ваши слова. Перехода на личности в них не было. Вы же, назвав оппонентов детьми лейтенанта Шмидта, по сути дела назвали их мошенниками, т.к. всем известно, откуда эта фраза и что она означает.

Но, "Враги, указывающие нам на наши недостатки, лучше, чем друзья, скрывающие их" (может, знаете, кто это сказал?).

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

А теперь вернёмся к эксперименту. Вспомним историю. Первый раз вы упомянули о нём в сообщении от 30-10-2006 08:49. Я в ответе от 30-10-2006 09:30 высказал предположение, что это может быть связано с отладчиком. Вы в ответе от 31-10-2006 02:58 стали убеждать меня, что проверили всё пошагово, да ещё и прочитали целую лекцию о том, как работать с отладчиком. Я проверил ваши результаты, обнаружил, что там всё совсем не так, и описал свои результаты и их толкование в сообщении от 31-10-2006 02:58. Вы этих моих слов не заметили, поэтому в своём сообщении от 01-11-2006 01:55 вы в грубой форме обвинили меня в том, что я не способен дать объяснение этому эксперименту. Да ещё и начали соответствующий абзац со слов "И самое главное". Я ответил, что уже дал объяснение, и после этого у вас эту тему как отрезало: несмотря на мои неоднократные напоминания и прямые обвинения вас в трусости и некомпетентности вы так и не соизволили ответить по существу. Странно, правда?

Почему же та тема, о которой вы увлечённо писали, которую называли самым главным, резко стала для вас неинтересной сразу после того как вы ознакомились с моим объяснением? Ответ очевиден: вы рассчитывали этим экспериментом посадить в лужу меня. Вот только поторопились и сели сам. И теперь вы усиленно делаете вид, что этот эксперимент (ещё недавно, по вашей же версии, "самое главное") - это какая-то мелочь, о которой вы даже толком не помните. И кем я должен считать вас после этого?

Я буду каждый раз возвращаться к этому вопросу до тех пор, пока вы либо не укажете на ошибку в моём объяснении, либо не согласитесь, что я был прав. Просто потому, что вы слишком сильно на меня нападали в начале, чтобы я теперь мог просто забыть об этом вопросе.

19-11-2006 13:32 | Комментарий к предыдущим ответам

Блин, Loki извините, ну просто полный бред, в любой параграф пальцем ткни - бред.


Если ты не понимаешь, что это и для чего, то это еще не значит, что это – бред. Не стоит так откровенно выставлять свою недалекость. Так говорят люди, которым просто нечего сказать, а сказать-таки хочется.


Это, конечно, не имеет никакого отношения к теме дискуссии, но все-равно прикольно.


Ну, непосредственно к теме не относится, напрямую относится к тому, что меня пытаются наставить на путь истинный ссылками на первоисточники. И мне глубоко по барабану, сколько у паука ног – хоть 25 (двадцать пять), и пусть не один, а десять переводчиков ошиблись, и пусть Аристотель сравнивал паука хоть с удавом, это не имеет никакого значения. Все, что я хотел подчеркнуть, так это то, что и великие ошибаются, что веками повторяемые истины в реальности могут ими не оказаться. Историю я слышал про пауков, количество ног значения не имеет, важен факт, что по Аристотелю оно не совпадало с реальным. (Ведь заставляете все разжевывать, а потом обижаетесь на «оскорбления»).
На счет «библиотеки VCL» могу сказать, что я читал в Интернете о том, что Borland признала, что некоторые ее классы и компоненты могут давать утечку памяти при своем функционировании или при разрушении. Так что и библиотека VCL не всегда может являться истиной в последней инстанции.


А применять New к (судя по всему) нетипизированному указателю - такое мне и в страшном сне не приснилось бы :))


В теме вопроса четко был указан НЕТИПИЗИРОВАННЫЙ указатель:



Но функцией New можно инициализировать только предопределенные типы указателей. Типы pointer - увы! - она не инициализирует, потому что не знает, сколько памяти нужно под нее отводить. Проверьте сами - указатель типа pointer после использования этой функции равен nil.


Опять какая-то ерунда. Во-первых, для инициализации указателя нулём не нужно знать размер данных, на которые он ссылается. Во-вторых, Initiflize ничего не делает с указателями простых типов, поэтому что там будет после New - непредсказуемо (я проверил - у меня действительно получался то nil, то другие произвольные значения).


В то время как в ответе почему то всплывают какие то непонятные простые типы, про которые в моем ответе речи даже не шло. И кто меня посмеет после этого обвинять в том, что я невнимательно читаю ответы?
Но, тем не менее, сам Антон Григорьев этим и другими ответами доказал, что функция AllocMem В НЕКОТОРЫХ СИТУАЦИЯХ лучше, чем New, потому что:
1). Она гарантированно очищает ВСЕ переменные структуры, приводя их к нулю, чего New не делает. И у меня еще не было случая, когда мне приходилось заполнять переменные какими-то другими, отличными от нуля, значениями (повторяю специально для тех, кто не понял с первого раза).
2) Она работает со всеми видами указателей: типизированными и не типизированными, в то время как New с нетипизированными указателями не работает, даже не смотря на то, что в дельфийском хелпе параметр этой функции объявлен как нетипизированный указатель:
    procedure New(var P: Pointer);
Да не введет в заблуждение это объявление всех остальных программистов: процедура New работает исключительно с типизированными указателями.

И вот еще интересно:


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


Конечно-конечно, как же можно опровергнуть человека, который не всегда дает ответы в тему? (предвижу радостный вопль оппонентов: а сам то, а сам то!!!)



человеку, который привёл так много цитат, грех обвинять других в ссылках на "авторитеты".


Вообще то с самого начала я совершенно не ссылался ни на какие авторитеты, вы первые начали. И чтобы хотя бы приглушить этот фонтан «авторитарности», я ВЫНУЖДЕН был бороться с вами вашими же методами. Меня то вы не слушаете, свято уверовав, что я всегда не прав (по крайней мере, у меня сложилось такое впечатление). Поэтому эту фразу я не могу расценивать иначе, кроме как попытку передернуть факты.


А вы дальше осмелитесь утверждать, что никогда никому не хамили? Меня зовут Антон, никакого отношения к Франции я не имею, и обращение "месье" расцениваю как оскорбление, потому что в таком контексте оно использовано с целью унизить.


Ну прямо как у Зиновия Высоковского в одной из его миниатюр (дело происходит во Франции): «Он говорит ему: Месье! Он его месьём обозвал». Интересно, а где вы увидели «унизительный» контекст? А в каком контексте вами было произнесено слово «трус»? В возвеличествующем? Вы таким образом меня похвалили? Хвалите себя подобными словами, я таким манером никогда ни к кому не обращался (по крайней мере, старался воздерживаться от таких высказываний).


Далее – к своим оппонентам вы обращаетесь "умники", "дети лейтенанта Шмидта", в своём ответе от 03-11-2006 07:39 назвали оппонета "синьор Буратино", а также испольовали другое унизительное в данном контексте обращение - "юноша". Что это, если не хамство? И разве за такое не нужно извиняться?


Если вы – не юноша, а девушка, то можете первым кинуть в меня камень. Вообще то все это – цитаты из фильмов, жаль, что вы этого не знаете. Ко мне, кстати, некоторые товарищи тут куда как грубее обращались, возьмите самый первый абзац сего комментария, или можете посмотреть ответы, в коих особенно усердствовал некто Banderas. Однако, я же не требую извинений. Когда я вижу, что человек груб, я просто прекращаю с ним общаться и все. Кроме вас никто не воспринял эти реплики как оскорбление. И не надо устраивать диспут на тему «он на меня не так посмотрел!» (надеюсь, это не грубость - про диспут?)



Переменная FreeAndNil работаен НЕ СО ВСЯКИМ указателем. Так понятнее?


Указатель – он и в Африке указатель. Не бывает указателей второго или еще какого сорта. "Свежесть бывает только одна: первая. Она же последняя" (М.Булгаков. "Мастер и Маргарита". Объяснить, к чему это я привел эту цитату и автора?). На протяжении всей темы вы с жаром убеждали меня, что переменная-строка – это указатель, даже не взирая на мои доводы о невозможности применения к ней специфических для указателя процедур. И теперь вот выясняется, что указатели бывают разных типов. По типу содержимого указатели могут быть только типизированными или нетипизированными. Все, других не существует. Будьте последовательнее: переменная объектного типа в реальности такой же указатель, как и переменная-строка, но только все это в обоих случаях находится внутри, скрыто от программиста, или, как говорит Ins, все это неявные указатели, и поэтому типовые функции указателя для этих переменных недоступны. (В конечном счете, если уж так хочется, никто не мешает создать перегруженную процедуру  FreeAndNil для работы с обычными указателями, очень полезная перегрузка получится).



Спор про то, можно ли называть динамические массивы и строки указателями, считаю далее неинтересным. Я уже высказал свою позицию: с точки зрения языка высокого уровня они м в самом деле указателями не являются, но с точки зрения кода они - стопроцентные указатели, потому что низкоуровневые операции с ними ничем не отличаются от операций с указателями. Даже если вас такая позиция не устраивает, вы никак не выразили своего к ней отношения, поэтому мне пока просто не на что отвечать.


Мой предыдущий ответ четко определяет мою позицию, все расставляет по своим местам, отделяя столь любимые некоторыми мухи от менее любимых котлет, т.е. переменные языка от их внутренней реализации. Как выясняется, позиции совпадают полностью. И если бы вы внимательнее относились к моим утверждениям по этим вопросам, то спора бы как такового, не было.  Я с самого начала говорил исключительно о переменных языка, а не об их внутренней реализации. Укажите мне хоть одно место, где я бы утверждал, что реализация переменной-массива представляет собой что-то, отличное от указателя.


Во-первых, FillChar в чужом коде сам по себе ничего не доказывает - его могли поставить просто по незнанию. В вопросах иногда такое пишут! Так что я не стал бы вообще ссылаться на такие сомнительные авторитеты :))))


Здорово, как только появляются доказательства противного, они сразу объявляются неавторитетными! И кто меня теперь посмеет упрекнуть в приведенных ранее примерах нетерпимости к чужому мнению в виде иезуитства и проч.? И как можно поставить для локальное переменной этот оператор «по незнанию»? Полный абсурд. Я лично с самого начала его не использовал, пока не натолкнулся на проблемы. Вообще он предназначен для быстрого заполнения определенной константой больших размеров данных, а использование его для начальной инициализации – это лишь частный случай применения. Ну, а если его «поставили по незнанию», то можете связаться с авторами и поинтересоваться, почему они это сделали? В крайнем случае, попробовать самостоятельно создать аналогичное приложение, не использующее FillChar, и чем все закончится.
Почему вы проигнорировали мой вопрос на счет вашей уверенности в том, что компилятор всегда генерирует один и тот же код? Приложения, создававшиеся мной, содержали в себе массу функций обратного вызова, потоков, находящихся в библиотеках, которые через эти функции обращаются к основному приложению, вложенные вызовы функций и прочая чертовщина. Ведь компилятор – оптимизирующий, и, в зависимости от условий он может так или иначе модернизировать создаваемый код. В простом однопоточном приложении все будет в порядке, а вот в таком приложении что-то может и не сработать. В конечном счете, все-таки Дельфи – это весьма сложная система, ее делали люди, которые так же могли допустить какие-либо ошибки, в конечном счете и к средам программирования выпускаются сервиспаки. Приведите веские аргументы вашей уверенности, и я сразу же признаю вашу правоту в части того, что для инициализации массивов и строк в структурах не требуется FillChar.
И, кстати, в моем предыдущем ответе была затронута тема о том, что слишком большие массивы лучше финализировать руками, а не ожидать этого от компилятора. Мысль эта не моя, из цитаты, надеюсь, с ней вы спорить не будете? Если будеет, то спорьте с автором, а не со мной.


Согласен, давайте на этом спор "что есть указатель" прекратим. Тем более, что эту точку зрения вам подсказал Антон Григорьев:

Это правильно, но только пока мы остаёмся на соответствующем уровне абстрагирования. Пока мы оперируем исключительно высокоуровневыми терминами, ни строки, ни массивы действительно не являются указателями.

Рад, что вы ее приняли. Мне такое определения указателя тоже нравится.


Вообще то я с самого начала говорил ОБ ИМЕНАХ ПЕРЕМЕННЫХ, а не о том, как они внутри определяются (уже не знаю, в который раз повторяю это заклинание). И не моя вина в том, что некоторым все приходится разжёвывать до атомарного уровня. И не я принял чью то точку зрения, просто слишком много усилий понадобилось, чтобы вы наконец поняли, о чем именно идет речь. Ну, а изобретение каких-то «абстрагированных уровней» - что под этим вообще понимается? Я говорил исключительно о переменных, а не о каких то абстрактных, то бишь отвлеченных, понятиях, и, нужно было сильно постараться, чтобы это то не заметить.


Ничего себе! Уважайте профессора!


В каком смысле профессора? Профессора бывают разные. Если в общеупотребительном, то наоборот, не позорьте профессора: людям думающим недопустимы такие промахи.
И, кроме того, не нарушайте первую заповедь.




А мне удалось! Чудеса!


После перезагрузки Дельфи и мне удалось. Вероятно, какая то ошибка накопилась. Или вы начнете вопить: мол, Дельфи – идеальная безглючная система, ее никогда не надо перегружать? Вчера, по крайней мере, выскакивало сообщение об ошибке приведения типов, хотя я точно помню, что осуществлял такое приведение применительно к свойству компонента Tag (для придир: p:=pointer(Component.Tag))  Пишу это только для того, чтобы никто не посмел упрекнуть меня в том, что я что-то замалчиваю.

P.S. Предыдущий ответ Антона Григорьева уж очень похож на "За что же, не боясь греха...". Надеюсь, это не оскорбление? Конечно, каждому приятно, что ему говорят хорошие слова, что его цитируют, что его хвалят, и он старается платить тем же, чтобы и в дальнейшем слышать хорошие слова. Но, "Враги, указывающие нам на наши недостатки, лучше, чем друзья, скрывающие их" (может, знаете, кто это сказал?).
Да, каких то мелких деталей я мог и не знать или вообще забыть. Но мне вполне достаточно того, что созданные мной клиент-серверные системы бесперебойно работают без сбоев месяцами (не было возможности протестировать на большем сроке).
И, если вы считаете себя достаточно умными, ответьте, пожалуста на вопрос №30056. Мне это уже не особенно нужно, но здесь уже нельзя обойтись простым прочтением одного документа с последующим его перепечатыванием в королевство (надеюсь, никого не обидел? Ни чья честь не задета? Если обидел - покорнейше извините), тут уже нужны эксперименты и аналитические действия.

17-11-2006 06:33
Я уже давно решил свою проблему, но не отписывался о ее решении, только потому что в ней стихийно и самостоятельно развилась дискуссия совершенно по другому вопросу! Но! Не смотря на это, я получил довольно таки много информации, спасибо Вам за это, мне не придется задавать много новых вопросов!

зы:
А сейчас я думаю, как написать:

  union {int sost_kan;
        short sos[2];
        }
S[57];


Эту запись на дельфи, но прошу не писать именно здесь ответа. Так. как тема не будет логически завершена.

Всем Вам большое спасибо и думаю тема подошла к логическому завершению!

17-11-2006 06:18 | Замечание модератора
Всем участникам дискусси, кроме, разумеется, Loki, я хочу принести свои извинения. Вы знаете, что обычно я жёстко пресекаю любое хамство, как этого и требуют правила Королевства, однако в данном случае я не предпринял никаких подобных действий, хотя высказывания Loki уже давно перешли все границы вежливости. Я ведь и сам - участник этого спора, так что если я воспользуюсь своими привилегиями модератора и воздам Loki по заслугам, это будет выглядеть как если бы у меня не хватило аргументов и я решил банально заткнуть оппоненту рот.

Мне, конечно, очень обидно видеть, как оскорблениям со стороны Loki скопом и по одиночке подвергаются участники этого разговора. DRON, постоянно демонстрирующий очень глубокие знания в самых разных областях и поэтому вполне предсказуемо выигравший с огромным отрывом конкурс в номинации "Самый фундаментальный ответ". Ins, который несмотря на свою относительную молодость постоянно даёт нетривиальные и правильные ответы, а также является автором нескольких интересных статей. Алексей Румянцев, который в Королевстве уже более пяти лет, является автором нескольких статей и всё время даёт ответы, справедливо замеченные посетителями на нескольких конкурсах. Banderas, с которым у меня хоть и был когда-то давно конфликт, но который - я должен это признать - с тех пор ни разу не нарушил наших правил, а его ответы очень грамотны и не раз получали заслуженные благодарности. И, наконец, Крокодил, мой институтский преподаватель, который появился здесь совсем недавно, но в своём первом же ответе поразил меня глубиной и точностью решения проблемы и с тех пор ни разу не опускал эту планку. Я понимаю, как вам всем неприятно слушать оскорбления от Loki, который ничем подобным пока себя в Королевстве не проявил, но почему-то сразу решил, что мозги здесь есть только у него. Надеюсь, вы тоже проявите понимание к тому, в какой ситуации я оказался, и простите мне моё бездействие.

Специально для Loki добавлю: не думайте, что теперь вам дана индульгенция, и вы можете и дальше хамить абсолютно безнаказанно, а я и пальцем пошевелить не посмею. Будете нарываться - я наплюю на то, что вы обо мне подумаете, и перейду к карательным мерам. Так что тщательнее взвешивайте свои слова.

Чтобы вы вновь не вспоминали про инквизицию, скажу ещё вот что: вы можете свободно высказивать здесь своё мнение, и я даю вам гарантии, что будь оно на мой взгляд хоть трижды неправильным, это никогда не станет причиной репрессий. Наказывать я буду вас только за "синьора Буратино", "детей летенанта Шмидта" и прочие оскорбительные для других участников разговора выражения. Надеюсь, вы всё поняли, и мне не придётся вразумлять вас ещё раз.

17-11-2006 03:06
если это указатели, то почему их, как нормальные указатели, нельзя раскрыть? И что они тебе ответят?
Так как строка - особый тип указателя, то она и раскрывается по своему:
var st:String;
PChar(st)[0]:='...';
Например:

var
  s1,s2,s3:String;
begin
  s1:='a';
  s2:=s1+'b';
  s3:=s2;
  PChar(s2)[0]:='c';

Строка s2 равна 'cb'.
Вопрос: чему равна строка s3 (именно s3)?

17-11-2006 02:04 | Комментарий к предыдущим ответам
Конкретно для Pointer не будет, но для любого типизированного указателя будет. Я написал Pointer, что бы обобщить понятие указателей, я думаю это понятно.

это моя фраза, да.


И это мне заявляет человек, который упрекал меня:


Тогда будьте поточнее в своих высказываниях, так как все ваши предыдущие примеры касались именно процедур и их локальных переменных.

а это не моя :)

Так что, Loki, реально внимательно следи за тем. кто что и в каком контексте тебе пишет :)


17-11-2006 01:39 | Комментарий к предыдущим ответам
Всё, котлеты с мухами я отказываюсь есть под любым соусом...
Блин, Loki извините, ну просто полный бред, в любой параграф пальцем ткни - бред. Начиная с неумесных "расстрелов", и не в тему "Аристотеля", и заканчивая просто незнанием/непониманием pascal'я.
Кстати, на счёт мух и Аристотеля: на сколько я в курсе он не называл муху пауком на основании восьми ног, а просто говорил что у мух восемь ног. Но когда-то я прочитал интересную заметку о том что Аристотель и не был не прав, а был не прав переводчик или переписчик. Мол Аристотель говорил о восьми конечностях, а не ногах. А в инете кто-то дописал: "а у сомца мухи девять" :o)

16-11-2006 23:59 | Комментарий к предыдущим ответам
Loki продолжает хамить. Вдруг ни с того ни с сего начал мне тыкать, хотя я с ним всегда был на "вы" :))))

Итак, я уже говорил это, но до Loki, как обычно, с первого раза не доходит: я изучал исходные коды, работающие со строками, поэтому знаю, как и что организовано внутри. И если я соглашаюсь с автором RSDN, то только потому, что я всё это и без него проверил, и поэтому знаю, что он прав. Кстати, человеку, который привёл так много цитат, грех обвинять других в ссылках на "авторитеты".

А вот это уже – прямое оскорбление. Кое-кто тут пытался меня заставить извиниться за то, что я отстаиваю свою точку зрения.

Нет, вас пытаются заставить извинится за хамство. Вы откровенно нахамили мне, в грубой форме сказав, что я не в состоянии объяснить ваш "эксперимент", хотя к тому моменту я это уже сделал. Далее, несмотря на все мои напоминания, вы отделываетемь пустой демагогией, а не разбором моих результатов по существу. Что, сказать нечего, да? Тогда надо извинится за своё хамство. Или хоть как-то прокомментировать мои результаты.

перечитай мои ответы, и ты увидишь, что я признавал себя неправым, а вот ты – ни разу.

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

Спор про то, можно ли называть динамические массивы и строки указателями, считаю далее неинтересным. Я уже высказал свою позицию: с точки зрения языка высокого уровня они м в самом деле указателями не являются, но с точки зрения кода они - стопроцентные указатели, потому что низкоуровневые операции с ними ничем не отличаются от операций с указателями. Даже если вас такая позиция не устраивает, вы никак не выразили своего к ней отношения, поэтому мне пока просто не на что отвечать.

Кстати, и паука действительно 8 ног (а у некоторых австралийских видов - вообще 10). В отличие он насекомых, к коим паук не относится. А ошибка Аристотеля, насколько я знаю, заключалась в том, что он утверждал, будто у насекомых, как и пауков, тоже восемь ног, а не шесть.

Задав по круглому столу соответствующий поиск, я нашел несколько ответов, подтверждающих мою правоту – это ответы №№45046, 44506, 44087, 43956, 43706, 43033. Во всех примерах оператор очистки локальной переменной FillChar стоит одним из первых, перед первым применением переменной.

И что вы этим доказали? Только то, что невнимательно читаете ответы оппонентов, что было и так известно :))))

Во-первых, FillChar в чужом коде сам по себе ничего не доказывает - его могли поставить просто по незнанию. В вопросах иногда такое пишут! Так что я не стал бы вообще ссылаться на такие сомнительные авторитеты :))))

Теперь - серьёзно. Я утвердал, что автоматически инициализируются: а) строки б) днамические массивы в) варианты г) интерфейсы. Как самостоятельные переменные, так и элементы массивов и поля записей. Про переменные и поля остальных типов я много раз говорил, что они автоматически не инициализируются, а потому могут содержать любое значение. Если вы найдёте, где я утверждал нечто не соответствующее этому, готов принести все извинения, которые вы сочтёте нужным, и признать себя полностью неправым. А теперь разберём ваши примеры по существу.

Вопрос 45056 - FillChar используется для инициализации СТАТИЧЕСКОГО массива. Между статическими и динамическими массивами с точки зрения внутренней структуры огромная разница, статический массив не финализируется автоматически, а потому и не инициализируется. Если вы не знаете разницы между статическим и динамическим массивом, советую восполнить пробел в своём образовании. А про статические массивы вам тут никто ничего такого не говорил.

Вопрос 44506 - FillChar используется для инициализации структуры типа TTVIItem. Какое отношение имеет эта структура к автоматически финализируемым типам?

Вопрос 44087 - FillChar используется для инициализации структуры TSecurityAttributes - тоже никакого отошения к перечисленным выше типам.

Вопрос 43956 - опять инициализация структуры TStartupInfo, не имеющей отношения к финализируемым типам.

Вопрос 45926 - опять статический массив.

Вопрос 43033 - и тут тоже статический массив.

Итог: ни одного примера, который хотя бы косвенно подтверждал, что локальные строки (AnsiString aka string и WideString), ДНАМИЧЕСКИЕ массивы, интерфейсы и варианты нуждаются в инициализации, вы не привели. Зря потраили своё и наше время.

Что вы на это скажете, господа умники? Только не говорите, что я договорился с этими людьми и такого быть не может и ничего не надо очищать, месье Григорьев лично своим ответом подтвердил мою правоту, равно как ее подтверждают и вопросы в приведенных мной примерах.

Дорогие дети лейтенанта Шмидта, <...>


А вы дальше осмелитесь утверждать, что никогда никому не хамили? Меня зовут Антон, никакого отношения к Франции я не имею, и обращение "месье" расцениваю как оскорбление, потому что в таком контексте оно использовано с целью унизить. Далее - к своим оппонентам вы обращаетесь "умники", "дети лейтенанта Шмидта", в своём ответе от 03-11-2006 07:39 назвали оппонета "синьор Буратино", а также испольовали другое унизительное в данном контексте обращение - "юноша". Что это, если не хамство? И разве за такое не нужно извиняться?

Вы, конечно, сейчас начнёте говорить, что вас заставляют извиняться за отстаивание своих убеждений. Оставим пока ваши убеждения в стороне - я требую извинений только за это хамство. Вы, конечно, можете поступить как негры в Америке или в Европе. Некоторые из них ведут себя агрессивно, хамят окружающим, а когда их пытаюся приструнить, начинают вопить о притеснении чернокожих. Так вот, подчёркиваю, что о ваших иубеждениях сейчас ресь не идёт, я требую извинений только за эти хамские обращения. И буду вас долбить этим требованием, если вы опять по своей привычке проигнорируете эти неприятные для вас слова.

Особенно насчет FreeAndNil - он не с указателями работает а с объектами - переменными классов, наследников от TObject

То есть, переменная – объект не является указателем? А как же с заявлениями фирмы Borland, что это на самом деле указатель на объект?


Переменная FreeAndNil работаен НЕ СО ВСЯКИМ указателем. Так понятнее?

Ты это просто так соврал или пытаешься всех ввести в заблуждение? У меня почему то не получилось при помощи метода New записать в казатель какое-то «непредсказуемое» значение: он всегда оказывался равным nil. Вот текст процедуры срабатывания таймера:

  p:=Pointer(Random(MaxInt));
  New(p);
  If p<>nil then beep;


Мне остаётся только процитировать ваши же слова: Когда я с кем то обсуждаю какие-либо темы, я полагаю, что мой собеседник сам поймет те мелочи, которые я опускаю, что он внутри своей черепной коробки расставит все правильно и восстановит недостающие звенья логических цепочек в силу их очевидности. Однако, как показывает практика, я часто переоцениваю интеллектуальные способности своих оппонентов. Поэтому начну медленно, вдумчиво и по порядку.

Итак, медленно, вдумчиво, и по порядку. Я утверждал, что указатели (в высокоуровневом понимании этого слова), являющиеся полями структур, не инициализируются при использовании New. В отличие от автоматически финализируемых типов. Приведу конкретный пример:

type
  PSomeRecord=^TSomeRecord;
  TSomeRecord=record
    I:Integer;
    pI:PInteger;
    P:Pointer;
    S:string;
    A:array of Integer
  end;

...
var X:PSomeRecord;
...
New(X);



Так вот, я утверждаю, что в такой структуре после вызова New поля I, pI и P могут иметь произвольные (в т.ч. и нулевые) значения, а вот S и A всегда окажутся проинициализированы пустой строкой и пустым массивом соответственно. Сможете построить контрпимер?

А применять New к (судя по всему) нетипизированному указателю - такое мне и в страшном сне не приснилось бы :))

16-11-2006 17:06 | Комментарий к предыдущим ответам
Однако привести целочисленный тип к указателю вам не удастся – мне, по крайней мере, не удалось.

А мне удалось! Чудеса!

procedure TForm1.Button1Click(Sender: TObject);
var
  p: pointer;
  i: integer;
begin
  i:=0;
  p:=Pointer(i);
  Caption:=string(p); // Эта строка нужна, чтобы оптимизатор не выкинул предыдущие
end;



16-11-2006 16:25 | Комментарий к предыдущим ответам
Да, еще несколько моментов. Прежде всего, хочу сказать, с каким из ваших утверждений я пожалуй соглашусь (правда, это не совсем ваше утверждение):

Как я понял, спор велся с разных плоскостей: я спорил с плоскости  языка программирования, мои оппоненты – с плоскости внутренней организации программ. На самом деле это две большие разницы.

Согласен, давайте на этом спор "что есть указатель" прекратим. Тем более, что эту точку зрения вам подсказал Антон Григорьев:
Это правильно, но только пока мы остаёмся на соответствующем уровне абстрагирования. Пока мы оперируем исключительно высокоуровневыми терминами, ни строки, ни массивы действительно не являются указателями.
Рад, что вы ее приняли. Мне такое определения указателя тоже нравится.

Крокодил, прежде чем критиковать, хотя бы вдумайся в то, что ты пытаешься осмеивать, а потом критикуй. Если непонятно – могу здесь разъяснить по буквам лично для тебя.

Ничего себе! Уважайте профессора!

16-11-2006 15:58 | Комментарий к предыдущим ответам
О, Loki появился... а вот и новые перлы, я уже было расстроился, что их не увижу!

На заре христианства (или, может быть, чуть раньше) был такой чел – Аристотель, слышали, наверно? Он для вас авторитетен? Так вот, однажды, толи по пьяни, толи поспорил на пузырь, но поймал сей ученый муж какое то насекомое, назвал его пауком и объявил, что у паука 8 ног. И Святая Церковь делала шашлык из любого, кто позволял себе усомниться в количестве паучьих ног, даже не учитывая при этом, что пока еще не удалось поймать ни одного паука с оным количеством конечностей; все пойманные пауки оказывались шестиногими, однако это не смущало святых отцов, они заявляли, что этот паук просто перенес в утробе матери какую то инфекцию, сделавшую его шестиногим.

Это, конечно, не имеет никакого отношения к теме дискуссии, но все-равно прикольно. Что-то мне обычно все-таки восьминогие пауки попадаются. Наверное они перенесли какую-то инфекцию в утробе матери или это у нас чернобыльская зона...

Дальше, ну, то что господин читает по-диагонали наши сообщения, подтверждает тот факт, что он не поставил тип ответа "Комментарий к предыдущим ответам", а ведь просьбы была адресована и к нему также.

New и Dispose - это устаревшие методы. Сейчас в моде AllocMem и FreeMem или FreeAndNil. Последний не только освобождает память указателя, но и присваивает указателю значение Nil.

То есть, память, выделенную с помощью AllocMem FreeAndNil тоже освободит? И вы еще пытаетесь отвечать за эти слова? Удивительно... Вот эта фраза - эта была полнейшая глупость, и не пытайтесь сделать вид, что вы имели в виду экземпляры классов, которые по нашим словам являются указателями.

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

Нет, вы плохо читали ответы. Никто и не спорил, что локальные переменные простых типов будут содержать мусор, который до этого находился в стеке. Вам пытались доказать, что автоматически финализируемые инициализируются нулем. Вот ваши слова, абсолютно не соответсвующие действительности, с которых все и началось:

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

Напомню ответ Антона Григорьева:

Когда я говорил, что ВСЕ локальные переменные автоматически инициализируются? Я говорил только о том, что инициализируются ВСЕ АВТОМАТИЧЕСКИ ФИНАЛИЗИРУЕМЫЕ локальные переменные. Вот точная цитата из моего сообщения от 30-10-2006 09:30: "Локальные переменные всех автоматически финализируемых типов (string'и, варианты, интерфейсы, динамические массивы) в прологе функции обязательно инициализируются пустым значением. Это только в нефинализируемых типах вроде того же double может оказаться что угодно, а строка обязательно будет пустой". А вот ещё одна, из моего же сообщения от 31-10-2006 04:06: "Лучше всего попытаться не инициализировать переменные, а сразу посмотреть, какие там значения. Попробуйте и убедитесь, что в большинстве случаев там будут отнюдь не нули. А вот чтобы строка без инициализации оказалась не пустой - с таким вы точно никогда не столкнётесь." Речь там, кстати, шла как раз о целочисленных переменных. Так что я не только не утверждал, что Integer'ы должны автоматически инициализироваться нулями, а говорил прямо противоположное. Так что к чему вы всё это написали - непонятно.

Читайте внимательно, что вам пишут умные люди, я вас очень прошу. А насчет авторитетов - для меня, я полагаю и для большинства людей, которые ведут с вами спор, главным авторитетом являются исходники VCL, а вы - полагаетесь на свои догадки, свой опыт, который приводит к тому, что понятные и логичные ситуации трактуются вами неверно из-за недостатка знаний.

16-11-2006 14:57
Перечитал все, что здесь написано. Убедился лишний раз, что, сидя на работе, вести какой-то серьезный диспут сложно: постоянно отрываешься, можешь что-нибудь пропустить, как, например, выпали из моего поля зрения  целые фрагменты некоторых ответов. Пересмотрел все это строго – противоречий очень много. Но, в отличие от поэта я все-таки попытаюсь их исправить. Долго думал, с чего начать, решил с главных тем разговора.
Но сначала хотелось бы остановиться на одном маленьком моменте.


не надо пока рассуждать. просто отвечай на вопросы


  Слушаюсь, мой белый господин!


4. После моего напоминания вы опять не нашли ни одного слова, чтобы прокомментировать эксперимент, к которому ранее проявляли такой интерес. Из этого я делаю вывод, что вы - трус, который боится признать, что был неправ.


А вот это уже – прямое оскорбление. Кое-кто тут пытался меня заставить извиниться за то, что я отстаиваю свою точку зрения. Мне кажется, что сие сродни иезуитскому средневековью, когда представители известного католического ордена живьем на кострах жгли тех, кто сомневался, что земля покоится на трех слонах, которые стоят на большой черепахе, плывущей по океану. Это сродни еще не очень давних времен, когда людей расстреливали только за то, что они не соглашались с действующим режимом. Подобное мракобесие происходило не только у нас, но и в нацистской Германии, и во многих других странах. Я уже указал, в чем причина того, что некоторые части ответов я пропустил. По этому случаю могу только сказать, что реально я хотел спросить о чем то о другом, но, видимо, отвлекся, и сейчас уже точно не помню о чем.  А заявление на счет трусости – это не только оскорбление, это и откровенная ложь: перечитай мои ответы, и ты увидишь, что я признавал себя неправым, а вот ты – ни разу. Кроме того, ты откровенно, я бы даже сказал, сознательно врал на счет того, что New в нетипизированном указателе может вернуть все, что угодно, и я об этом расскажу далее.
А теперь – к делу

Когда я с кем то обсуждаю какие-либо темы, я полагаю, что мой собеседник сам поймет те мелочи, которые я опускаю, что он внутри своей черепной коробки расставит все правильно и восстановит недостающие звенья логических цепочек в силу их очевидности. Однако, как показывает практика, я часто переоцениваю интеллектуальные способности своих оппонентов. Поэтому начну медленно, вдумчиво и по порядку.
Являются ли переменные-строки или переменные-массивы указателями? Как я понял, спор велся с разных плоскостей: я спорил с плоскости  языка программирования, мои оппоненты – с плоскости внутренней организации программ. На самом деле это две большие разницы. Еще раз заявлю: ни переменные –массивы, ни переменные-строки С ТОЧКИ ЗРЕНИЯ ПРОГРАММИСТА УКАЗАТЕЛЯМИ НЕ ЯВЛЯЮТСЯ, потому что он не может применить к ним основные для указателей действия: раскрытие и взятие адреса (ну, только переменная-массив может получить и вернуть свой адрес, это действительно так). При компиляции приложения компилятор преобразует имя переменной-строки или массива в указатель, я НИКОГДА ЭТО НЕ ОСПАРИВАЛ, но это ВНУТРЕННИЙ УКАЗАТЕЛЬ в программе, поэтому он программисту НАПРЯМУЮ НЕДОСТУПЕН. Это понятно? Надеюсь да. Единственно для меня непонятным был момент с внутренними полями этих типов, я предполагал, что на самом деле они входят в состав переменных этих типов, однако вовсе не потому, что я невнимательно читал литературу, как раз наоборот, и берусь это доказать.
  Для начала возьму двухтомник «Программирование в Delphi5» Стива Тейксейры и Ксавье Пачеко (надеюсь, это достаточные для вас авторитеты?). Открываем страницу 68, где как раз начинается описание переменных-строк. Про указатели почти ничего не говорится. Только на странице 69 есть одно предложение (самый первый абзац): «Такая операция, как копирование, по сути сводится к копированию указателя и увеличению счетчика». Все. Больше указатели никак не упоминаются. Приведен так же рисунок, подобный тому, что привел Ins. Однако в рисунке в книге есть некоторые изменения: первые четыре байта – размер выделенной памяти (это – свойство всех указателей), далее – как у Инса, кроме того, что вместо надписи (Ins): «Переменная типа String – 4 байта» у Тейксейры и Пачеко стоит другая надпись: «Данные AnsiString», и никакой указатель тут не упоминается. Так что, на основании этого рисунка я вполне имею право предположить, что реальный указатель указывает на начало структуры строки, а вовсе не на первый символ. И в описании массивов (стр. 88) так же не упоминаются никакие указатели.
Далее, беру книгу Джулиана Баккела «Фундаментальные алгоритмы и структуры данных в Delphi». Вроде бы уж как раз тут то и должно проявиться! Ан нет, ни про какие указатели и тут не говорится. Единственное место – это где приводится формула поиска элемента массива с заданным индексом. И, опять-таки, все, ничего более.
Обратимся к дельфийскому хелпу. Я просмотрел все пункты, так или иначе связанные со строками, но нигде не нашел описания приведения переменных-строк и массивов к типу указателя. НИГДЕ. Отсюда я могу сделать вывод, что подобное приведение, скорей всего, является недокументированной особенностью Delphi, и, возможно, является результатом работы какого-нибудь алгоритма, отвечающего за корректность таких  приведений.  Попробуйте привести тип integer к типу pointer – у меня не получилось, компилятор выругался о несовместимости типов. Поэтому вполне возможно так же, что это просто недосмотр разработчиков компилятора, но, тем не менее, как и в случае с другими недокументированными возможностями, разработчики могут в один прекрасный момент закрыть эту лазейку, что-нибудь поменяв в ней или же вообще запретив ее. И, таким образом, программы, ранее нормально компилировавшиеся, вполне могут оказаться либо некомпилируемыми, либо начнут работать с ошибками (например, если вдруг разработчики Delphi решать, что указатель должен указывать не на первый символ, а на начало структуры).
Когда я начал использовать процедуру Move, я так же наивно подумал, что имя строки или массива можно использовать как указатель. Но Move(p1^,p2^,Size) выдала известное сообщение об ошибке. Даже попытка приведения раскрытого имени  строки-массива к типу, дала тот же результат. Мне тогда и в голову прийти не могло, что для того, чтобы воспользоваться переменной-указателем, нужно ее еще привести к типу указатель. Попытайтесь просто ВДУМАТЬСЯ в эту фразу, не прибегая к ссылкам на «классиков программирования»: не абсурд ли это на самом деле?
Я надеюсь, вопрос по поводу того, являются ли переменные-строки и массивы указателями или нет (с точки зрения программиста) закрыт?
Но отвечу все-таки на последний выпад по теме.


Во, нашёл ещё одного "идиота", который не понимает, что строки - это совсем не указатели :)))

Статья http://www.rsdn.ru/article/Delphi/dynarrays.xml#EWLAC , точная цитата оттуда: "Еще раз хотелось бы напомнить, что переменная типа длинная строка или динамический массив есть указатель. Непонимание этого может привести к непредсказуемым эффектам".

И ведь серьёзное издание - RSDN Magazine! А вот пробрался туда такой глупый автор, да ещё и редакторы оказались не умнее :)))))))) Эх, Loki на них нет, он бы им объяснил, как правильно статьи писать, и что на самом деле динамические массивы - это не указатели, а аж 12-байтные структуры :)))))))


  Хотя я все уже расписал, но специально тебе порекомендую: спроси их, что они имели ввиду? И если они тебе скажут, что имели ввиду именно то, что переменные-строки – это указатели, задай им вопрос: если это указатели, то почему их, как нормальные указатели, нельзя раскрыть? И что они тебе ответят?
  На заре христианства (или, может быть, чуть раньше) был такой чел – Аристотель, слышали, наверно? Он для вас авторитетен? Так вот, однажды, толи по пьяни, толи поспорил на пузырь, но поймал сей ученый муж какое то насекомое, назвал его пауком и объявил, что у паука 8 ног. И Святая Церковь делала шашлык из любого, кто позволял себе усомниться в количестве паучьих ног, даже не учитывая при этом, что пока еще не удалось поймать ни одного паука с оным количеством конечностей; все пойманные пауки оказывались шестиногими, однако это не смущало святых отцов, они заявляли, что этот паук просто перенес в утробе матери какую то инфекцию, сделавшую его шестиногим.


Далее, по вопросу использования оператора FillChar применительно к локальным переменным, которые, вроде бы, не надо очищать:


Если вы приведёте хотя бы один такой пример, все споры будут завершены. Но вы предпочитаете пустой трёп с надуванием щёк вместо хотя бы одного такого примера. Какой вывод мы должны сделать? Такой, что этих примеров просто не существует. Возможно, что когда-то у вас что-то и не получалось без FillChar, но теперь вы поняли, почему, и поняли, что мы здесь были правы. Хватит смелости в этом признаться, или опять будете делать вид, что всё в порядке?

Конкретный пример такого кода будет? Или я в очередной раз должен буду читать пространные рассуждения, ничем не подкреплённые? Пока не будет кода, всё это - пустой трёп.




На сколько я помню, разговор шел о необходимости очистки локальных переменных, которые надо филчарить нулями перед началом их использования. Я тут хотел было привести свои примеры, когда мне перед использованием требовалось очищать структурные локальные переменные, которые якобы автоматически инициализируются. Но вспомнил, что про локальные переменные я читал, кажется как раз в материалах Королевства. Задав по круглому столу соответствующий поиск, я нашел несколько ответов, подтверждающих мою правоту – это ответы №№45046, 44506, 44087, 43956, 43706, 43033. Во всех примерах оператор очистки локальной переменной FillChar стоит одним из первых, перед первым применением переменной. Что вы на это скажете, господа умники? Только не говорите, что я договорился с этими людьми и такого быть не может и ничего не надо очищать, месье Григорьев лично своим ответом подтвердил мою правоту, равно как ее подтверждают и вопросы в приведенных мной примерах.
Дорогие дети лейтенанта Шмидта, если бы вы не занимались бездумным повторением тезисов авторитетов в области программирования, бормоча «Строка – это указатель» и «массив- это указатель», совершенно не вникая при этом в суть сказанного, а хоть немного напрягали свои мозги самостоятельным мышлением, вы бы задали себе вопрос: что, я в свое удовольствие использую процедуру FillChar применительно к локальным переменным или, может все-таки потому, что в этом возникает потребность? И надо при этом учесть, что в многопоточных приложениях, кои я имел честь разрабатывать, память используется несколько не так, как в линейных, и я нередко сталкивался с необходимостью чистить локальные переменные. СТАЛКИВАЛСЯ, а не выдвинул какую то свою теорию. И если я говорю, что у меня большой практический опыт – значит, так оно и есть, и мне смешно слушать аргументацию некоторых товарищей, которые с апломбом заявляют, что такого быть не может, потому что не может быть никогда, приводя при этом отдельные примеры. Вы просто с этим не сталкивались, но это не значит, что такое невозможно.  Ребята, почему вы решили, что во всех случаях жизни компилятор генерирует всегда один и тот же код? Что дает вам такую уверенность?
Приводя в качестве аргументов цитаты из книг великих людей, вы, к тому же, нарушаете первую библейскую заповедь. А что бывает с теми, кто нарушает первую заповедь, вы сможете узнать, посмотрев фильм «Догма». ? Я тоже «верю в это». ?

Ну, и далее по мелким вопросам, которые я упустил.


Давайте поставим точки над i. Что представаляет собой первооснову. Машинный код или текст программы? На первоначальном этапе никаких языков программирования не было, все операции писались в машинных кодах, а языки программирования были созданы для облегчения жизни программистам. Таким образом, язык программирования - это средство написания машинного кода, который и является первичным понятием. Процессор выполняет машинные команды, а не строки языка программирования. Еще раз: язык программирования создан для того, чтобы отражать машинный код и утверждение о том, что машинный код не имеет с исходным текстом ничего общего ставит Вами под сомнение здравый смысл всех разработчиков мира.


Меня тут некоторые обвиняют в том, что я невнимательно читаю, «по диагонали». Однако – повторюсь – исходя из этого фрагмента темы в очередной раз выясняется, что вовсе не я один такой. Автор сего шедевра ничуть не лучше. Конечно, это просто: выдрать из контекста какой-то фрагмент, на основании его полностью переврать идею и потом обвинить автора в некомпетентности или еще в каком грехе. Что я сейчас и вижу. Крокодил, прежде чем критиковать, хотя бы вдумайся в то, что ты пытаешься осмеивать, а потом критикуй. Если непонятно – могу здесь разъяснить по буквам лично для тебя.
А вот еще один прекрасный момент выдирания слов из контекста:


А может все же обратиться к учебной литературе? Например:
"Кип Ирвин. Язык ассемблера для процессоров INTEL. 2005.(стр.188)"
  Переменная, содержащая адрес другой переменной называется переменной указателем (pointer variable) или просто указателем.
"Стенли Липпман. Язык программирования C++. 2001 (стр. 101)."
  Указатель - это объект, содержащий адрес другого объекта и позволяющий косвенно манипулировать этим объектом. 
"Стив Тейксера, Ксавье Пачеко. Borland Delphi 6. Руководство разработчика. 2002 (стр. 104)"
  Указатель (pointer) представляет собой переменную, содержащую месторасположение (адрес) участка памяти.
  Откуда такое единодушие. Да просто процессор может использовать только два вида адресации для доступа к объектам: прямую и косвенную. При прямой адресации в ячейке памяти или регистре (указанных в машинной команде) находится значение объекта, а при косвенной адресации - адрес этого объекта. Других вариантов нет. Поэтому все переменные делятся на два класса - обычные переменные и указатели.


Вообще то здесь шла речь не о переменных-указателях и не о типах адресации памяти процессором, а о переменных-массивах и переменных-строках языка высокого уровня сравнительно с указателями, и что для Delphi эти типы - не одно и то же, и мне не совсем понятен смысл этих вырезок.


Зачем дезинформируешь? :) Особенно насчет FreeAndNil - он не с указателями работает а с объектами - переменными классов, наследников от TObject


То есть, переменная – объект не является указателем? А как же с заявлениями фирмы Borland, что это на самом деле указатель на объект? Ведь меня укоряли именно за то, что я игнорирую утверждения фирмы о причастности  типов строк к указателям. Но та же Borland говорит, что переменные-объекты – это те же указатели. И почему тогда массивы и строки вы называете указателями, а переменные-объекты – нет? ? Тут разница лишь в том, НА ЧТО указывает тот или иной указатель. Если посмотреть метод FreeAndNil, то его параметр – нетипизированная переменная, которая приводится к типу TObject. Однако приведение это происходит без проверки на корректность, поэтому если процедуре передается какой-то другой указатель, отличный от TObject, то при попытке вызвать метод Free, будет сгенерировано исключение.



Опять какая-то ерунда. Во-первых, для инициализации указателя нулём не нужно знать размер данных, на которые он ссылается. Во-вторых, Initiflize ничего не делает с указателями простых типов, поэтому что там будет после New - непредсказуемо (я проверил - у меня действительно получался то nil, то другие произвольные значения).


Ты это просто так соврал или пытаешься всех ввести в заблуждение? У меня почему то не получилось при помощи метода New записать в казатель какое-то «непредсказуемое» значение: он всегда оказывался равным nil. Вот текст процедуры срабатывания таймера:

  p:=Pointer(Random(MaxInt));
  New(p);
  If p<>nil then beep;

Здесь p:pointer, не локальный (хотя, как показала практика, это не имеет никакого значения). В начале я ему специально присваиваю какое-либо не нильное значение, для чистоты эксперимента. Я гонял примерно в течение получаса (или даже больше) это приложение, но ни одного бипа так и не услышал, что однозначно свидетельствует о том, что ни разу New всегда инициализирует указатели такого типа значением Nil. Как это объяснить?  Посмотри ассемблерный код, он другого значения возвращать просто не может. И как тебе удалось поместить туда «какие то значения» при помощи New – для меня загадка.


Дополнительный P.S. к вопросам Антона Григорьева для Loki:
Если всё ещё будешь опровергать, то знай что в запасе есть дополнительный аргумент, состоящий из одной строки кода, после которого ты не сможешь не ответить "да" на поставленные вопросы.


Я что-то упустил? Уже прозвучал «дополнительный аргумент»?


А можно источник сего умного изречения? Где вы это вычитали? То есть ткните меня пальцем, где написана такая фраза: "Основной признак указателя, отличающий его от остальных типов - это возможность его раскрытия". Глупо звучит, правда? Определять типы нужно не по возможным операциям с ними, а по, так сказать, физическому смыслу. Кстати, тип Pointer нельзя разадресовывать, если он стоит слева от оператора присваивания, в отличие от типизированных указателей. Начит Pointer, по вашим словам также не указатель в полном смысле этого слова.


У меня вопрос: а для чего указатели предназначены? Разве не для хранения адреса памяти? И не для обращений по этому адресу? Кажется, именно для этого и был придуман этот тип. А раз так, то основными характеризующими  этот тип операциями, являются как раз операции, открывающие пользователю доступ к памяти и возможность работы с ней. В конечном счете, не поддерживают же указатели прямых арифметических операций, иначе вместо них можно было бы спокойно использовать целочисленный тип. Однако привести целочисленный тип к указателю вам не удастся – мне, по крайней мере, не удалось. Думаю, в силу строгой типизации языка. А вот со стрингами и массивами эта типизация почему-то не работает, хотя по идее должна.
А разадресовать Pointer в указанном случае нельзя только потому, что неизвестен тип данных, на которые он ссылается, проще говоря, компилятор не знает, какой размер данных вы хотите получить, иначе бы он заявлял вам “Pointer type required”. Таким образом, все в рамках теории. (с)


Конкретно для Pointer не будет, но для любого типизированного указателя будет. Я написал Pointer, что бы обобщить понятие указателей, я думаю это понятно.


И это мне заявляет человек, который упрекал меня:


Тогда будьте поточнее в своих высказываниях, так как все ваши предыдущие примеры касались именно процедур и их локальных переменных.


Я ведь тоже говорил «обще», надо бы это понимать. Это что, попытка отмазаться, не признать себя неправым?

Кажется, все. На все остальные вопросы я уже давал ответы, и не раз.

09-11-2006 03:41
А может все же обратиться к учебной литературе? Например:
"Кип Ирвин. Язык ассемблера для процессоров INTEL. 2005.(стр.188)"
  Переменная, содержащая адрес другой переменной называется переменной указателем (pointer variable) или просто указателем.
"Стенли Липпман. Язык программирования C++. 2001 (стр. 101)."
  Указатель - это объект, содержащий адрес другого объекта и позволяющий косвенно манипулировать этим объектом. 
"Стив Тейксера, Ксавье Пачеко. Borland Delphi 6. Руководство разработчика. 2002 (стр. 104)"
  Указатель (pointer) представляет собой переменную, содержащую месторасположение (адрес) участка памяти.
  Откуда такое единодушие. Да просто процессор может использовать только два вида адресации для доступа к объектам: прямую и косвенную. При прямой адресации в ячейке памяти или регистре (указанных в машинной команде) находится значение объекта, а при косвенной адресации - адрес этого объекта. Других вариантов нет. Поэтому все переменные делятся на два класса - обычные переменные и указатели.
  Что находится в ячейке оперативной памяти, выделяемой для переменной типа string? Первый байт строки или его адрес? Вроде все участники дискуссии согласны с тем, что там находится адрес. Следовательно, переменная типа string является указателем.

08-11-2006 06:19
Хорошая беседа получилась, поучительная!

08-11-2006 05:35
текст программы в виде

  p:^Char;
  ...
  p:=pointer(s)

компилятор преобразует в вид:
mov eax,[ebp-$08]
mov [ebp-$10],eax,

считая это убедительным "аргументом" (пардон, несколько упустил из виду, и не
ответил сразу). Так я на это могу заявить, что компилятор, вообще то ВСЕ преобразует
в вид машинных кодов, не имеющих с исходным текстом программы ничего общего


Давайте поставим точки над i. Что представаляет собой первооснову. Машинный код или текст программы? На первоначальном этапе никаких языков программирования не было, все операции писались в машинных кодах, а языки программирования были созданы для облегчения жизни программистам. Таким образом, язык программирования - это средство написания машинного кода, который и является первичным понятием. Процессор выполняет машинные команды, а не строки языка программирования. Еще раз: язык программирования создан для того, чтобы отражать машинный код и утверждение о том, что машинный код не имеет с исходным текстом ничего общего ставит Вами под сомнение здравый смысл всех разработчиков мира.

07-11-2006 13:31 | Комментарий к предыдущим ответам
Антон Григорьев
Там кстати не очень корректный пример идёт после этой цитаты и никаких ошибок в нём не будет, так как строки константные (счётчик ссылок =-1) и всегда указывают на "правильную" память.

07-11-2006 12:29 | Комментарий к предыдущим ответам
Во, нашёл ещё одного "идиота", который не понимает, что строки - это совсем не указатели :)))

Статья http://www.rsdn.ru/article/Delphi/dynarrays.xml#EWLAC , точная цитата оттуда: "Еще раз хотелось бы напомнить, что переменная типа длинная строка или динамический массив есть указатель. Непонимание этого может привести к непредсказуемым эффектам".

И ведь серьёзное издание - RSDN Magazine! А вот пробрался туда такой глупый автор, да ещё и редакторы оказались не умнее :)))))))) Эх, Loki на них нет, он бы им объяснил, как правильно статьи писать, и что на самом деле динамические массивы - это не указатели, а аж 12-байтные структуры :)))))))

07-11-2006 09:55 | Комментарий к предыдущим ответам
Перед отправкой своего предыдущего ответа я обновил страницу, но она взялась из кэша, поэтому не видел ответ Антона. И так же хочу его поддержать в том что вначале в большей степени спор начал разгараться из-за того, что Вы, Loki, "подозревали" string в том, что у она это типа ссылка на указатель... поэтому надо руками приводить к pointer.

07-11-2006 09:40
* взятие адреса (присвоение адреса) без использования приведения
* Указанные переменные можно будет называть указателями тогда и только тогда, когда при встрече оператора типа s^ компилятор не перестанет выдавать ошибку
* задействовать эти переменные в функциях и процедурах вместо параметров-указателей без использования приведения.

По моему, т.к. на принципиальном втором пункте, взаимопонимания не удастся достичь, то спор теряет смысл. Конечно не плохо было бы, если бы была какая-то директива, отключающая эту проверку (может есть, я не знаю).

Первый пункт, всё же можно обойти:
в моём предыдущем ответе-коде заменить pointer(s):=p; на move(p,s,4), где адрес s перезапишется, но s всё равно можно будет использовать как стринг.

Третий пункт мог бы решаться двумя способами
* на примере messagebox - function MessageBoxX(hWnd: HWND; const lpText, lpCaption: String; uType: UINT): Integer; stdcall; external user32 name 'MessageBoxA';
* или если бы была вышеупомянутая директива.

07-11-2006 09:21 | Комментарий к предыдущим ответам
Спор, как я понимаю, превратился в примитивную попытку доказать свою правоту, не взирая на очевидные противоречия.

Ага, именно так :)

переменную можно считать принадлежащей определенному типу, если к ней можно применить действия, характерные именно для этого типа

Это правильно, но только пока мы остаёмся на соответствующем уровне абстрагирования. Пока мы оперируем исключительно высокоуровневыми терминами, ни строки, ни массивы действительно не являются указателями. Но как только мы начинаем обсуждать внутреннее устройство этих строк, т.е. выходим за рамки уровня абстрагирования, определяемого синтаксисом Delphi, понятие "указатель" меняется, и поэтому и строки, и динамические массивы уже можно называть указателями. Потому что в данном случае указателем называются ячейки памяти, хранящие адрес данных, и ничего, кроме этого адреса. Вы же не будете спорить, что строки в таком смысле являются указателями?

Может, вы действительно думаете, что вы - единственный, кто знает, что такое указатель? Что все ваши оппоненты, а также программисты из Borland'а и авторы книг по Delphi - идиоты, путающиеся в элементарных терминах? Завышенное, однако, самомнение.

И, кстати, никого конкретно я не обвинял в том, что "некоторые товарищи меня с надрывом убеждали, будто переменные обнуляются", фамилии не указаны, почему вы все принимаете на свой счет?

Потому что всё, что было написано в абзаце до этого и в абзаце после этого, относилось лично ко мне - перечитайте свой ответ от 01-11-2006 01:55. Разве не логично сделать вывод, что и то, что между ними, тоже относится ко мне, так как обратное не указано?

А теперь вернёмся к разговору о вашем эксперименте. Вы опять проигнорировали то, что я там написал. Что ж, буду гворить по пунктам.

1. Вы привели описание результатов эксперимента. Я провёл его в точности по вашим описанием и получил совсем другие результаты. Из этого я делаю вывод, что вы недостаточно квалифицированы даже для того, чтобы понять, где именно возникает ошибка.

2. Я привёл описание того, что я делал, какие результаты получил и как они согласуются с той теорией, которую я защищаю. Несмотря на это вы меня обвинили в том, что я якобы только корчу из себя крутого программиста, а сам не способен объяснить ваш эксперимент. Их этого я делаю вывод, что вы приходите сюда высказываться, что вам говорят - читаете невнимательно и не вдумываетесь.

3. После этих моих слов вы несколько раз появлялись здесь, но никак не прокомментировали мои результаты. Из этого я делаю вывод, что вам нечего сказать - вы, наверное, повторили эксперимент более тщательно и убедились, что я прав.

4. После моего напоминания вы опять не нашли ни одного слова, чтобы прокомментировать эксперимент, к которому ранее проявляли такой интерес. Из этого я делаю вывод, что вы - трус, который боится признать, что был неправ.

приведенные вами доводы по поводу того, как выделяется память для строк, не являются доказательством того, что переменные-строки и массивы представляют собой указатели.

Сформулирую первый свой вопрос чуть-чуть по-другому. Второй оставлю без изменения. Получится вот что:

1. Согласны ли вы с утверждением, что для переменных типа string и динамических массивов в сегменте данных (для глобальных переменных) или в стеке (для локальных переменных) выделяется 4 байта, в которых хранится адрес первого символа/элемента, и больше ничего? Всё остальное (в т.ч. длина и счётчик ссылок) хранится в куче.

2. Согласны ли вы с тем, что для строк и динамических массивов оператор Pointer(X) просто позволяет использовать ячейки памяти, занятые X, как Pointer, без какого-либо изменения хранящегося там значения?

Как видите, спорного слова "указатель" здесь больше нет, поэтому гнилые отмазки насчёт того, что мы тут все неправильно понимаем этот термин, болше не проходят. Итак, согласны ли вы с этими утверждениями? Да или нет.

Впрочем, я знаю, почему вы не стали отвечать на так ясно сформулированные вопросы. Вы уже понимаете, как вы будете выглядеть, если ответите "нет" после всех тех аргументов, которые вам здесь привели. А "да" вы ответить не можете, потому что знаете: вам тут же припомнят ваши фразы типа при компиляции для переменной типа array так же выделяется строго определенная область памяти, занимающая 12 байт (4 байта - размер, 4 байта - количествос сылок на массив/строку) (цитата из вашего ответа от 31-10-2006 08:24). Ну, а то, что вам элементарно не хватает мужества признавать свои ошибки, мы уже выяснили.

А ещё я хочу припомнить вам следующую фразу:

На все остальные претензии и "аргументы" я отвечу позже и приведу фрагменты моих программ, где я использовал (вынужден был использовать) FillChar. (из вашего сообщения от 01-11-2006 07:01)

Если вы приведёте хотя бы один такой пример, все споры будут завершены. Но вы предпочитаете пустой трёп с надуванием щёк вместо хотя бы одного такого примера. Какой вывод мы должны сделать? Такой, что этих примеров просто не существует. Возможно, что когда-то у вас что-то и не получалось без FillChar, но теперь вы поняли, почему, и поняли, что мы здесь были правы. Хватит смелости в этом признаться, или опять будете делать вид, что всё в порядке?

некоторые товарищи мне заявляли, что текст программы в виде

  p:^Char;
  ...
  p:=pointer(s)

компилятор преобразует в вид:
mov eax,[ebp-$08]
mov [ebp-$10],eax,

считая это убедительным "аргументом" (пардон, несколько упустил из виду, и не ответил сразу). Так я на это могу заявить, что компилятор, вообще то ВСЕ преобразует в вид машинных кодов, не имеющих с исходным текстом программы ничего общего. А приведение pointer(s) просто есть указание компилятору трактовать преобразовать такое обращение к имени строки в указанный ассемблерный код, и все.


А вы забыли одну свою фразу? Вот такую:

Скорей всего, в реальности имя массива не является указателем на первое его значение, просто в компилятор встроена возможность корректного приведения типов, и встретив, такое приведение, компилятор просто подставляет адрес первого элемента массива. (из вашего ответа от 31-10-2006 07:25)

И приведённым примером я хотел продемонстрировать прежде всего то, что в области памяти, выделенной под переменную типа "динамический массив", хранится именно адрес первого элемента. И ничего такого компилятор никуда не подставляет, а просто снимает ограничения на использование этой области памяти в кочестве указателя.

Так что не удивляйтесь, что вас постоянно переспрашивают. Вы явно понимаете нашу правоту, но признаться в этом вам гордость мешает. Поэтому вы начинаете противоречить сами себе - вот вас и переспрашивают, чтобы уточнить ваше мнение.

07-11-2006 08:34 | Комментарий к предыдущим ответам
По техническим причинам фраза предыдущего ответа:


На счет позиции "наговорить, а потом молчать" - это не только я "практикую". И сам я конкретно по два раза вынужден отвечать на одни и те же вопросы, в этом достаточно убедиться, перечитав мои ответы, почему претензии только ко мне? В данном ответе (скорей всего, последнем в этой теме, по причине, указанной мной в самом начале) я постарался окончательно и бесповоротно разъяснить, что такое указатель и чем он отличается от всего остального. Кто не понял (не захотел понять) - я не виноват. И, кстати, никого конкретно я не обвинял в том, что "некоторые товарищи меня с надрывом убеждали, будто переменные обнуляются", фамилии не указаны, почему вы все принимаете на свой счет?


оказалась вписанной не в тот пункт постскриптума ответа, за что автор приносит свои извинения Алексею Румянцеву. Данная фраза адресована Антону Григорьеву.
Ему же адресована и следующий ответ:


Из ваших последних сообщений создаётся впечатление, что теперь согласны. Если я прав, то почему вы до сих пор не извинились перед всеми, кого оскорбили, доказывая, что это не так?


Обычно извиняются за то, что кого то публично оскорбили (например, назвав каким-то непотребным словом или сравнив с каким-то непотребным животным). С каких пор отстаивание своей точки зрения является оскорблением? Повторяю: приведенные вами доводы по поводу того, как выделяется память для строк, не являются доказательством того, что переменные-строки и массивы представляют собой указатели. Если не понятно почему - перечитайте этот ответ еще раз.

07-11-2006 08:25
2Антон Григорьев и пр.

Спор, как я понимаю, превратился в примитивную попытку доказать свою правоту, не взирая на очевидные противоречия. Я теряю к нему интерес, если честно.

Итак, для тех, кто в танке - через ствол:
переменную можно считать принадлежащей определенному типу, если к ней можно применить действия, характерные именно для этого типа. В частности, для указателя есть две основные операции: взятие адреса (присвоение адреса) и раскрытие (обращение по адресу). Все. Других характеристик, являющихся основными для указателя, привести нельзя (имеется ввиду, разумеется, прямые операции, безо всяких преобразований вроде приведения к типу и проч.). И как бы кто ни старался, но РАСКРЫТЬ ПЕРЕМЕННУЮ-МАССИВ ИЛИ ПЕРЕМЕННУЮ-СТРОКУ НЕЛЬЗЯ, потому что ОНИ НЕ ЯВЛЯЮТСЯ УКАЗАТЕЛЯМИ с точки зрения компилятора, а в его лице - фирмы Borland. Чего непонятно? И вы так же не сможете прямым, или, выражаясь образно, "тупым" методом, задействовать эти переменные в функциях и процедурах вместо параметров-указателей без использования приведения. И все остальные попытки доказать, что указанные переменные являются указателями, ничего не стоят.
  В конечном счете, мне по барабану, хочется вам считать переменную-строку  указателем, считайте, это ваше личное дело. Важнее то, что она от этого реальным указателем не станет. Ну, а если вы придерживаетесь правила "написано, что муха - вертолет, значит, муха - вертолет", то это тоже ваши личные проблемы.

P.S.
  1. Как я понял из приведенных ранее фрагментов английских текстов, в них фирма Борланд всего-навсего раскрывала физическую сущность переменных-строк, не более того. В конечном счете, практически любая переменная до окончательной компиляции является указателем или ссылкой на какую-то область памяти, будь то байт, слово, integer или что еще. И мне несколько удивительно, что приведенное описание было воспринято некоторыми столь буквально.
  2. Указанные переменные можно будет называть указателями тогда и только тогда, когда при встрече оператора типа s^ или a^ (ну, или хотя бы type(a^)) компилятор не перестанет выдавать ошибку (здесь а:array of type; s:string; type - определенный тип элемента массива). Тогда и только тогда указанные типы переменных можно будет назвать указателями (как кстати пригодилась фраза-заклинание из учебника геометрии Погорелова :)  ).

  3. 2Алексей Румянцев:
    На счет позиции "наговорить, а потом молчать" - это не только я "практикую". И сам я конкретно по два раза вынужден отвечать на одни и те же вопросы, в этом достаточно убедиться, перечитав мои ответы, почему претензии только ко мне? В данном ответе (скорей всего, последнем в этой теме, по причине, указанной мной в самом начале) я постарался окончательно и бесповоротно разъяснить, что такое указатель и чем он отличается от всего остального. Кто не понял (не захотел понять) - я не виноват. И, кстати, никого конкретно я не обвинял в том, что "некоторые товарищи меня с надрывом убеждали, будто переменные обнуляются", фамилии не указаны, почему вы все принимаете на свой счет?
  И, еще кстати, что за "дополнительный аргумент", который "есть в запасе"? Например, некоторые товарищи мне заявляли, что текст программы в виде

  p:^Char;
  ...
  p:=pointer(s)

компилятор преобразует в вид:
mov eax,[ebp-$08]
mov [ebp-$10],eax,

считая это убедительным "аргументом" (пардон, несколько упустил из виду, и не ответил сразу). Так я на это могу заявить, что компилятор, вообще то ВСЕ преобразует в вид машинных кодов, не имеющих с исходным текстом программы ничего общего. А приведение pointer(s) просто есть указание компилятору трактовать преобразовать такое обращение к имени строки в указанный ассемблерный код, и все. И вся программа в конечном виде преобразована к такому коду. Компилятор ДОПУСКАЕТ такое преобразование, называемое приведением, ибо это вписывается в рамки существующих правил языка. И в конечном коде вы не найдете ни описаний типов, ни классов, ни имен переменных и функций (за небольшим обязательным исключением, касающимся, как правило, вызовов библиотечных функций), потому что в конечной программе используются уже непосредственные ссылки на нужные места (для переменных) и переходы к нужным функциям (я выражаюсь обще и надеюсь, меня не будут пытаться схватить за язык криками типа "а как же вот и вот???", ссылаясь на некоторые частные случаи). Так что если ваша "строчка" представляет собой что-либо подобное - извольте не трудиться и приводить.

04-11-2006 03:36 | Комментарий к предыдущим ответам
И кстати:
Дополнительный P.S. к вопросам Антона Григорьева для Loki:
Если всё ещё будешь опровергать, то знай что в запасе есть дополнительный аргумент, состоящий из одной строки кода, после которого ты не сможешь не ответить "да" на поставленные вопросы.

04-11-2006 01:24 | Комментарий к предыдущим ответам
Вопросы для Loki:

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

1. Согласны ли вы с утверждением, что для переменных типа string и динамических массивов в сегменте данных (для глобальных переменных) или в стеке (для локальных переменных) выделяется 4 байта, в которых хранится указатель на первый символ/элемент, и больше ничего? Всё остальное (в т.ч. длина и счётчик ссылок) хранится в куче.

2. Согласны ли вы с тем, что для строк и динамических массивов оператор Pointer(X) просто позволяет использовать ячейки памяти, занятые X, как Pointer, без какого-либо изменения хранящегося там значения?

Из ваших последних сообщений создаётся впечатление, что теперь согласны. Если я прав, то почему вы до сих пор не извинились перед всеми, кого оскорбили, доказывая, что это не так?

Кстати, лично я жду от вас извинений ещё по двум пунктам: во-первых, за то, что приписали мне слова об автоматической инициализации локальных Integer'ов, хотя я до этого как минимум дважды утверждал прямо противоположное. Во-вторых, за то, что в грубой форме обвинили меня в том, что я якобы не могу дать объяснение вашему "эксперименту", хотя до этого я его дал, просто вы не потрудились прочитать. Да и ваших комментариев к моему объяснению я тоже не увидел. В общем, великолепная позиция: наговорили чуши, а когда вас на этом поймали - делаете вид, что ничего не было. Нет уж, если хотите остаться порядочным человеком - либо найдите ошибку в моём объяснении, либо признайтесь, что ошиблись сами.

И ещё учтите вот что: если поставить опцию компилятора Use Debug DCUs, можно выполнять трассировку исходных кодов, в т.ч. и тех, которые занимаются перераспределеним памяти для строк. Я это не раз делал, поэтому я точно знаю, как всё это делается. И не только я - тут, судя по ответам, немало людей, которые не хуже меня знают эти исходники. А вы их знаете? Если нет, то, может, сначала изучите матчасть, чтобы мы здесь могли спорить о вкусе устриц с теми, кто их ел?

P.S. для Banderas'а: пожалуйста, воздержитесь от использования ненормативной лексики (я имею ввиду последнюю строчку в сообщении от 01-11-2006 07:32). В следующий раз я удалю такое сообщение независимо от того, сколько полезной информации будет в нём содержаться.

P.P.S. для всех (ну, почти всех): пожалуйста, не забывайте ставить тип сообщения "Комментарий к предыдущим ответам". В противном случае ваши ответы дублируются автору вопроса, чему он вряд ли рад.

03-11-2006 10:03
Но если вы попытаетесь присвоить строке этот указатель без преобразования, то у вас ничего не выйдет. Ничего не выходит не потому что нельзя присвоить, просто ты так и не понял, что паскаль следит за всем. И даже если ты просто присвоишь, то получишь ошибку потому что за типом string идёт отдельная слежка. Но присвоить можно

procedure TForm1.Button1Click(Sender: TObject);
const
  inf: array[0..1] of integer = (1, 255);
  text: string = 'Abcd';
var
  s:string;
  p:pointer;
begin
  p := allocmem(255);//хоть миллион
  move(inf, p^, sizeof(inf));
  p := pointer(integer(p)+8);
  move(pointer(text)^, p^, length(text));
  pointer(s):=p;
  caption:=s;
end;


и при этом никаких утечек памяти не будет. при выходе из процедуры будет вызван freemem.

03-11-2006 09:42
Ну, начнем с того, что данная функция возвращает указатель. Так? А раз так, синьор Буратино, то если пример написан корректно, он и вернет указатель. Вопрос - на что?
Строка
  GetMem(P, размер_под_строку + размер_служебной_информации(8));
действительно возвращает указатель в переменную Р.
А вот строка
  Result := Pointer(Integer(P) + размер_служебной_информации(8));
вернет смещение на 8 байт от начала выделенной области памяти.
Так всё же указатель возвращает эта функция (со смещением на 8)? А если я теперь скажу что так и выделяется место под строку и возвращается результат этой функции с которым ты в последствии и работаешь, то согласишься теперь, что строка это и есть тотже самый pointer, просто назван по другому, и + забота о нём снимается с пользователя (а вот к этой служебной части как раз и тикает счётчик и прописывается длина).

03-11-2006 09:17 | Комментарий к предыдущим ответам
А именно раскрытие указателя - это основной его признак.

А можно источник сего умного изречения? Где вы это вычитали? То есть ткните меня пальцем, где написана такая фраза: "Основной признак указателя, отличающий его от остальных типов - это возможность его раскрытия". Глупо звучит, правда? Определять типы нужно не по возможным операциям с ними, а по, так сказать, физическому смыслу. Кстати, тип Pointer нельзя разадресовывать, если он стоит слева от оператора присваивания, в отличие от типизированных указателей. Начит Pointer, по вашим словам также не указатель в полном смысле этого слова.

Даже если предположить, что вы правы, разадресация при обращении к строке происходит, правда неявно, значит строка - это указатель, так как разадресация - признак указателя.

И вообще, кажется, мы пошли обсуждать тему по второму кругу: мне приходится отвечать на вопросы, на которые я уже ответил. Мои позиции ясны, я их неоднократно аргументировал, а вот что пытаются доказать мои оппоненты - мне так и не понятно, никакой весомой аргументации не вижу. Читайте мои предыдущие ответы, чтобы не задавать снова те же самые вопросы.

Ой-ой! И это слова человека, которому пять человек в течение 30-40 сообщений пытались объяснить, как в Delphi устроены строки. Лучше вам перечитать все сообщения сначала, чтобы понять всю нелепость вашей ситуации.

03-11-2006 08:56 | Комментарий к предыдущим ответам
Даже для PPointer :)

03-11-2006 08:50 | Комментарий к предыдущим ответам
А для Pointer работать не будет потому что для него неизвестна единица смещения, которая для типизированных указателей (PSomeType=^TSomeType;) равна: SizeOf(TSomeType)

03-11-2006 08:48 | Комментарий к предыдущим ответам
Кстати, приведенный пример:

p:pointer
...
inc(p,8) //или dec(p,8);
...
работать не будет в силу незнания автором правил работы с указателями :). Угадайте, почему? Если не сможете - ответ я вам дам позже.


Конкретно для Pointer не будет, но для любого типизированного указателя будет. Я написал Pointer, что бы обобщить понятие указателей, я думаю это понятно.

И вообще, ты софист и попал не на тот форум :)

03-11-2006 07:39
Кажется, данный спор перешел уже в какую-то непонятную абстрактную сферу.


Можно ли из вашего утверждения сделать такой вывод: инкрементировать, декрементировать, смещать значение указателя на какую либо величину нельзя, так как эти операции характерны только для числовых типов, а не для указателей?


Я разве такое где-то говорил? Я четко сказал: арифметические изменение значения указателя НЕ ЯВЛЯЕТСЯ ПРИЗНАКОМ (характеристикой) указателя. И не более того. Я сам очень часто использовал изменение адреса указателей при помощи матопераций (в т.ч. и инкремента/декремента), что позволяло мне не использовать асм.
И вообще, что вы со мной спорите по очевидным (ну, видимо, не для всех) вопросам? Попробуйте реализовать ваши изыски на Дельфи и посмотрите, что получится.
Кстати, приведенный пример:

p:pointer
...
inc(p,8) //или dec(p,8);
...
работать не будет в силу незнания автором правил работы с указателями :). Угадайте, почему? Если не сможете - ответ я вам дам позже.


Если бы, предположим, внутри программы, скрытно, место под новую строку выделялось бы примерно так:
function NewString: pointer;
var
  P: Pointer;
begin
  GetMem(P, размер_под_строку + размер_служебной_информации(8));
  Result := Pointer(Integer(P) + размер_служебной_информации(8));
end;
то можно было бы считать что строка это указатель?


Ну, начнем с того, что данная функция возвращает указатель. Так? А раз так, синьор Буратино, то если пример написан корректно, он и вернет указатель. Вопрос - на что?
Строка
  GetMem(P, размер_под_строку + размер_служебной_информации(8));
действительно возвращает указатель в переменную Р.
А вот строка
  Result := Pointer(Integer(P) + размер_служебной_информации(8));
вернет смещение на 8 байт от начала выделенной области памяти.
Мне непонятно, что вы этим хотите сказать, юноша? И вовсе не стоило для этих целей использовать такую сложную конструкцию, все можно сделать гораздо проще. Но если вы попытаетесь присвоить строке этот указатель без преобразования, то у вас ничего не выйдет. А вот с массивами этот номер проходит. Значит, динамический массив ближе стоит к указателям, чем строка, со всеми вытекающими последствиями. :)

И на счет приведенной цитаты из Борланда - вы просто невнимательно, "по диагонали", читаете мои ответы, я уже говорил, что все ваши упреки должны быть адресованы не мне, а Борланд, которая декларировав имена массивов/строк как указатели, на деле не обеспечила работу с ними как с указателями - т.е., например, раскрыть такие переменные нельзя. А именно раскрытие указателя - это основной его признак. И я уже сказал, каким образом надо трактовать имена строк и массивов - как ссылки, которые можно привести к типу указателя.

И вообще, кажется, мы пошли обсуждать тему по второму кругу: мне приходится отвечать на вопросы, на которые я уже ответил. Мои позиции ясны, я их неоднократно аргументировал, а вот что пытаются доказать мои оппоненты - мне так и не понятно, никакой весомой аргументации не вижу. Читайте мои предыдущие ответы, чтобы не задавать снова те же самые вопросы.

02-11-2006 11:56 | Комментарий к предыдущим ответам
И еще: смотрим в хелпе, что Borland говорит о длинных строках:

AnsiString, also called a long string, represents a dynamically allocated string whose maximum length is limited only by available memory.

A long-string variable is a pointer occupying four bytes of memory. When the variable is empty--that is, when it contains a zero-length string--the pointer is nil and the string uses no additional storage. When the variable is nonempty, it points a dynamically allocated block of memory that contains the string value. The eight bytes before the location contain a 32-bit length indicator and a 32-bit reference count. This memory is allocated on the heap, but its management is entirely automatic and requires no user code.

Because long-string variables are pointers, two or more of them can reference the same value without consuming additional memory. The compiler exploits this to conserve resources and execute assignments faster. Whenever a long-string variable is destroyed or assigned a new value, the reference count of the old string (the variable's previous value) is decremented and the reference count of the new value (if there is one) is incremented; if the reference count of a string reaches zero, its memory is deallocated. This process is called reference-counting. When indexing is used to change the value of a single character in a string, a copy of the string is made if--but only if--its reference count is greater than one. This is called copy-on-write semantics.

То есть Borland называет строку именно указателем (pointer), а не ссылкой (reference)

02-11-2006 11:42 | Комментарий к предыдущим ответам
Да, еще...

Таким образом, "арифметика" указателей не есть характеристика указателя.

Можно ли из вашего утверждения сделать такой вывод: инкрементировать, декрементировать, смещать значение указателя на какую либо величину нельзя, так как эти операции характерны только для числовых типов, а не для указателей?

02-11-2006 09:32 | Комментарий к предыдущим ответам
Loki:
И именно поэтому я так настойчив в четком определении терминологии и понятий: путаницы будет меньше, и работать станет проще, не придется вместо, скажем, создания ПО заниматься изучением работы определенных кодов методом научного тыка.

Путаница возникает не столько из-за самих терминов, но и из-за непонимания, что за этими терминами стоит. Вы это нам наглядно продемонстрировали в примерах со строками, динамическими массивами, функциях GetMem etc... Если нет четкого знания и понимания внутренних механизмов - то получаются догадки, как правило неверные, т.е. тот самый методом научного тыка. И этот метод вы нам здорово продемонстрировали. Так что не вам судить о правильности определений...

Надеюсь, что я вас не обидел, я не эту цель ставлю перед собой.

02-11-2006 09:18
Что значит сместить?
ну тоже самое что и
при выделении памяти под массив или строку Windows выделяет НЕПРЕРЫВНЫЙ блок памяти, а не разбросанный по разным отсекам, и именно это позволяет, получив указатель на первый элемент, обращаться ко всем последующим простым инкрементом этого указателя

не надо пока рассуждать. просто отвечай на вопросы.

Если бы, предположим, внутри программы, скрытно, место под новую строку выделялось бы примерно так:
function NewString: pointer;
var
  P: Pointer;
begin
  GetMem(P, размер_под_строку + размер_служебной_информации(8));
  Result := Pointer(Integer(P) + размер_служебной_информации(8));
end;
то можно было бы считать что строка это указатель?

02-11-2006 09:16 | Комментарий к предыдущим ответам
А если вправо то Inc(P, 8)

02-11-2006 09:15 | Комментарий к предыдущим ответам
Что значит сместить? Значит, содержимое уменьшить на 8? Содержимое находится в переменной-указателе?

P: Pointer;
...
Dec(P, 8)


02-11-2006 09:12
Что значит сместить? Значит, содержимое уменьшить на 8? Содержимое находится в переменной-указателе? Значит, оно является адресом памяти, именно так его будет трактовать компилятор. Однако это можно исправить.
Тут уже все зависит от того, как ты хочешь трактовать это содержимое. Если оно находится в переменной-указателе, то оно является адресом. Если в переменной-целом, то - целым числом. Тут уже все зависит от того, как ты собираешься трактовать это значение. Сделай приведение типа a:integer; pointer(a) - и значение а оказывается указателем, и становится возможным следующее действо: p:pointer; p:=Pointer(a) - и целое число стало указателем. И наоборот. Я, вообще то, об этом уже говорил ранее.

02-11-2006 07:54
Если этот указатель сместить на 8 знаков вправо, то он всё ещё остаётся указателем?

02-11-2006 07:45
Марко Кэнту в своей книге "Delphi 7 для профессионалов" относительно к объектным переменным применил термин "объектная ссылка" (стр. 144, предпоследний абзац). Думаю, что это - наиболее точное определение, которое может подойти и к переменным-массивам/строкам: ссылка на массив и ссылка на строку соответственно. Ссылка не может использоваться как указатель, но ее можно преобразовать в указатель.
Первый параметр GetMem - указатель по определению. И что?

02-11-2006 06:43
Вообще то я говорил про глобальные переменные.
Тогда будьте поточнее в своих высказываниях, так как все ваши предыдущие примеры касались именно процедур и их локальных переменных.
Так почему же переменные-массивы и строки называются указателями? "переменные-массивы", я так понимаю, надо расшифровывать как "динамические массивы"
Потому что в переменной хранится не её значение, а указатель на это значение, по моему это очевидно. В сущности значение (текст в строке) может быть одно, а переменных (ссылок на это значение) с тем же содержимым сколько угодно.

02-11-2006 05:32
Loki: что делает процедура GetMem и можно ли назвать первый параметр, возвращаемый результат работы этой процедуры, указателем?

02-11-2006 04:51
Хм, а разве тут где-то шла речь об арифметике указателей? В конечном счете адрес памяти, хранимый в указателе, является таким же четырехбайтным числом,, с которым можно производить арифметические операции. Правда, для этого нужно компилятору дать понять, как вы хотите трактовать этот адрес, выполнив соответствующее приведение. Таким образом, "арифметика" указателей не есть характеристика указателя. Основные операции, характеризующие указатель - это операция разыменования и обращения по адресу (в т.ч. и взятие адреса), для чего, собственно, указатели и были созданы.
А на счет терминологии - это вы зря. К сожалению, я очень часто сталкивался (да и сейчас иногда с талкиваюсь) с тем, что под одним термином понимается понятие, не совсем характерное (или совсем не характерное) для термина, и наоборот. И именно поэтому я так настойчив в четком определении терминологии и понятий: путаницы будет меньше, и работать станет проще, не придется вместо, скажем, создания ПО заниматься изучением работы определенных кодов методом научного тыка.

02-11-2006 03:53 | Комментарий к предыдущим ответам
Loki:
Радует, что вы теперь хоть понимаете, что собой представляет строка или динамический массив. А спорить насачет терминологии, что же все-таки является указателем можно бесконечно. Ваше определение (указатель - это то, что компилятор понимает как указатель без приведения типов, и то, с чем допустимы все операции, характерные указателем) понятно. Свое (А я указателем считаю все те типы, значения которых является адресом других данных, не зависимо от того нужно ли их разадресовывать явно или это за меня сделает компилятор) я уже изложил ниже.

Можно такой к вам вопрос: арифметику указателей вы считаете неотъемлой операцией, характерной для указателей? Да или нет?

02-11-2006 02:07

Так вот, все переменные в любой программе статичны по своему размещению в памяти, будь то указатель, типизированная переменная, переменная-строка или переменная-массив, они ВСЕГДА располагаются в строго отведенном месте от начала выполнения и до завершения программы.

Оба-на :) Заявления Loki с каждым разом всё круче и круче.
Уважаемый вы про стек когда нибудь слышали? По вашему локальные переменные функций всегда расположены по одному и тому же адресу?



Вообще то я говорил про глобальные переменные. Но если говорить о локальных, располагаемых в стеке (посмотри один из моих предыдущих ответов  - именно это я и утверждал), то при вызове процедуры/функции они ВСЕГДА будут расположены в строго определенном месте стека, по одному и тому же смещению от его начала, и это смещение никогда не меняется, т.е. таким образом можно так же утверждать, что и локальные переменные имеют постоянный относительный (а не абсолютный, как у глобальных переменных) адрес. Это то понятно?

Далее на счет рисунка Ins. Достаточно толковое описание, соответствующее действительности. Но не способ размещения в памяти переменных строк и массивов является камнем преткновения, а то, что называя такую переменную "указателем" мы, тем не менее, не можем использовать ее как указатель без приведения к типу указатель. То же самое касается, например, и переменных типа объект: они вроде как являются указателями, но использовать их как указатели напрямую мы не можем, только через приведение. А приведение - это фактически команда компилятору, каким образом надо трактовать ту или иную переменную. Тот же указатель вы можете трактовать через приведение как целое число, например, p:pointer; integer(p) - и выполнять с ним любые арифметические операции. Но ведь из-за этого почему то никто указатель не называет целым числом. Можете таким же образом привести указатель к типу single и работать с ним как с плавающеточечным  - компилятор вам и слова не скажет. Но когда при попытке использовать имя массива как указатель напрямую, без приведений, компилятор выкидывает Pointer type required, это значит, что он не признает это имя как указатель. Если же я проделываю операцию раскрытия нетипизированного указателя, например: p:pointer; ...; p^:=23; то компилятор выдаст мне другой мессадж: Operator not applicable to this operator type. В переводе на человеческий это означает, что к данному типу оператора данное выражение неприменимо, потому что не указан тип данных, на который ссылается указатель. Но все заработает при приведении: integer(p^):=23 (конечно же размер памяти, на которую ссылается указатель, должен быть не меньше 4 байт). Таким образом, компилятор во втором случае не спорит, что переменная р - указатель. А в первом случае он это с порога отвергает. Отвергаю не я - отвергает компилятор, поэтому все претензии ваши должны быть высказаны не мне, а фирме Борланд: как это, она заявляет, что переменные-массивы, строки и объекты - это указатели, но использовать их как указатели нельзя!
И поэтому я говорю, что такие переменные не являются указателями в полном смысле этого слова, их МОЖНО использовать как указатели, но не более того. И компилятор рассматривает такие переменные как указатели только в определенных условиях, однако он не предоставляет такой возможности программисту.
Когда давно-давно я начинал изучать паскаль, толковой литературы было мало, а остальная изобиловала такими вот "накладками", что приводило к замедлению процесса изучения, потому как компьютера у меня тогда не было, и проверить те или иные постулаты не всегда удавалось. Поэтому, когда я начал реально работать на машине, у меня полезли разные ошибки, причиной которых были именно вот такие объяснения, сбивающие с толку. Кстати, именно поэтому какие-то книги бывает читать легко, потому что там все четко объясняется, а какие то - тяжело, по прямо противоположной причине. И мой совет всем пишущим: сразу вносите полную ясность в ваши материалы. Если переменная - указатель, то значит, ее можно использовать как указатель без дополнительных операций. Иначе это не указатель.
Целое число тоже можно привести к типу single, но вполне вероятно, что значение, которое там хранится в данный момент, может оказаться NAN, и первая же операция с таким числом может привести к исключению. Однако из-за такой возможности приведения никто же не называет целое число числом с плавающей точкой. Так почему же переменные-массивы и строки называются указателями?

01-11-2006 10:16 | Комментарий к предыдущим ответам
кстати: проверять лень, но подозрение, что если ты делаешь так
И не подозрение, а на все 100 процентов утечка памяти размеров в длину строки, так как FreeMem ничего не знает о том что надо удалить не только запись но и содержимое строки S. Тут или Dispose или вручную Finalize.

01-11-2006 10:09 | Комментарий к предыдущим ответам
Видимо в моем "рисунке" следует поменять местами элементы [длина] и [счетчик], но суть от этого не меняется

01-11-2006 10:04
Так вот, все переменные в любой программе статичны по своему размещению в памяти, будь то указатель, типизированная переменная, переменная-строка или переменная-массив, они ВСЕГДА располагаются в строго отведенном месте от начала выполнения и до завершения программы.
Оба-на :) Заявления Loki с каждым разом всё круче и круче.
Уважаемый вы про стек когда нибудь слышали? По вашему локальные переменные функций всегда расположены по одному и тому же адресу?
Проще говоря, при компиляции для переменной типа array так же выделяется строго определенная область памяти, занимающая 12 байт (4 байта - размер, 4 байта - количествос сылок на массив/строку). А вот последние 4 байта (на которые ссылается имя переменной) - это не первый символ, а область памяти, указывающая, где располагается первый символ, который может находиться где угодно, а вовсе не в самой переменной.
Ну что тут сказать: "Остапа несло..." :)
Вам уже говорили о том как устроены строки и динмассивы в Delphi, но вы всё фантазируете и фантазируете.
Структура строк хорошо видна из исходников, например посмотрим как работает функция финализации строки (модуль System.pas):

type
  PStrRec = ^StrRec;
  //Вот эта структура является частью строки и хранит её размер,
  //а также счётчик ссылок и размещается в памяти непосредственно
  //перед первым символом строки.
  StrRec = packed record
    refCnt: Longint;
    length: Longint;
  end;

procedure _LStrClr(var S);
var
  P: PStrRec;
begin
  //Вот тут идёт проверка на то пустая строка или нет
  //причём проверяется только равенство указателя (которым по сути и является строка)
  //нулю и более ничего.
  if Pointer(S) <> nil then
  begin
    //А вот тут компилятор получает указатель на структуру с длиной и счётчиком.
    //Хорошо видно, что делает он это просто вычитая размер структуры из указателя
    P := Pointer(Integer(S) - Sizeof(StrRec));
    //Записываем в переменную (которая указывает на строку) ноль.
    Pointer(S) := nil;
    //Если указатель <0 (=-1), то строка расположена в сегменте кода (то есть это константа) и её не надо удалять
    if P.refCnt > 0 then
      //Уменьшаем счётчик ссылок и если он нулевой, то освобождаем память выделенную под строку
      if InterlockedDecrement(P.refCnt) = 0 then
        //Вот тут советую обратить внимание, что освобождается память отнюдь не с первого символа строки, а с начала структуры StrRec (то есть адрес первого символа минус 8)
        FreeMem(P);
  end;
end;


Вобщем строка устроена так: сама переменная типа String это просто указатель (четыре байта и не на байт больше) на память (или nil, если строка пустая), пусть он содержит 1000, тогда получим следующее
992 счётчик ссылок на данную строку (именно отсюда начинается кусок памяти выделенный GetMem)
996 длина строки, то есть то что возвращает функция Length.
1000 первый символ строки
1001 второй символ строки
...
n    последний символ строки
n+1  ноль (для совместимости с PChar)

01-11-2006 09:36
Вобщем человек в программе что-то ни так делает (ну к примеру тот же move чуть ранее в дискуссии), в результате чего сыпятся ошибки и не хочет ни показать код ни почитать чего-нибудь по теме. Хочет доказать что string не указатель и, даже в независимости кто прав, непонятно что это меняет - всё равно string инициализируется/финализируется сама, по ней хоть перебором s[x], хоть через ^ можно перемещаться вперёд/назад чего ещё надо непонятно.
Loki - чего у тебя там не работает-то, чего бесишься? что за непонимание с new? неужели весь спор из-за того что после new строки и массивы нули, а числа не нули?
-----
кстати: проверять лень, но подозрение, что если ты делаешь так
type
  pt=^tt;
  tt=record
  s:string;
  end;
var
  t: pt;
begin
  t:=allocmem(sizeof(tt));
  t.s:='jjjjjjj';
  freemem(t);
end;
то получаешь утечку памяти...

01-11-2006 09:35
Уважаемый Ins, а куда же вы подевали еще два поля: поле размера строки и поле счетчика ссылок? Они ведь тоже присусттвуют в переменной типа string/array, но только ДО того места, на которое ссылается имя переменной? Видимо, именно поэтому SizeOf возвращает вам 4, а не 12 байт. И подобный аргумент - извините - несерьезен.

Объясняю: Переменная типа String содержит в себе 4-байтное значение (именно поэтому SizeOf возвращает 4, а не потому, как вы предполагаете). Это 4-байтное значение может быть nil - пустая строка, тогда ни о какой длине или счетчике ссыслок речи быть не может, их значения и так понятны и их не нужно где либо хранить. Если значение не nil - то это указатель на данные в динамической памяти. Попытаюсь нарисовать:


            Переменная типа String - 4байта
                    |
                    v
[длина][счетчик][символы строки][символ с кодом "0"]
    4б    4б      [длина]байт      1байт



Надеюсб рисунок получился, если нет, поясню еще раз: значение переменной типа String является указателем на область в динамической памяти. Длина строки храниться не в переменной String, а также в динамической памяти по смещению -8байт, а счетчик ссылок - по смещению -4байт.

И не это пытаются мне доказать, расхождение именно в терминологии: я называю указателем то, к чему можно безо всяких приведений применять операции, типичные для указателя, например, разыменовывание.

А я указателем считаю все те типы, значения которых является адресом других данных, не зависимо от того нужно ли их разадресовывать явно или это за меня сделает компилятор.

01-11-2006 09:14
Уважаемый Ins, а куда же вы подевали еще два поля: поле размера строки и поле счетчика ссылок? Они ведь тоже присусттвуют в переменной типа string/array, но только ДО того места, на которое ссылается имя переменной? Видимо, именно поэтому SizeOf возвращает вам 4, а не 12 байт. И подобный аргумент - извините - несерьезен.


А кто утверждает, что строка содержит первый символ??? Она содержит указатель на первый символ, именно это вам и пытаются доказать уже почти всем Королевством!
...
Компилятор толкует это так: Берем значение, помещенное в "a" и считаем, что это указатель на байт. Он не смотрит, что находиться в переменной "a", строка, Integer или еще что-то.


А я разве с этим спорил? И не это пытаются мне доказать, расхождение именно в терминологии: я называю указателем то, к чему можно безо всяких приведений применять операции, типичные для указателя, например, разыменовывание. Приведение типа можно применить почти к любой переменной, для указателя оно не типично. Другой вопрос, что не всякий код потом будет работать корректно (при неправильном приведении). И под символом понимается исключительно 1 байт информации и не более того, а уж как вы его трактуете - ваши лично дело.



А трюк не проходит, потому что Паскаль - строго типизированный язык, что тоже уже не раз было сказано. Это вам не "СИСИплюс"! Разадресовывыть можно только явные указатели, но ни в коем случае не неявные (классы, длинные строки, динамические массивы). Последние - только жестко приводя типы.


Можно мне не ерничать на эту тему? Потому что я уже как минимум дважды это самое и сказал. Некоторые меня упрекают, что я "читаю по диагонали". Что ж, "каждый может ошибиться - сказал ежик, слезая с кактуса". Но, как видимо, не я один такой. :)


01-11-2006 08:52 | Комментарий к предыдущим ответам
Компилятор толкует это так: Берем значение, помещенное в "a" и считаем, что это указатель на байт. Он не смотрит, что находиться в переменной "a", строка, Integer или еще что-то.

Сорри, не заметил значок разадресации. Точнее будет так:
Берем значение, помещенное в "a" и считаем, что это указатель на байт и производит операцию разадресации, т.е. возвращает этот самый байт.

01-11-2006 08:47 | Комментарий к предыдущим ответам
Но это не простые указатели, а указатели на указатели.
Нет. Это указатель на область в динамической памяти, где хранится как строка/массив так и служебная информация о ней (счетчик ссылок, длина)

Проще говоря, при компиляции для переменной типа array так же выделяется строго определенная область памяти, занимающая 12 байт (4 байта - размер, 4 байта - количествос сылок на массив/строку).
Нет - 4 байта - указатель!!! Проверяется элементарно:

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
  Caption:=IntToStr(SizeOf(s));
end;



А вот последние 4 байта (на которые ссылается имя переменной) - это не первый символ, а область памяти, указывающая, где располагается первый символ, который может находиться где угодно,
Абсолютно верно, только не последние, а единственные. Если строка пустая, то значение этого указателя Nil.
а вовсе не в самой переменной.
А кто утверждает, что строка содержит первый символ??? Она содержит указатель на первый символ, именно это вам и пытаются доказать уже почти всем Королевством!

И именно поэтому трюк a^ не проходит.
А трюк не проходит, потому что Паскаль - строго типизированный язык, что тоже уже не раз было сказано. Это вам не "СИСИплюс"! Разадресовывыть можно только явные указатели, но ни в коем случае не неявные (классы, длинные строки, динамические массивы). Последние - только жестко приводя типы.

А вот приведение, например, pbyte(a)^ позволяет компилятору толковать, что вас интересует именно первый символ, расположенный по адресу, находящемуся в этом месте.
Компилятор толкует это так: Берем значение, помещенное в "a" и считаем, что это указатель на байт. Он не смотрит, что находиться в переменной "a", строка, Integer или еще что-то.

01-11-2006 08:30 | Комментарий к предыдущим ответам
Loki:
Кстати, в своем ответе, где пишется:
  p:^Char;
  ...
  p:=pointer(s)
он опять же работает не с именем строки-указателем, а приводит имя переменной к типу указатель (pointer(s)) и работает с переменной-указателем (p^), передергивая тем самым факты и подтверждая мою правоту.


Вы действительно читаете по диагонали видимо, вам Антон Григорьев написал, на что компилятор заменяет эту конструкцию:
mov eax,[ebp-$08]
mov [ebp-$10],eax

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


Что подтверждает вашу неправоту. Не думайте, что здесь все зеленые новички и только у вас с вашим огромнейшим стажем программирования правильные мысли. Пока что очевидно обратное... Глупости пишите!

01-11-2006 08:23 | Комментарий к предыдущим ответам
31-10-2006 08:24 | Антон Григорьев

Читая Ваши ответы по поводу того, является или нет переменная типа String или Array указателем, у меня создается впечатление, что вы не совсем верно понимаете, чем динамические переменные отличаются от статических. Так вот, все переменные в любой программе статичны по своему размещению в памяти, будь то указатель, типизированная переменная, переменная-строка или переменная-массив, они ВСЕГДА располагаются в строго отведенном месте от начала выполнения и до завершения программы. Однако, например, типизированная переменная при компиляции превращается в ссылку на область память, содержащую данные определенного размера и поэтому никогда не меняющуюся по этому параметру. В то же время как, например, переменная типа pointer, всегда находясь в одном и том же месте, сама может указывать на данные, находящиеся в разных местах памяти, проще говоря, четыре байта, которые занимает тип pointer, от самого запуска и до завершения программы всегда находятся в строго определенном месте памяти, однако содержат в себе данные, указывающие на какую-то определенную область памяти. Надеюсь, это понятно и с этим никто спорить не будет?
Переменные типа string и array - это действительно указатели. Но это не простые указатели, а указатели на указатели. Проще говоря, при компиляции для переменной типа array так же выделяется строго определенная область памяти, занимающая 12 байт (4 байта - размер, 4 байта - количествос сылок на массив/строку). А вот последние 4 байта (на которые ссылается имя переменной) - это не первый символ, а область памяти, указывающая, где располагается первый символ, который может находиться где угодно, а вовсе не в самой переменной. И именно поэтому трюк a^ не проходит. А вот приведение, например, pbyte(a)^ позволяет компилятору толковать, что вас интересует именно первый символ, расположенный по адресу, находящемуся в этом месте. И именно такая организация строк и массивов позволяет сделать их динамическими, т.е. изменять их размер в процессе выполнения программы функцией SetLength. Если вы не в курсе, каким образом это происходит, то поясню, что при выделении памяти под массив или строку Windows выделяет НЕПРЕРЫВНЫЙ блок памяти, а не разбросанный по разным отсекам, и именно это позволяет, получив указатель на первый элемент, обращаться ко всем последующим простым инкрементом этого указателя на размер элемента массива(практически так же, как и в С/С++), что я, например, делал очень часто.
Именно это я и подразумевал, когда говорил, что имена массивов и строк - это не указатели в полном смысле этого слова. И в приведенной ссылке на ваш текст стоит написать, не что "имена массивов - это указатели", а "их можно трактовать как указатели, использовать приведение типов например". Указатель - это то, с чем работает безо всяких приведений конструкция типа a^.

01-11-2006 07:32
Он должен быть нулевым - почитай лучше предыдущие ответы, где отдельные товарищи с надрывом убеждали меня, что все локальные переменные обнуляются.

Покажи конкретно где это тебе утверждали подобное???? Тебе говорили не за скалярные типы а за автоматически финализируемые!!!

"Вы говорите, что New не используете, потому что оан непонятно чем заполняет" - этого я вообще не говорил, это уже вранье.

Да ну значит я уже вру? Это чьи слова?

При использовании, как правило, эта переменная заполнялась различными данными, а не какими то одинаковыми во всех случаях жизни. И именно поэтому я никогда и не использовал процедуру New. Как раз использование AllocMem приводит к заполнению одинаковыми на все случаи жизни значениями, а New просто подгатавливает автоматически финализируемые переменные к работе после выделения памяти.

Как ты думаешь такой код выглядит в машином виде?

p:=pointer(s)

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

"зачем скалярные типы данных нулями инициализировать, если вы все равно будете их записывать" - я уже ответил на этот вопрос в моем предыдущем ответе, почитай внимательнее, прежде чем писать такие вопросы. да ну, опять же.. тебе никто не утверждал что инициализируются все локальные переменные, а ты это доказуешь...

Вообщем, бля, не умничай, а просто подумай.

01-11-2006 07:01

Тебе не надоело? Ты пишешь, что у тебя локальный Integer не очищается  а куда он должен очищаться? Тебе никто и не говорил про скалярные типы данных - тебе конкретно говорили про финализируемые типы, а-ля длинные строки и динамические массивы. Ты пишешь, что имя строки это не указатель на первый символ строки и приводишь даже аргументацию, а тебе не приходило в голову почему твоя конструкция s^ не нравится компилятору? Потому, что Object Pascal строго типизированный язык не подразумевает неявного преобразования типов для таких вариантов. Простым явным приведением типа Pointer(s)^ вы получите первый символ строки (такая запись необходима дял защиты от ошибок - т.е. вы явно говорите компилятору, что знаете , что творите). Вы говорите, что New не используете, потому что оан непонятно чем заполняет - вам нравится самим заливать нули для всей записи - зачем спрашивается, зачем скалярные типы данных нулями инициализировать, если вы все равно будете их записывать? New все делает правильно, инициализирует только финализируемые типы. Может хватит уже стоять на своем, просто постарайся вникнуть, а не лезть на рожон.


Он должен быть нулевым - почитай лучше предыдущие ответы, где отдельные товарищи с надрывом убеждали меня, что все локальные переменные обнуляются. Не все и не всегда.
На счет того, что Паскаль - строго типизированный язык - именно я уже это говорил, опять же почитай предыдущие ответы. Именно я сказал, что переменная строки/массива должна быть приведена к типу указатель из-за этой типизации. Но человек уперся - и ни в какую. Кстати, в своем ответе, где пишется:
  p:^Char;
  ...
  p:=pointer(s)
он опять же работает не с именем строки-указателем, а приводит имя переменной к типу указатель (pointer(s)) и работает с переменной-указателем (p^), передергивая тем самым факты и подтверждая мою правоту. Но об этом я еще поговорю.
 
"Вы говорите, что New не используете, потому что оан непонятно чем заполняет" - этого я вообще не говорил, это уже вранье.
"зачем скалярные типы данных нулями инициализировать, если вы все равно будете их записывать" - я уже ответил на этот вопрос в моем предыдущем ответе, почитай внимательнее, прежде чем писать такие вопросы.

На все остальные претензии и "аргументы" я отвечу позже и приведу фрагменты моих программ, где я использовал (вынужден был использовать) FillChar. Но уже сейчас могу сказать: у меня начало складываться впечатление, что все нижеизложенное - результат слишком малой практики тех, кто пытается со мной спорить. Ребята, чем вы занимаетесь по работе? Рисуете программы мышкой или вообще вся ваша работа заключается в установке софта и ПО? Почему вы даже не хотите слушать и стремитесь доказать свою правоту любой ценой? Может, вам действительно просто не хватает практики реального программирования (написание векторных программулин я к таким не отношу).

01-11-2006 03:03 | Комментарий к предыдущим ответам
Мне еще ни разу при использовании процедуры GetMem не требовалось заполнять новую переменную чем-то еще. При использовании, как правило, эта переменная заполнялась различными данными, а не какими то одинаковыми во всех случаях жизни. И именно поэтому я никогда и не использовал процедуру New.

Вообще не понял, что вы хотите сказать. С вашим утверждением про GetMem согласен: эта функция действительно просто выделяет память, не модифицируя её, и что там окажется - дело случая. А вот как из этого вы делаете вывод о том, что применять New не стоит - не понял.

Далее, очень часто мне приходилось перед первым использованием локальной структурной переменной использовать функцию FillChar, которая как раз и "тупо заполняет" нулями все поля таких переменных, иначе при начале работы с теми же массивами возникал эксепшн. Если локальная переменная "очищается" при входе в процедуру, то почему эксепшен то выскакивает при первом обращении к ней? (это касается и массивов, и строк, и более сложных структур).

Конкретный пример такого кода будет? Или я в очередной раз должен буду читать пространные рассуждения, ничем не подкреплённые? Пока не будет кода, всё это - пустой трёп.

Я разве говорил это про New? Этот оператор как раз и очищает память. Но его недостаток только в том, что он может применяться только к типизированным указателям. С простыми же указателями он не работает.

Типизированные указатели New тоже не инициализирует. Или вы считаете, что string'и и динамические массивы как раз и называются типизированными указателями? Нет, они называются автоматически финализируемыми типами. А типизированные указатели - это нечто совсем другое. Если вы этого не знаете - откройте книгу и прочитайте, чтобы хотя бы в базовой терминологии не путаться.

Является, и проверяется это элементарно.

Пример в студию - отучайтесь быть голословным.


Ха-ха-ха, кто бы говорил насчёт голословия :)))

Что же касается конкретного случая - а речь шла о том, чтобы проверить, как на самом деле хранятся указатели на строки, массивы и т.п., то тут никакой высокоуровневый код сам по себе в принципе не может быть ни доказательством, ни опровержением, т.к. обязательно будет задействовать механизм преобраования типов, который вы и подвергаете сомнению. Доказательством может быть только исследование того кода, который даёт компиялтор. Если вы сами это не сделали, привожу вам такой код.

procedure TForm1.Button1Click(Sender: TObject);
var
  S,R:string;
  P:^Char;
begin
  S:='abcd';
  P:=Pointer(S);  {*}
  while P^<>#0 do
  begin
    R:=R+P^;  {**}
    Inc(P)
  end;
  Label1.Caption:=R
end;



После его выполнения в Label1.Caption оказывается 'abcd'. Надеюсь, вы считаете это достаточным доказательством того, что в P в строке {*} записывается именно указатель на первый символ строки, а не что либо иное. Теперь осталось разобраться, что происходит в самой этой строке. В моём случае ей соответствует такой код (только оптимизацию надо отключить, а то оптимизатор размещает переменную P не в стеке, а в регистре ESI):

Unit1.pas.32: P:=Pointer(S);
mov eax,[ebp-$08]
mov [ebp-$10],eax

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

Кстати, я писользовал тип ^Char и приведение к Pointer, а не PChar потому, что приведение string'а к PChar - это точно не просто копирование. Там особым образом обрабатываются пустые строки, и использование PChar нарушило бы чистоту эксперимента. А так, надеюсь, я вас убедил, что в S хранится именно указатель на первый символ строки.

Кстати, обратите внимание, что при компиляции этого кода никаких предупреждений об использовании неинициализированной переменной R в строке {**} не будет, хотя явно переменная не инициализирована. Если бы вы попытались сделать то же самое, скажем, с целочисленной переменной, то предупреждение было бы. А знаете почему? Потому что локальные строковые переменные, в отличие от Integer'ов, инициализируются пустым значением, и такое их использование безопасно.

В данном случае речь шла о строках и массивах, имеющих несколько более сложные структуры, чем простой указатель.

Пусть S - переменная типа string, A - динамический массив любого типа. SizeOf(S) и SizeOf(A) при любых значениях S и A вернут 4 - можете проверить, если не верите. Размер указателя в 32-разрядной Windows - тоже 4 байта. Объясните, откуда в этих переменных найдётся место для хранения чего-то ещё, кроме указателя?

при работе с указателями размер выделенной памяти находится непосредственно перед первым байтом, иначе его пришлось бы всегда указывать в процедуре FreeMem.

Насчёт FreeMem всё правильно. Только размер динамического массива и длина строки, хранящиеся по отрицательному смещению, - это совсем не то, хотя механизм очень похож. Во-первых, динамические массивы и строки имеют ещё и счётчик ссылок, а во-вторых, хранят число символов или элементов, а не размер выделенной памяти в байтах. Так что не путайте похожие, но разные вещи.

На самом деле значение nil - это, в компьютерном понимании определенная константа, так или иначе трактуемая компилятором. Как правило, это 0.

Во всех известных мне случаях и во всех известных мне версиях Delphi это всегда аппаратный ноль. Если знаете хоть один контрпример - привидите, а то опять получается философия на пустом месте.

Однако если у меня указатель на первый символ равен Nil (0), а размер строки (массива) неожиданно оказывается каким то числом, отличным от нуля, то вполне вероятно, что компилятор, видя такой размер, воспринимает следующее число как указатель на начало строки/массива и генерирует код, работающий с ним, что и приводит к исключению. И именно поэтому динамические, а так же локальные структурные переменные необходимо обнулять.

Это даже не комментирую, потому что вы опять исходите из ложного предположения, что размер хранится якобы в самой переменной, а не в той области памяти, на которую она указывает.

Очень часто у меня возникала следующая ситуация, когда в локальную переменную передавался определенный массив, не нулевой (или не пустая строка)и мне требовалось считать или записать при помощи локальной переменной целого типа нулевой элемент этого массива. Я так же наивно полагал, что локальные переменные уже очищены и всегда равны нулю и, не инициализируя их, тут же пытался  сделать это обращение, в результате чего тут же получал исключение и программа вылетала. Пошаговый анализ показал, что на самом деле в переменной типа integer, которая по идее должна была быть "очищена" оказывалось громадное число (ну, например, 569451354, чтобы понятнее было), которое значительно превышало размерность массива. <...> Этот практический опыт в корне отвергает вашу теорию о том, что, дескать "все локальные переменные очищаются". Не очищаются, это уже из практики. И необходимости в очистке таких переменных нет, тут компилятор Delphi совершенно прав. Объяснить, почему, или сами догадаетесь?

Можно вас попросить: в следующий раз внимательнее читайте то, что я написал, чтобы не приписывать мне то, чего я не говорил. Когда я говорил, что ВСЕ локальные переменные автоматически инициализируются? Я говорил только о том, что инициализируются ВСЕ АВТОМАТИЧЕСКИ ФИНАЛИЗИРУЕМЫЕ локальные переменные. Вот точная цитата из моего сообщения от 30-10-2006 09:30: "Локальные переменные всех автоматически финализируемых типов (string'и, варианты, интерфейсы, динамические массивы) в прологе функции обязательно инициализируются пустым значением. Это только в нефинализируемых типах вроде того же double может оказаться что угодно, а строка обязательно будет пустой". А вот ещё одна, из моего же сообщения от 31-10-2006 04:06: "Лучше всего попытаться не инициализировать переменные, а сразу посмотреть, какие там значения. Попробуйте и убедитесь, что в большинстве случаев там будут отнюдь не нули. А вот чтобы строка без инициализации оказалась не пустой - с таким вы точно никогда не столкнётесь." Речь там, кстати, шла как раз о целочисленных переменных. Так что я не только не утверждал, что Integer'ы должны автоматически инициализироваться нулями, а говорил прямо противоположное. Так что к чему вы всё это написали - непонятно.

Возникает подозрение, что вы не читаете то, что я пишу, а так, по диагонали просматриваете.

На самом деле если бы имя строки типа массива было бы указателем на первый элемент, то выражение, например, a^ возвращало бы мне именно этот первый символ строки. Однако при использовании такой конструкции компилятор ругается: Pointer type required, что как раз и означает, что имя строки НЕ ЯВЛЯЕТСЯ указателем на первый символ, компилятор это подтверждает.

Компилятор подтверждает лишь то, что он не рассматривает данный указатель как настоящий указатель, и защищает программиста от некорректных операций с этим типом. Но приведение типов позволяет это преодолеть. Надеюсь, приведённый выше пример с конвертацией строки в Pointer вас всё же убедил. Можете проделать аналогичные эксперименты с динамичаскими массивами - получите тот же самый результат.

же тогда вы до сих пор не смогли объяснить природу возникновения исключений в указанном мной примере?

А вот это уже - очень серьёзное оскорбление. В своём сообщении от 31-10-2006 04:06 я подробно разобрал ваш эксперимент и объяснил полученные результаты (кстати, у меня они получились не такие, как у вас). Ну да, я забыл, что вы мои сообщения поверхностно смотрите, а не читаете.

P.S. Я сегодня уезжаю, так что отсутствие в течение ближайших нескольких дней ответов от меня - это не потеря интереса к теме, а просто отсутствие возможности. Когда вернусь, обязательно отвечу, если вы что-нибудь напишите.

01-11-2006 02:10
Loki:
Тебе не надоело? Ты пишешь, что у тебя локальный Integer не очищается  а куда он должен очищаться? Тебе никто и не говорил про скалярные типы данных - тебе конкретно говорили про финализируемые типы, а-ля длинные строки и динамические массивы. Ты пишешь, что имя строки это не указатель на первый символ строки и приводишь даже аргументацию, а тебе не приходило в голову почему твоя конструкция s^ не нравится компилятору? Потому, что Object Pascal строго типизированный язык не подразумевает неявного преобразования типов для таких вариантов. Простым явным приведением типа Pointer(s)^ вы получите первый символ строки (такая запись необходима дял защиты от ошибок - т.е. вы явно говорите компилятору, что знаете , что творите). Вы говорите, что New не используете, потому что оан непонятно чем заполняет - вам нравится самим заливать нули для всей записи - зачем спрашивается, зачем скалярные типы данных нулями инициализировать, если вы все равно будете их записывать? New все делает правильно, инициализирует только финализируемые типы. Может хватит уже стоять на своем, просто постарайся вникнуть, а не лезть на рожон.

01-11-2006 02:05
Да, и вот еще одно:


Вы бы, прежде чем теоретизировать, почитали бы базовые вещи. А то вроде догадываетесь, но знаний катастрофически не хватает.


Да, это правда, приходится много работать, постоянно что-то новое изучать, поэтому просто нет времени (и электричества, да, в прочем, и необходимости) влезать в мелкие детали. Но зато у меня имеется достаточно большой практический опыт работы. Если у Вас есть время - пожалуста, приведите свои доводы, обоснуйте их, буду весьма признателен.

01-11-2006 01:55

К локальным переменным AllocMem отношения не имеет (равно как New и GetMem). В остальном - правильно. AllocMem, о чём мы вам уже ктороый раз твердим, тупо заполняет всё нулями. В результате все указатели (как простые, так и автоматически финализируемые) получают значения nil. Поэтому всё в порядке.


Мне еще ни разу при использовании процедуры GetMem не требовалось заполнять новую переменную чем-то еще. При использовании, как правило, эта переменная заполнялась различными данными, а не какими то одинаковыми во всех случаях жизни. И именно поэтому я никогда и не использовал процедуру New.
Далее, очень часто мне приходилось перед первым использованием локальной структурной переменной использовать функцию FillChar, которая как раз и "тупо заполняет" нулями все поля таких переменных, иначе при начале работы с теми же массивами возникал эксепшн. Если локальная переменная "очищается" при входе в процедуру, то почему эксепшен то выскакивает при первом обращении к ней? (это касается и массивов, и строк, и более сложных структур). Ответ может быть только один и я его уже приводил (кстати, не я его придумал, прочитал, и кажется, где-то здесь в материалах королевства о том, что локальные переменные размещаются в стеке при входе в процедуру и память под ними не очищается. Именно эта информация и позволила мне использовать AllocMem и FillChar и мои проги заработали как надо).


Приведите пример кода, в котором локальная переменная или поле структуры, выделенной с помощью New, имеет непустое значение. Готов спорить, что такого кода вы не приведёте. Вы просто что-то перепутали. А если вы опять про GetMem вспомите, то обратите внимание - мы все как раз и утверждаем, что GetMem, в отличие от New, вызывает такие проблемы.


Я разве говорил это про New? Этот оператор как раз и очищает память. Но его недостаток только в том, что он может применяться только к типизированным указателям. С простыми же указателями он не работает. Речь в данном абзаце шла о локальных переменных.


Является, и проверяется это элементарно.


Пример в студию - отучайтесь быть голословным.


Впечатление такое, будто вы думаете, что длина хранится рядом с самим указателем. На самом деле она хранится в динамической памяти, непосредственно перед первым байтом.


Хм.. Гм... Наверно мне придется всегда указывать, о чем идет речь. Я знаю, что при работе с указателями размер выделенной памяти находится непосредственно перед первым байтом, иначе его пришлось бы всегда указывать в процедуре FreeMem. В данном случае речь шла о строках и массивах, имеющих несколько более сложные структуры, чем простой указатель.


Клюква. Однозначно. Почему бы вам просто не подучить матчасть, прежде чем строить предположения? Значение nil - нормальное для таких указателей, как раз оно-то и не вызывает никаких проблем. Оно означает пустую строку, массив и т.п., и компилятор, встречая такое значение, не пытается ни осводождать его, ни читать память по этому указателю. С чего вы вдруг решили, что nil - это плохо, непонятно.

P.S. А вы вот это читали? http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1206


На самом деле значение nil - это, в компьютерном понимании определенная константа, так или иначе трактуемая компилятором. Как правило, это 0. Однако если у меня указатель на первый символ равен Nil (0), а размер строки (массива) неожиданно оказывается каким то числом, отличным от нуля, то вполне вероятно, что компилятор, видя такой размер, воспринимает следующее число как указатель на начало строки/массива и генерирует код, работающий с ним, что и приводит к исключению. И именно поэтому динамические, а так же локальные структурные переменные необходимо обнулять.
Кстати, в поддержку своих слов приведу еще такой пример. Очень часто у меня возникала следующая ситуация, когда в локальную переменную передавался определенный массив, не нулевой (или не пустая строка)и мне требовалось считать или записать при помощи локальной переменной целого типа нулевой элемент этого массива. Я так же наивно полагал, что локальные переменные уже очищены и всегда равны нулю и, не инициализируя их, тут же пытался  сделать это обращение, в результате чего тут же получал исключение и программа вылетала. Пошаговый анализ показал, что на самом деле в переменной типа integer, которая по идее должна была быть "очищена" оказывалось громадное число (ну, например, 569451354, чтобы понятнее было), которое значительно превышало размерность массива. Ну, и, разумеется, при обращении к несуществующему элементу массива с таким индексом я тут же получал ошибку. Именно это и заставило меня перед началом работы вручную инициализировать все нужные переменные нужными значениями, иногда я даже писал для этих целей локальные по отношению к текущей процедуры. Этот практический опыт в корне отвергает вашу теорию о том, что, дескать "все локальные переменные очищаются". Не очищаются, это уже из практики. И необходимости в очистке таких переменных нет, тут компилятор Delphi совершенно прав. Объяснить, почему, или сами догадаетесь?

Это: А вы вот это читали? http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1206 прочитал. Теперь понятны причины такого ожесточенного спора. :) На самом деле если бы имя строки типа массива было бы указателем на первый элемент, то выражение, например, a^ возвращало бы мне именно этот первый символ строки. Однако при использовании такой конструкции компилятор ругается: Pointer type required, что как раз и означает, что имя строки НЕ ЯВЛЯЕТСЯ указателем на первый символ, компилятор это подтверждает. То же самое касается и имени массива, компилятор так же выкидывает то же самое сообщение, т.е. для него имя массива НЕ ЯВЛЯЕТСЯ УКАЗАТЕЛЕМ, он его не воспринимает как указатель. Для этого это имя нужно сначала привести к типу указателя. Надеюсь, эти доводы убедительны, или вы опять с упорством, достойным лучшего применения, будете толочь воду в ступе? Учитесь признавать свои заблуждения.

И самое главное. Если вы считаете себя крутым специалистом в Delphi, то почему же тогда вы до сих пор не смогли объяснить природу возникновения исключений в указанном мной примере? Я дал свою теорию, теперь хотел бы услышать от вас чего-нибудь по теме.
(Уточняю проблему: в структуре, содержащей строку и массив обращении к одному из элементов проходит без проблем, а к другому - возникает исключение. Переменной-указателю такого типа память выделяется функцией GetMem).





31-10-2006 08:24 | Комментарий к предыдущим ответам
Loki:

Вы бы, прежде чем теоретизировать, почитали бы базовые вещи. А то вроде догадываетесь, но знаний катастрофически не хватает.

Но тогда объясните: почему же исключение все-таки возникает при использовании GetMem, в то время, как при AllocMem такого не происходит? В чем причина, если не в неочистке локальных статических или вновь выделенных по процедуре GetMem переменных от предыдущих значений?

К локальным переменным AllocMem отношения не имеет (равно как New и GetMem). В остальном - правильно. AllocMem, о чём мы вам уже ктороый раз твердим, тупо заполняет всё нулями. В результате все указатели (как простые, так и автоматически финализируемые) получают значения nil. Поэтому всё в порядке.

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

Приведите пример кода, в котором локальная переменная или поле структуры, выделенной с помощью New, имеет непустое значение. Готов спорить, что такого кода вы не приведёте. Вы просто что-то перепутали. А если вы опять про GetMem вспомите, то обратите внимание - мы все как раз и утверждаем, что GetMem, в отличие от New, вызывает такие проблемы.

Скорей всего, в реальности имя массива не является указателем на первое его значение, просто в компилятор встроена возможность корректного приведения типов, и встретив, такое приведение, компилятор просто подставляет адрес первого элемента массива.

Является, и проверяется это элементарно.

И в полях размера и указателя на первый байт могут находиться неопределенные значения.

Впечатление такое, будто вы думаете, что длина хранится рядом с самим указателем. На самом деле она хранится в динамической памяти, непосредственно перед первым байтом.

Скорей всего потому, что при изменении длины строки/массива функция SetLength одним из своих действий проверяет текущую длину строки/массива, и если она не нулевая (что возможно как для статической локальной переменной, так и для динамической переменной, выделенной процедурой GetMem), пытается удалить память, на которую ссылается указатель первого элемента. Но (как ранее правильно замечено) так как он равен нулю, т.е. указывает на нулевой адрес памяти, то попытка очистить эту память и вызывает эксепшн.

Клюква. Однозначно. Почему бы вам просто не подучить матчасть, прежде чем строить предположения? Значение nil - нормальное для таких указателей, как раз оно-то и не вызывает никаких проблем. Оно означает пустую строку, массив и т.п., и компилятор, встречая такое значение, не пытается ни осводождать его, ни читать память по этому указателю. С чего вы вдруг решили, что nil - это плохо, непонятно.

P.S. А вы вот это читали? http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1206

31-10-2006 08:19 | Комментарий к предыдущим ответам
Парень, тебе же уже объяснили всю суть, просто почитай чужие ответы.

Использование New - наиболее целесообразно для выделения памяти для структур данных, содержащих динамические массивы или длинные строки.

GetMem это не New - а лишь один из этапов New, который выделяет память. AllocMem отличается от New тем, что инициализирует нулями область памяти, а New вызывает нужные процедуры для корректной инициализации этих самых массивов и строк. AllocMem нужна там где память должна быть инициализирована нулями - при передачи буфера например в нек-ые SH функции. New - предпочтительно использовать в любом выделении памяти под свои записи со сложными структурами для внутреннего использования.

31-10-2006 08:09
Кстати, я кажется, понял, почему обращение к строке или массиву при использовании функции GetMem или (иногда) к локальной переменной может вызвать эксепшн. Скорей всего потому, что при изменении длины строки/массива функция SetLength одним из своих действий проверяет текущую длину строки/массива, и если она не нулевая (что возможно как для статической локальной переменной, так и для динамической переменной, выделенной процедурой GetMem), пытается удалить память, на которую ссылается указатель первого элемента. Но (как ранее правильно замечено) так как он равен нулю, т.е. указывает на нулевой адрес памяти, то попытка очистить эту память и вызывает эксепшн. Впрочем, значение указателя может быть и не нулевым, однако в любом случае оно будет ссылаться на ту область памяти, которая либо не числится в системных таблицах Windows (свободна), либо не принадлежит процессу, либо имеет спацифические атрибуты, препятствующие очистке (например, отмечена как execute).

31-10-2006 07:25
Я не совсем понял, какой именно код обсуждается, возможно, я не так силен в ассемблере, как мне того бы хотелось бы, что, впрочем, не мешает проанализировать код в дальнейшем. Но тогда объясните: почему же исключение все-таки возникает при использовании GetMem, в то время, как при AllocMem такого не происходит? В чем причина, если не в неочистке локальных статических или вновь выделенных по процедуре GetMem переменных от предыдущих значений? Перед тем, как дойти да причины ошибок в работе программ, я не раз просматривал при отладке значения структур. Так вот, в массивах, которые, по идее, должны быть "автоматически очищенными", почему то вдруг оказывалось огромное количество элементов, первая же попытка обращения к которым тут же приводила к исключению. Строки, которые так же должны были быть "пустыми", оказывались заполненными непонятной абракадаброй. Единственный ответ, который лично я могу дать: при инициализации такие переменные очищаются от предыдущих значений далеко не всегда. И в полях размера и указателя на первый байт могут находиться неопределенные значения. И разумеется, если, скажем, в указателе массива на первый байт содержится какое то число, но память под массив в реальности не выделена, то обращение по этому адресу тут же генерирует исключение.
Кстати, об именах массивов и указателях. Скорей всего, в реальности имя массива не является указателем на первое его значение, просто в компилятор встроена возможность корректного приведения типов, и встретив, такое приведение, компилятор просто подставляет адрес первого элемента массива.

31-10-2006 05:52
компилятором не пропускаются, что лишний раз свидетельствует о том, что переменные подобного типа не инициализируются (иначе зачем борландский оптимизатор их тоже не пропускает?)
Чтобы в следующий раз не оказаться в столь глупом положении, советую сначала посмотреть на тот код который генерирует компилятор. Поставьте точки останова на begin и end (именно на них, а не на строки самой процедуры) и нажмите Ctrl+Alt+C. Теперь видно что в прологе и эпилоге присутствуют примерно такие строки:

asm
  xor eax,eax
  mov [ebp-$1c],eax      //Тут инициализируется строка S (ноль туда пишется)
  lea eax,[ebp-$24]      //Адрес A:TMyData
  mov edx,[$0053518c]    //Указатель на TypeInfo для TMyData
  call @InitializeRecord //А вот и вызов Initialize
  xor eax,eax            // Ну тут просто ExceptionFrame создаётся
  push ebp              // то есть ключевое слово try
  push $00535219
  push dword ptr fs:[eax]
  mov fs:[eax],esp
  //Сама процедура
  mov fs:[eax],edx      //Это соответствует слову finally
  push $00535220
  lea eax,[ebp-$24]      //Снова А
  mov edx,[$0053518c]    // TypeInfo
  call @FinalizeRecord  //И теперь уже Finalize
  lea eax,[ebp-$1c]      //Адрес строки S
  call @LStrClr          //Очистка строки S
  ret                    //Тут end от finally..end
end;


В итоге код на паскале который генерирует компилятор будет следующий:

begin
  Pointer(S):=nil;
  Initialize(A);
  try
    ...
  finally
    Finalize(A);
    S:='';      //Для строк нет аналога Finalize,
                //а LStrClr доступен только из асма.
  end;
end;



31-10-2006 04:06 | Комментарий к предыдущим ответам
А вот и нет. И доказательство тому - сделующий код:

Var i:integer;
    j,k,m:double;
    s:string;
    a:TMyData;
begin
  i:=0;
  j:=0;
  k:=0;
  m:=0;
  s:='';
  a.a:='';
  SetLength(a.b,0);
  ...
end;

Убедитесь, что при попытке компиляции компилятор действительно пропустит следующие строки )(где бы они не стояли):
  i:=0;
  j:=0;
  k:=0;
  m:=0;
потому что эти типы действительно инициализируются нулями (хотя опять же из своего опыта говорю - такое бывает только в самых простых случаях, как, например, в приведенном; часто бывало, что у меня пропускалась только одна подобная строка)
Однако строки
  s:='';
  a.a:='';
  SetLength(a.b,0);
компилятором не пропускаются, что лишний раз свидетельствует о том, что переменные подобного типа не инициализируются (иначе зачем борландский оптимизатор их тоже не пропускает?)


Мало получить экспериментальные результаты, надо ещё правильно их интерпретировать :) Да и эксперименты надо ставить правильно :)))))

Лучше всего попытаться не инициализировать переменные, а сразу посмотреть, какие там значения. Попробуйте и убедитесь, что в большинстве случаев там будут отнюдь не нули. А вот чтобы строка без инициализации оказалась не пустой - с таким вы точно никогда не столкнётесь.

Что касается вашего кода - оптимизатор легко определяет, что значения, присвоенные переменным простых типов, в дальнейшем никак не используются, и поэтому выкидывает эти присваивания. Именно поэтому, а вовсе не потому, что там якобы и так нули. А вот присваивания сложных типов - это не просто помещение какого-то значения в определённую ячейку памяти, эти присваивания могут сопровождаться перераспределением памяти, которое, в принципе, оказывает влияние на другие переменные и участки программы. И отследить, когда присваивание можно безболезненно убрать, а когда - необходимо оставить - задача в общем случае очень сложная, оптимизатору она не по зубам. Поэтому он НИКОГДА не выкидывает такие присваивания.

Проверил. Пошагово. Исключение происходит не в первой, а именно в той строке, в которой происходит обращение к второму элементу структуры - массиву или строке.

Я тоже проверил, и получил другой результат: у меня исключение возникает всегда на строке SetLength(a^.Arr,23), независимо от того, идёт ли она второй или первой. Это было потому, что Pointer(a^.b) был равен nil (что соответствует пустой строке), а Pointer(a^.Arr) - $C, и попытка работы с таким массивом приводила к ошибке. Но стоило мне перед GetMem'ом вставить ещё один такой же GetMem (чтобы a^ выделялась в другом месте и заполнялась другим мусором), как Pointer(a^.b) тоже стал ненулевым, и попытка присвоить что-то строке также начала приводить к AV. Всё в полном соответствии с теорией :)

Я посмотрел тексты процедур AllocMem и New - первая гораздо более компактна, чем вторая, следовательно, работать будет не в пример быстрее.

AllocMem тупо заполняет выделенную память нулями. New (точнее, вызываемая ей Initialize) избирательно инициализирует только те поля, которые в этом нуждаются. В данный момент все имеющиеся автоматически финализируемые типы при инициализации просто обнуляются, поэтому в конечном счёте вы не видите разницы. Но если вдруг в следующей версии появится такой тип, который инициализируется по-другому, AllocMem окажется бессильной.

Но функцией New можно инициализировать только предопределенные типы указателей. Типы pointer - увы! - она не инициализирует, потому что не знает, сколько памяти нужно под нее отводить. Проверьте сами - указатель типа pointer после использования этой функции равен nil.

Опять какая-то ерунда. Во-первых, для инициализации указателя нулём не нужно знать размер данных, на которые он ссылается. Во-вторых, Initiflize ничего не делает с указателями простых типов, поэтому что там будет после New - непредсказуемо (я проверил - у меня действительно получался то nil, то другие произвольные значения).

31-10-2006 02:58

Ерунда. Локальные переменные всех автоматически финализируемых типов (string'и, варианты, интерфейсы, динамические массивы) в прологе функции обязательно инициализируются пустым значением. Это только в нефинализируемых типах вроде того же double может оказаться что угодно, а строка обязательно будет пустой - см. код, который генерирует компилятор.
[/qoute]

А вот и нет. И доказательство тому - сделующий код:

Var i:integer;
    j,k,m:double;
    s:string;
    a:TMyData;
begin
  i:=0;
  j:=0;
  k:=0;
  m:=0;
  s:='';
  a.a:='';
  SetLength(a.b,0);
  ...
end;

Убедитесь, что при попытке компиляции компилятор действительно пропустит следующие строки )(где бы они не стояли):
  i:=0;
  j:=0;
  k:=0;
  m:=0;
потому что эти типы действительно инициализируются нулями (хотя опять же из своего опыта говорю - такое бывает только в самых простых случаях, как, например, в приведенном; часто бывало, что у меня пропускалась только одна подобная строка)
Однако строки
  s:='';
  a.a:='';
  SetLength(a.b,0);
компилятором не пропускаются, что лишний раз свидетельствует о том, что переменные подобного типа не инициализируются (иначе зачем борландский оптимизатор их тоже не пропускает?)

Я посмотрел тексты процедур AllocMem и New - первая гораздо более компактна, чем вторая, следовательно, работать будет не в пример быстрее. Но функцией New можно инициализировать только предопределенные типы указателей. Типы pointer - увы! - она не инициализирует, потому что не знает, сколько памяти нужно под нее отводить. Проверьте сами - указатель типа pointer после использования этой функции равен nil.


Думаю, исплючение происходит в первой строке. Просто у отладчика есть такая фича - он нередко останавливается не на той строке, где произошло исключение, а на следующей. Скорее всего, с таким эффектом вы и столкнулись. Пройдите этот код по шагам и посмотрите, какая строка реально вызовет исключение.


Проверил. Пошагово. Исключение происходит не в первой, а именно в той строке, в которой происходит обращение к второму элементу структуры - массиву или строке. А если компилятор останавливается "не на той строке", то, скорей всего, ошибка (ошибки) кроются где-то в другом месте кода, и даже не в этой процедуре, такое у меня было тоже и не раз, особенно, когда я работал с библиотеками без перекомпиляции всего проекта. Главная отличительная особенность подобной ошибки - синие точки трассировки могут оказаться в строках, не содержащих текста, и наоборот, строки с текстом могут оказаться не помеченными, отладчик же будет работать исключительно "по точкам".
Но здесь же приведен один из простейших примеров, здесь нет кода "во вне", который мог бы привести к возникновению ошибки. Стало быть, проблема кроется именно в использовании функций выделения памяти и ее инициализации.


если уж хочется самому всё это делать, то можешь под record выделять память с помощью allocmem, и самостоятельно инициализировать в них строки и массивы с помощью процедуры initialize(), их надо инициализировать потому, что строки и динамические массивы это по сути указатели на данные, а их getmem не создаёт.


Зачем такие сложности? Я вполне удовлетворен работой функции AllocMem, и при ее использовании у меня НИКОГДА не возникало проблем с обращением к строкам, массивам и прочим подобным вещам, и мне ни разу не приходилось использовать initialize().
Строки же и динамические массивы - это не указатели в чистом виде, это особые типы переменных, в которых есть не только указатели на первый элемент, но и масса других полей. Например, в типе string имеется поле ссылок, т.е. количество переменных, ссылающееся на эту строку; так же имеется поле длины строки (кажется, такая переменная может достигать в длину 4 гигабайт). (Полная информация о составе полей фирмой borland не раскрывается, потому как в обычной жизни это никому не нужно, а в новой версии Delphi назначение и состав могут поменяться и ваши старые проги, использовавшие в работе старые поля, могут оказаться неработоспособными после компиляции в новой среде). И неизвестно, какие значения могут оказаться в этих полях после вызова процедуры, например, GetMem, которая эти поля не очищает.
Но говорить, что GetMem не создает указатели на данные - я бы не стал. Дело в том, что и New, и AllocMem в самом начале используют функцию GetMem, после чего, например, AllocMem вызывает FillChar для очистки выделенной памяти:

function AllocMem(Size: Cardinal): Pointer;
begin
  GetMem(Result, Size);
  FillChar(Result^, Size, 0);
end;

То, что FillChar уж точно ничего не выделяет - я думаю, понятно. :)

30-10-2006 09:45

var
  R: PMyRecord;
begin
  R := AllocMem(SizeOf(TMyRecord)); //получаем данные в памяти 00000000
  //где первый четыре нуля это a: integer вторые четыре нуля это b:string
  initialize(R.B); //т.к. B у нас не инициализирована, то
  r.b := 'String';
  caption := r.b;
  system.Finalize(r.B); //говорим что завершаем работать со строкой
  FreeMem(R); // освобождает память.
end;


30-10-2006 09:34
Функция New не только выделяет память соответствующего размера под соответствующий pointer (getmem), но и инициализирует массивы и строки если они есть в record например, а dispose финализирует строки и вызывает freemem.
если уж хочется самому всё это делать, то можешь под record выделять память с помощью allocmem, и самостоятельно инициализировать в них строки и массивы с помощью процедуры initialize(), их надо инициализировать потому, что строки и динамические массивы это по сути указатели на данные, а их getmem не создаёт.

30-10-2006 09:30
Например, в переменной типа double запросто может оказаться число типа NAN. Все это происходит потому, что локальные переменные процедуры выделяются не в какой-то фиксированной области памяти, а в стеке, при этом для них память только отводится, но вовсе не очищается, и что было ранее записано по этим адресам ранее - навряд ли известно даже Богу. Поэтому переменная типа string может содержать недопустимые инициализационные данные и обращение к ней даже для записи может привести к ошибке (см. пример далее).

Ерунда. Локальные переменные всех автоматически финализируемых типов (string'и, варианты, интерфейсы, динамические массивы) в прологе функции обязательно инициализируются пустым значением. Это только в нефинализируемых типах вроде того же double может оказаться что угодно, а строка обязательно будет пустой - см. код, который генерирует компилятор.

Процедура AllocMem не только выделяет память для переменной, но и очищает ее, чего команды New или GetMem не делают.

GetMem действительно ничего с выделенной памятью не делает. А New вызывает для неё Initialize, поэтому все автоматически финализируемые поля опять-таки окажутся инициализированными пустым значением. После New ничего обнулять FillChar'ом не нужно.

При создании объектов действительно используется метод Initialize, который действительно очищает все переменные.

Во-первых, Initialize - это не метод, а процедура, и к инициализации полей объекта никакого отношения не имеет. Эти поля очищаются в методе InitInstance.

Однако как вы объясните следующее.
<...>
При этом вы можете поменять эти строки местами: строка, оказавшаяся второй, опять таки вызовет исключение, в то время как первая выполнится без проблем.


Думаю, исплючение происходит в первой строке. Просто у отладчика есть такая фича - он нередко останавливается не на той строке, где произошло исключение, а на следующей. Скорее всего, с таким эффектом вы и столкнулись. Пройдите этот код по шагам и посмотрите, какая строка реально вызовет исключение.

Если же вместо GetMem(a,SizeOf(TVar)) использовать a:=AllocMem(SizeOf(TVar)), то все работает нормально. Почему?

Вы же уже ответили - AllocMem обнуляет память. Но делает это тупо. Гораздо лучше использовать New, которая инициализирует память интеллектуально с помощью Initialize. Или вы будете говорить, что с New тоже ошибки возникают?

30-10-2006 08:49
Хочу сразу внести ясность, потому как имею не теоритический, а практический опыт работы.

1. Ну чтение полей только что созданной записи как правило не нужно, обычно после создания идет заполнение полей, так что все должно быть нормально и без инициализации нулями.


  Нередко случается такой казус, что, например, при попытке присвоить строке записи какое-то значение неожиданно выскакивает эксепшн. Детальный анализ показал, что достаточно часто многие переменные при объявлении их локальными в процедуре, содержат непонятные данные. Например, в переменной типа double запросто может оказаться число типа NAN. Все это происходит потому, что локальные переменные процедуры выделяются не в какой-то фиксированной области памяти, а в стеке, при этом для них память только отводится, но вовсе не очищается, и что было ранее записано по этим адресам ранее - навряд ли известно даже Богу. Поэтому переменная типа string может содержать недопустимые инициализационные данные и обращение к ней даже для записи может привести к ошибке (см. пример далее). Поэтому чистить надо не только динамические переменные, но (желательно) и статические командой FillChar (желательно - потому что это необходимо не всегда, но в моей практике иногда требовалось по указанным выше причинам).
  Процедура AllocMem не только выделяет память для переменной, но и очищает ее, чего команды New или GetMem не делают. Вы можете использовать и эти две команды, но после  любой из них лучше всего сразу же использовать команду FillChar, потому как, может, и не сразу, а спустя какое то время вы начнете получать неожиданные эксепшены в операциях, которые, вроде как должны работать корректно. Повторяю, что это касается только сложных типов переменных, содержащих, например, строки и массивы.


2. Это абсолютно не соответствует действительности, каждая создаваемая структура инициализируется с помощью функции Initialize (см System.pas), которая очищает все поля хранящие сложные объекты типа длинных строк и интерфейсов.



Мы, кажется, тут не поняли друг друга. Лично я говорил не об объектах, а о типах, указатели на переменные которых создаются вызовом методов AllocMem, GetMem или New. В них никакой очистки памяти не происходит. При создании объектов действительно используется метод Initialize, который действительно очищает все переменные.


3. Поэтому в таких случаях лучше использовать функцию AllocMem, которая не тольков выделяет память, но и очищает ее, т.е. длина строки или массива гарантировано будет нулевой.
А вот этого делать как раз и не следует и уж точно нельзя вызывать FreeMem вместо Dispose, так как получим утечку памяти из за того что не будут освобождены те самые сложные объекты, типа строк.


Проведенные испытания показали, что метод Dispose действительно лучше удаляет данные тестовой структуры типа:

TVar = record
    b:string;
    Arr:array of byte;
  end;

Однако как вы объясните следующее.
Пусть имеется некоторая процедура:

  GetMem(a,SizeOf(TVar));
  a^.b:='dkghehdsnfjkwdsfdwhi';//любая строка
  SetLength(a^.Arr,23);//любой размер массива
  For i:=0 to High(A^.Arr) do
    A^.Arr[i]:=Random(255);

где a=PVar;
  PVar=^TVar;
  TVar = record
    b:string;
    Arr:array of byte;
  end;


При выполнении указанной процедуры строчка a^.b:='dkghehdsnfjkwdsfdwhi' обрабатывается без проблем. Однако строка SetLength(a^.Arr,23) тут же вызывает исключение. При этом вы можете поменять эти строки местами: строка, оказавшаяся второй, опять таки вызовет исключение, в то время как первая выполнится без проблем. Если же вместо GetMem(a,SizeOf(TVar)) использовать a:=AllocMem(SizeOf(TVar)), то все работает нормально. Почему?

25-10-2006 10:58
Хотелось бы отметить такой факт, что, например, процедура New только резервирует память для переменной, но не очищает ее.
Это абсолютно не соответствует действительности, каждая создаваемая структура инициализируется с помощью функции Initialize (см System.pas), которая очищает все поля хранящие сложные объекты типа длинных строк и интерфейсов.
Поэтому в таких случаях лучше использовать функцию AllocMem, которая не тольков выделяет память, но и очищает ее, т.е. длина строки или массива гарантировано будет нулевой.
А вот этого делать как раз и не следует и уж точно нельзя вызывать FreeMem вместо Dispose, так как получим утечку памяти из за того что не будут освобождены те самые сложные объекты, типа строк.

25-10-2006 07:25 | Комментарий к предыдущим ответам
Но если тип включает в себя описание массива, строки или еще что-либо более сложное, то использование New может привести к непредсказуемым последствиям: представьте себе, какое число может оказаться в поле, например, длины строки или массива, в то время как в реальности под строку или массив память в реальности не выделялась, и к чему может привести обращение к таким строкам и массивам.

Ну чтение полей только что созданной записи как правило не нужно, обычно после создания идет заполнение полей, так что все должно быть нормально и без инициализации нулями.

25-10-2006 07:01
Опечатка.
В предыдущем ответе
  FillChar(a,XXX,0);
заменить на
  FillChar(a^,XXX,0);

:)

25-10-2006 06:59
New и Dispose и так вызывают GetMem и FreeMem так что об устарелости говорить рано...

Хотелось бы отметить такой факт, что, например, процедура New только резервирует память для переменной, но не очищает ее. Для простых типов это, как правило, не страшно. Но если тип включает в себя описание массива, строки или еще что-либо более сложное, то использование New может привести к непредсказуемым последствиям: представьте себе, какое число может оказаться в поле, например, длины строки или массива, в то время как в реальности под строку или массив память в реальности не выделялась, и к чему может привести обращение к таким строкам и массивам.
Поэтому в таких случаях лучше использовать функцию AllocMem, которая не тольков выделяет память, но и очищает ее, т.е. длина строки или массива гарантировано будет нулевой.
Эта процедура равносильна следующему блоку:

Var a:pointer;
begin
  a:=GetMem(XXX);
  FillChar(a,XXX,0);
end;

- здесь ХХХ - размер памяти, выделяемый переменной а

24-10-2006 01:54
Но по любому, в отличие от С/С++, в Дельфи надо сначала привести имя массива к типу указатель, и только после этого обрабатывать его. Таким образом, имена массивов нельзя назвать указателями в полном понимании этого слова. Возможно, это результат строгой типизации языка.

23-10-2006 11:06 | Комментарий к предыдущим ответам
будет корректно работать только в виде
  Move(PByte(FA)^,PByte(FB)^,Length(FA));
В противном случае получите исключение.
Я знаю, просто проверил ваше утверждение Попробуйте использовать строчку Move(A,B,Length(A));
и вы удивитесь тому, какую галиматью в массиве В увидите.


И массивы при выходе надо обнулять, иначе так же получаете утечку памяти. Массивы также как и строки не надо обнулять, посмотрите в CPU что выполняется при выходе из процедуры.

23-10-2006 10:14
В предыдущем ответе FA, FB = array of byte

23-10-2006 10:13
Да, действительно, работает. Однако в примере с массивами блок
  Move(A,B,Length(A));
будет корректно работать только в виде
  Move(PByte(FA)^,PByte(FB)^,Length(FA));
В противном случае получите исключение.
И массивы при выходе надо обнулять, иначе так же получаете утечку памяти.

20-10-2006 11:08 | Комментарий к предыдущим ответам
Move(A,B,4); конечно же в последем ответе.

20-10-2006 11:01 | Комментарий к предыдущим ответам
Loki: И ещё:
Попробуйте использовать строчку
  Move(A,B,Length(A));
и вы удивитесь тому, какую галиматью в массиве В увидите. Вернее, при работе с ним у вас сплошняком пойдут исключания,

С чего вы решили что с массивом B нельзя работать? Вы можете с ним спокойно работать пока массив A не выйдет из поля видимости и не освободится занисаемая им память....

var
  a,b:array of byte;
Begin
  setlength(a, 10);
  a[5] := 5;
  //SetLength(B,Length(a));
  Move(A,B,Length(A));
  b[7] := 250;
  caption:= inttostr(b[5]) + ' ' + inttostr(b[7]);
end;

далее вы получите access viol...

20-10-2006 10:40 | Комментарий к предыдущим ответам
И первый ваш пример
Var
  i:integer;
  a: array of integer;
begin
  SetLength(a,1);
  PInteger(a)^:=345;
  caption:= inttostr(a[0]);
end;

20-10-2006 10:38
А попробуйте:
Var a,b:array of byte;
Begin
  ...
  SetLength(B,Length(a));
  Move(Pointer(A)^,Pointer(B)^,Length(A));
  ...
end;
или в любой другой буфер. значит всё таки указывает на начало данных.

20-10-2006 10:25
Хорошо. Тогда как Вы объясните то, что при попытке скомпилировать следующий код:

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    FArr:array of integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
Var i:integer;
begin
  SetLength(FArr,1);
  FArr^:=345;
end;

на строчке 

FArr^:=345;

компилятор выбрасывает сообщение:
Pointer type required ?

Ведь если имя массива - указатель на его первый элемент, то компилятор должен без проблем компилировать такую вещь.
Попытки осуществить преведение типа такого вида:

integer(FArr^:=345),
@FArr^:=345  и прочие извращения так же успеха не имели; обязательно требуется указать индекс.
А в ответ на
FArr:=345 компилятор вообще заявил о несовместимости типов.
Фразу
  Integer(FArr):=345;
  Label1.Caption:=IntToStr(FArr[0]);
он проглотил, но припопытке выполнить этот код я тут же получил Access Violation на строчке Label1.Caption:=IntToStr(FArr[0])
  Из своего опыта мне известно, что любая попытка работать с именем массива как с указателем на первый элемент приводит к ошибкам, необходимо всегда явно указывать нулевой элемент массива:

Var a,b:array of byte;
Begin
  ...
  SetLength(B,Length(a));
  Move(A[0],B[0],Length(A));
  ...
end.

Попробуйте использовать строчку

  Move(A,B,Length(A));

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


20-10-2006 05:47
Переменная типа динамический массив - это указатель именно на первый элемент массива. Но по отрицательному смещению от этого указателя должно храниться число ссылок и размер массива, чего нет в массивах в C. Поэтому они и не совместимы. Более того, переменная типа массив в С - это не указатель , просто компилятор разрешает использовать такую переменную как указатель, неявно выполняя операцию получения адреса.

20-10-2006 05:20
В общем, какая то путанная ситуация получается, хочется внести ясность.
В языке С нет такого понятия как динамические массивы (может, я и не прав, но я, по крайней мере, не нашел), там всем массивы статические, и, следовательно, имя массива есть указатель на первый (нулевой) элемент массива (в случае одномерных массивов). В дельфи же имя динамического массива - указатель на некую структуру, в которой так же, помимо всего прочего, содержится указатель на первый элемент массива. Сам же массив может располагаться вообще в другой области памяти. То же самое касается и переменной типа string. Возможно, в этом вся проблема?

18-10-2006 02:55
Тут ты обязан: ptr каждый раз увеличивать на размер TParameter !

Ничего подобного! ptr указывает на начало блока данных, а обратиться к i-му элементу массива param можно так: param[i]

18-10-2006 02:47
Dmitry: чего-то у тебя не сходится...
* если ты из файла считываешь данные в какой-то буфер, то какая те разница куда считывать в pointer или динамический массив? и там и там надо вызывать или getmem или setlength.
* если ты считываешь/записываешь данные "напрямую" из файла, то чего ты спрашиваешь про буфер?

18-10-2006 02:40 | Сообщение от автора вопроса
with PMyData(ptr)^ do begin
...
end;

Тут ты обязан: ptr каждый раз увеличивать на размер TParameter !
А я спрашивал про params[I]^.FValue, здесь I как принято в мировой практике программистов выступает в роли индекса в массиве Параметров, 1й, 2й, 3й ,.. n-й
без вычисления надо!, только на уровне указания индекса!

18-10-2006 02:28
Надо именно в виде params[I]^.FValue этого нельзя?

Можно, в моем примере добавьте

with PMyData(ptr)^ do begin
...
end;


18-10-2006 02:09 | Сообщение от автора вопроса
Программерская поговорка: "Покажи мне свой код и скажу какой уровень твоего профессионализма" Ну предположим ты не со зла...
Мне самому такое сказали, меня пинали, в самом начале когда я только начал программировать и еще не понимал, что надо писать код проще, но потом столкнулся с исхдными кодами других людей, вот к примеру:
  if(dat[a]==0x0)
        {goto ex1;}
          if(dat[a]<0)
          {dat[a]=dat[a]&0x7f;
          if(dat[a]>=0x0)
                {if(dat[a]<=0x2f)
                    {dat[a]=dat[a]+0x40;dat[a]=dat[a]|0x80;goto ax1;}
                  if(dat[a]>=0x60)
                    {if(dat[a]<=0x6f)
                        {dat[a]=dat[a]+0x10;dat[a]=dat[a]|0x80;goto ax1;}

Тебе нравится? Мне нет, но ПО работает, однако мне сейчас проще самому написать, чем эту рабочую программу модернизировать! Это по поводу поговорки!

По поводу очередного предложения, дело в том что это еще ОДна доп. нагрузка! т.к. с файлом очень часто будут работать через мой написанный модуль, то потому надо как можно быстрее. Я на си привел писанину, через переменные, там нет лишних вызовов! А следовательно нет лишних "ошибочных" предсказаний переходов процессором!!!

Надо именно в виде params[I]^.FValue этого нельзя?

18-10-2006 02:00
Программерская поговорка: "Покажи мне свой код и скажу какой уровень твоего профессионализма" Ну предположим ты не со зла...

Это слишком громоздкий синтаксис.
Если в си позволяется(см. пример ниже), то почему в паскале такое нельзя? Не ужто он такой убогий?

Ты в си объявил две переменные:
TDTime * dt = (TDTime *)(pMem);
TParameter * params = (TParameter *)((DWORD)(pMem) * sizeof(TDTime);

По большому счёты это тоже самое что вынести код в отдельную функцию:

function GetDTime(Buffer: Pointer): PDTime;
begin
  Result := PDTime(Buffer);
end;
function GetParameter(Buffer: Pointer; Index: Integer): PParameter;
begin
  Result := PParameter(Longint(Buffer) + SizeOf(TDTime) + SizeOf(TParameter) * Index);
end;

А далее остаётся:
var
  Param: PParameter;
begin
...
for ... to
begin
  Param := GetParameter(P, I);
  param.FCode := TmpCode[I];
end;

18-10-2006 01:31 | Сообщение от автора вопроса
PDTime(P)^.FCode := 99;
PDTime(P)^.FMonth := 100;
PDTime(P)^.FStatus := 101;

Это слишком громоздкий синтаксис.

Программерская поговорка: "Покажи мне свой код и скажу какой уровень твоего профессионализма"

Если в си позволяется(см. пример ниже), то почему в паскале такое нельзя? Не ужто он такой убогий?

мне надо именно в виде: params[Indx]^.FValue := TmpValue; на си бы это выглядело как: params[Indx]->FValue = TmpValue и человеку не нужно было бы таких громоздких нагромождений в коде в виде:

for I := 1 to 8 do
begin
  Param := Pointer(Longint(Params) + SizeOf(TParameter) * I); //текущая
позиция = начало блока с параметрами + размер параметра * кол-во шагов.
  PParameter(Param)^.FStatus := I; // и вот теперь обращаемся к текущей
позиции как к параметру.
end;

18-10-2006 01:23
for I to Count-1 to
begin
  dtime[I]^.FCode := TmpCode[I];
  dtime[I]^.FValue := TmpValue[I];
  dtime[I]^.FStatus := TmpStatus[I];
end;
предположим что у тебя там Params, которую ты получаешь предположим вот так:
Params := Pointer(Longint(P) + SizeOf(TDTime)); //т.е. начало данных + размер tdtime = указатель на блок с параметрами (не массив с точки зрения pascal)

далее ты должен бежать по этому блоку с параметрами шагами = размеру параметра
for I := 1 to 8 do
begin
  Param := Pointer(Longint(Params) + SizeOf(TParameter) * I); //текущая позиция = начало блока с параметрами + размер параметра * кол-во шагов.
  PParameter(Param)^.FStatus := I; // и вот теперь обращаемся к текущей позиции как к параметру.
end;

сейчас заметил ошибку: for i := 0 to 7, а не for i := 1 to 8

18-10-2006 01:01 | Сообщение от автора вопроса
Даа... что то не внимательный стал я.. в коде params, а в вопросе dtime написал! )))
Спасибо, не судите строго, просто режим работы у меня такой, на отдых времени мало, вот и туплю

18-10-2006 00:53
for I to Count-1 to
begin
  dtime[I]^.FCode := TmpCode[I];
  dtime[I]^.FValue := TmpValue[I];
  dtime[I]^.FStatus := TmpStatus[I];
end;
Дельфи-Компиллер в недоумении и не может меня понять.
А что, подразумевается что должен? dtime у тебя какого типа? а при чём здесь FCode, FValue, FStatus?
1. Посмотри мой пример как есть+комментарий от "17-10-2006 08:05" - работает?
2. Я, к примеру, дал тебе какой-никакой но полный код, а ты два огрызка из своего. типа вам надо сами и разбирайтесь?

18-10-2006 00:31 | Сообщение от автора вопроса
Я сделал так:


  PDTime = ^TDTime;
  TDTime = record
..
  PParameter = ^TParameter;
  TParameter = record
...

var
  dtime  : PDTime;
  params  : PParameter;
begin
  dtime := PDTime(Buffer);
  params := PParameter(longint(Buffer)+SizeOf(TDTime));


обращаюсь к дате со временем так:
dtime^.FYear := <тута_мое_значение>;

но когда пытаюсь:


for I to Count-1 to
begin
  dtime[I]^.FCode := TmpCode[I];
  dtime[I]^.FValue := TmpValue[I];
  dtime[I]^.FStatus := TmpStatus[I];
end;



Дельфи-Компиллер в недоумении и не может меня понять.

Как мне объяснить ему?

17-10-2006 09:48 | Комментарий к предыдущим ответам
Loki:
Сейчас в моде AllocMem и FreeMem или FreeAndNil. Последний не только освобождает память указателя, но и присваивает указателю значение Nil.

Зачем дезинформируешь? :) Особенно насчет FreeAndNil - он не с указателями работает а с объектами - переменными классов, наследников от TObject :)

{ FreeAndNil frees the given TObject instance and sets the variable reference to nil. Be careful to only pass TObjects to this routine. }

procedure FreeAndNil(var Obj);


17-10-2006 09:47
Спасибо, за отклики буду пробовать. чего вышло завтра скажу! :)

17-10-2006 08:05 | Комментарий к предыдущим ответам
ой, у меня там вместо
PDTime(P)^.FCode := 99;
PDTime(P)^.FMonth := 100;
PDTime(P)^.FStatus := 101;
должны быть
FMin
FHour
FMs
FSec
FYear
FDay
FMonth

17-10-2006 07:45
Можно проще и понятнее, хотя в итоге будут те же ..., только в профиль:

TDTime = record
    {$A1+}
    FMin    : Byte;
    FHour  : Byte;
    FMs    : Byte;
    FSec    : Byte;
    FYear  : Word;
    FDay    : Byte;
    FMonth  : Byte;
    {$A1-}
  end;
  TParameter = record
    {A1+}
    FCode  : Word;
    FValue  : Single;
    FStatus : Word;
    {A1-}
  end;

var
  dt : array of TDTime;
param : array of TParameter;
begin
  SetLength(dt, количество параметров); //типа getmem
  SetLength(param, количество параметров);
  ...

  for i:=0 to количество параметров-1 do
    dt[i].FMin:='бла-бда-бла';

  ...
  SetLength(dt, 0); //типа freemem
  SetLength(param, 0);
end;

P.S. С детства путался я в этих указателях :-(

17-10-2006 07:07
Вот и хотелось бы взять указатель на 0й байт этого буфера присвоить переменной и бращаться как с переменной типа TDTime, а указатель на 9го буфера присвоить указателю на массив TParameter и обращаться к каждому параметру в цикле через индекс I.

Дело в том, что динамические массивы содержат не только элементы массива, но и служебную информацию, всякие там счетчики числа пользователей. Поэтому так просто рассматривать область памяти как динамический массив не получится. Так попробуйте:

type
  PMyData = ^TMyData;
  TMyData = packed record
    dt: TDTime;
    params: array[0..0] of TParameter;
  end;
...

var
  ptr: pointer;
  size: Cardinal;
...
size:=SizeOf(TDTime) + (SizeOf(TParameter) * CountParams);
GetMem(ptr,size);
...
try
  PMyData(ptr)^.dt.FHour:=...;
  PMyData(ptr)^.params[i].FCode:=...;
...
finally
  FreeMem(ptr,size);
end;


17-10-2006 07:00
Это имеешь ввиду?:

type
  PDTime = ^TDTime;
  TDTime = packed record
    FMin    : Byte;
    FHour  : Byte;
    FMs    : Byte;
    FSec    : Byte;
    FYear  : Word;
    FDay    : Byte;
    FMonth  : Byte;
  end;

  PParameter = ^TParameter;
  TParameter = packed record
    FCode  : Word;
    FValue  : Single;
    FStatus : Word;
  end;

  PParameters = ^TParameters;
  TParameters = array of TParameter;

procedure TForm1.FormCreate(Sender: TObject);
var
  P, Param, Params: Pointer;
  I: Integer;
begin
  GetMem(P, SizeOf(TDTime) + SizeOf(TParameter) * 8);

  PDTime(P)^.FCode := 99;
  PDTime(P)^.FMonth := 100;
  PDTime(P)^.FStatus := 101;

  Params := Pointer(Longint(P) + SizeOf(TDTime));
  for I := 1 to 8 do
  begin
    Param := Pointer(Longint(Params) + SizeOf(TParameter) * I);
    PParameter(Param)^.FStatus := I;
  end;

  //-------------------------

  for I := 1 to 8 do
  begin
    Param := Pointer(Longint(Params) + SizeOf(TParameter) * I);
    Caption := Caption + ' ' + Inttostr(PParameter(Param)^.FStatus);
  end;

  FreeMem(P);
end;


17-10-2006 06:14 | Сообщение от автора вопроса
Вы не совсем поняли условие задачи.

Я писал слова:
Мне надо выделить буфер который будет равным SizeOf(TDTime) + (SizeOf(TParameter) * CountParams) в байтах
Чуть ниже я описал формат буфера:
Сначала 1 объект структуры TDTime, а после CountParams объектов структуры TParameter

На примере:
Если параметров 58 штук, А размер TDTime 8 байт и TParameter имеет 8 байт.

тогда надо выделить буфер рамером 8 + 8*58 байт т.е. 472 байта!

Смотрим на формат буфера(см. выше) и видим что с 0-го байта этого буфера начинается объект TDTime, в котором хранится информация о времени и дате! С 9го же байта начинается массив параметров, каждый описывается структурой TParameter.

Вот и хотелось бы взять указатель на 0й байт этого буфера присвоить переменной и бращаться как с переменной типа TDTime, а указатель на 9го буфера присвоить указателю на массив TParameter и обращаться к каждому параметру в цикле через индекс I.

На си это выглядело бы так:

BYTE * pMem = new BYTE[(sizeof(TDTime) + count * sizeof(TParameter))];
TDTime * dt = (TDTime *)(pMem);
TParameter * params = (TParameter *)((DWORD)(pMem) * sizeof(TDTime);

и работал бы с массивом так:


dt->FYear;
dt->FMin;

for(int i=0,i<Count;i++) {
  params[i]->FCode;
  params[i]->FValue;
}



как на дельфи это будет?

17-10-2006 06:11
New и Dispose и так вызывают GetMem и FreeMem так что об устарелости говорить рано...

17-10-2006 05:58
New и Dispose - это устаревшие методы. Сейчас в моде AllocMem и FreeMem или FreeAndNil. Последний не только освобождает память указателя, но и присваивает указателю значение Nil.

var
dt : TDTime
param : array of TParameter;
tmp : Pointer;
begin
  p := SizeOf(TDTime) + (SizeOf(TParameter) * CountParams);
  td := p;
  param := Pointer(Integer(p) + SizeOf(TParameter));

- здесь не совсем понятно, что такое р?

17-10-2006 03:19
Дополнение:
Если вам нужно создавать переменную типа TDTime динамически, то нужно объявить указатель на этот тип
и переменную-указатель этого типа:


type
  PDTime=^TDTime;
var
  pdt:PDTime;


Распределение и освобождение памяти осуществляется с помощью процедур New и Dispose:


  New(pdt);//распределение памяти
  pdt^.FMin:=5;//доступ к полю
  pdt^.FHour:=12//доступ к полю
  Dispose(pdt);//освобождение памяти


17-10-2006 03:03
Если Вы объявили переменную dt типа TDTime, то она присутствует в памяти компьютера и так, а ее поля доступны без всякого буфера (dt.FMin,dt.FHour и т.д.). Память под динамический массив param выделяется процедурой

SetLength(param,CountParams);


после чего доступны все поля этого массива (param[I].FCode и т.д.). Освобождается память вызовом

param:=nil;


Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Два кольца, два конца, посередине гвоздик.
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования