Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 14.03.2013, 08:18
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию Проблема с SetString

Никак не могу врубиться, а почему если оставить FillChar(P^, SizeOf(TData), 0) закомментированным, то выдаёт любимый Access Violation?
Код:
unit TestDataUnit;

interface

uses Forms;

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end; // TForm1 = class(TForm)

  TData = packed record
    FText: String;
  end; // TData = packed record
  
var
  Form1: TForm1;
  P: Pointer;

implementation

{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin

  P := GetMemory(SizeOf(TData)) ;
//  FillChar(P^, SizeOf(TData), 0);
  with TData(P^) do
    SetString(FText, PChar(nil), 30);
end; // procedure TForm1.FormShow(Sender: TObject)

end.
Ответить с цитированием
  #2  
Старый 14.03.2013, 08:44
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Код:
type
  PData = ^TData;
  TData = record
    Text: String;
  end;

var
  p: PData;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  p:=GetMemory(SizeOf(TData));
  ZeroMemory(p, SizeOf(TData)); // необязательно вовсе
  p^.Text:='hello';
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  p^.Text:='';
  FreeMemory(p);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(p^.Text);
end;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #3  
Старый 14.03.2013, 09:01
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Ну во первых у меня Delphi 7, я там ZeroMemory не видел. Во-вторых, я полагаю, FillChar(P^, SizeOf(TData), 0) делает то же, что и ZeroMemory(p, SizeOf(TData)). Но вот для чего оно в данном контексте нужно? Знать бы как работает SetString... Исходника я не нашёл у себя. Мож в инете?
Ответить с цитированием
  #4  
Старый 14.03.2013, 09:23
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
Восклицание

у меня тоже Delphi 7, о чем написано в профиле.

Код:
var
  s: String;
begin
  SetString(s, PChar('hello'), 5);
  ShowMessage(s);
end;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #5  
Старый 14.03.2013, 09:48
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Да, извиняюсь, про Delphi 7 просмотрел. А для чего тут-то SetString? Можно просто s := 'hello'. Но вопрос был не об этом. Вопрос: почему без FillChar выдаёт Access Violation? И, кстати, если написать так
Код:
procedure TForm1.FormShow(Sender: TObject);
var
  s: String;
begin
  s := 'hello';
  ShowMessage(s);
  P := GetMemory(SizeOf(TData)) ;
//  FillChar(P^, SizeOf(TData), 0);
  with TData(P^) do
    SetString(FText, PChar(nil), 30);
end; // procedure TForm1.FormShow(Sender: TObject)
то Access Violation не выдаёт! Почему?
Ответить с цитированием
  #6  
Старый 14.03.2013, 10:15
Аватар для Aristarh Dark
Aristarh Dark Aristarh Dark вне форума
Модератор
 
Регистрация: 07.10.2005
Адрес: Москва
Сообщения: 2,907
Версия Delphi: Delphi XE
Репутация: выкл
По умолчанию

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

Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты.
Ответить с цитированием
  #7  
Старый 14.03.2013, 10:19
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

Потому что строка в Дельфи - это объект с автоматическим временем жизни и подсчётом ссылок. В константно1 строке счётчик равен -1, во вновь созданной - 0;
Любое присваивание в строку - это:
1)Проверить, на Nil старый указатель.
2)Если там Nil, то перейти на 6)
3)Проверить счетчик ссылок, если там не 1, то перейти на 5)
4)Освободить память, занимаемую строкой, перейти на 6)
5)Если счётчик не -1, то уменьшить счётчик

6)Собственно присвоить новый указатель

7)Проверить на Nil новый указатель
8)Если там Nil, то Exit
9)Проверить счётчик. Если там не -1, то увеличить счётчик.

В многопоточном режиме добавляются Interlocked операции

Строковые локальные переменные процедур и поля классовых переменных после конструкторов инициализируются Nil`ами.
GetMemory осуществляет только заказ памяти и ничем его не прописывает. Поэтому на шаге 1) у Вас будет не Nil, а на шаге 4) - Access Violation.
Ответить с цитированием
Этот пользователь сказал Спасибо icWasya за это полезное сообщение:
BBBCat (14.03.2013)
  #8  
Старый 14.03.2013, 11:57
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Сорри, электричество вырубали у нас
Ну наконец-то внятный ответ! А то все вопрос читают по диагонали Про строку - я это в курсе, а вот про SetString... Ну примерно так я и предполагаю, правда с одним 'но'. Хэлп из Delphi: For a long string variable, SetString sets S to reference a newly allocated string of the given length. И далее: If there is not enough memory available to create the string, an EOutOfMemory exception is raised. Following a call to SetString, S is guaranteed to reference a unique string, that is a string with a reference count of one. Т.е:
1)На Nil старый указатель не проверяется.
3)Счетчик ссылок не смотрится, а сразу устанавливается на единицу
7)Проверить на Nil новый указатель и
8)Если там Nil, то Exit - вот здесь-то и должно родиться EOutOfMemory
Про Access Violation ни слова. Т.е. исходя из хэлпа должно работать без FillChar(P^, SizeOf(TData), 0), а исходя из практики - так как вы отписали. Такая ситуация немного напрягает. А вдруг там ко всему вышесказанному ещё что-то есть. Поэтому хотелось бы точно знать, как SetString работает. В смысле на исходник глянуть. А у вас откуда все эти сведения?

Вот ещё что забыл: из сообщения icWasya рождается объясниние, почему во втором из приведённых мной здесь коде всё нормально срабатывает при добавлении
Код:
s := 'hello';
ShowMessage(s);
, а без этого выдаёт Access Violation. Во всех примерах здесь либо возникает ошибка, либо нет. А вот один из моих позавчерашних вариантов(там просто тестовая програмка, ничё не делает, чисто для проверки одного класса запускала его метод по нажатию кнопки) выдавал Access Violation на третий раз после запуска программы, а потом через каждые четыре раза на пятый. Делаешь выход из программы, запускаешь по-новой и опять на третий и каждый пятый. Я перезапускал Delphi, запускал EXE-шник без Delphi, перезагружал комп. Да чё-там - из розетки выдёргивал, когда спать ложился! Всё равно - на третий раз ошибка, а потом каждый пятый. Это как понять? Короче надо бы исходник. Или убедительное объяснение. А то не хочется потом, когда проект закончу, опять на начало возвращаться.

Последний раз редактировалось BBBCat, 14.03.2013 в 12:43.
Ответить с цитированием
  #9  
Старый 14.03.2013, 13:14
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

Как я сказал, эта процедура вызывается при ВСЕХ присваиваниях строк.
Как раз старый указатель на Nil проверяется всегда. А поскольку у Вас там мусор - то и ошибка.
А в хелпе написано, что делается с НОВОЙ строкой. То есть создаётся новая строка, а если не получилось(Nil), то и вызывается EOutOfMemory.

По поводу того, что при выполнении шамашских действий начинает работать.
Мусорный указатель не всегда приводит к Access Violation. Или приводит, но не сразу. Или ошибка выскочит где-нибудь через час работы программы на ровном месте. В Вашем случае этот указатель мог совпасть с указателем на вот эту строку 'hello'. Поскольку она константная, счётчик у неё равен -1, а для таких строк FreeMem не вызывается.

И запомните - если программа работает правильно(или Вам так кажется), это не значит, что в ней нет ошибок.
Ответить с цитированием
  #10  
Старый 14.03.2013, 13:39
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Согласен, программа без глюков - это значит глюк у программиста И да, ну очень сильно похоже на реакцию на мусор. Но вот в хэлпе-то не разграничено для новой строки или для существующей. Просто для длинной и всё. Непонятка! По поводу строчки с 'hello' - приблизительно как вы и сказали, это вопросов не вызывает. Но вот как она у меня умудрялась со 100%-ной стабильностью выдавать ошибку на третьем проходе, а потом на каждом пятом? Стабильно не смотря на те действия, которые я при этом проводил с компом. Всё же хочу повторить вопрос - откуда у вас такие, как бы выразится, алгоритмические сведения о работе SetString?
Ответить с цитированием
  #11  
Старый 14.03.2013, 14:09
Аватар для Aristarh Dark
Aristarh Dark Aristarh Dark вне форума
Модератор
 
Регистрация: 07.10.2005
Адрес: Москва
Сообщения: 2,907
Версия Delphi: Delphi XE
Репутация: выкл
По умолчанию

Я с вас сильно удивляюсь господа.
Исходник SetString не судьба посмотреть? Там 3 строчки всего, и сразу все понятно становится.
__________________
Некоторые программисты настолько ленивы, что сразу пишут рабочий код.

Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты.
Ответить с цитированием
  #12  
Старый 14.03.2013, 14:21
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Цитата:
Сообщение от Aristarh Dark
Я с вас сильно удивляюсь господа.
Исходник SetString не судьба посмотреть? Там 3 строчки всего, и сразу все понятно становится.
Да, да, да!!! Я же с этого тему и начал. Вот именно этого и хотелось бы. Но давлю на вызов функции, а у меня тупо unit System открывается в самом начале на шапке из борландовых комментов. Как само тело SetString посмотреть? У меня Delphi 7 если что. Или может эти самые 3 строчки сюда кинете? Тоже было б замечтательно.

Извиняюсь, не с этого начал, но во втором сообщении точно написал
Да и ZeroMemory я чёй-та не найду. Где он?

Последний раз редактировалось BBBCat, 14.03.2013 в 14:25.
Ответить с цитированием
  #13  
Старый 14.03.2013, 14:24
Аватар для Aristarh Dark
Aristarh Dark Aristarh Dark вне форума
Модератор
 
Регистрация: 07.10.2005
Адрес: Москва
Сообщения: 2,907
Версия Delphi: Delphi XE
Репутация: выкл
По умолчанию

Код:
procedure       _SetString(s: PShortString; buffer: PAnsiChar; len: Byte);
begin
  Byte(s^[0]) := len;
  if buffer <> nil then
    Move(buffer^, s^[1], len);
end;
__________________
Некоторые программисты настолько ленивы, что сразу пишут рабочий код.

Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты.
Ответить с цитированием
  #14  
Старый 14.03.2013, 14:29
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Не, ну это-то я уже видел. Это ж для ShortString. Там и вопроса-то такого не возникло бы. А вот что для String?
Ответить с цитированием
  #15  
Старый 14.03.2013, 14:31
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
Сообщение от BBBCat
Да и ZeroMemory я чёй-та не найду. Где он?
Код:
procedure ZeroMemory(Destination: Pointer; Length: DWORD);
begin
  FillChar(Destination^, Length, 0);
end;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
Этот пользователь сказал Спасибо NumLock за это полезное сообщение:
BBBCat (14.03.2013)
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 06:55.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025