|
Вопрос # 5 054/ вопрос решён / |
|
Здравствуйте, уважаемые эксперты!
Подскажите пожалуйста, как можно сохранить и прочитать многомерный динамический массив??
ar:array of array of integer;
 |
Вопрос задал: Ham_ele_on (статус: Посетитель)
Вопрос отправлен: 27 февраля 2011, 18:37
Состояние вопроса: решён, ответов: 1.
|
Ответ #1. Отвечает эксперт: min@y™
Если массив является матрицей (т.е. он прямоугольный), то вот тебе 2 функции.
type
TMatrix = array of array of Integer;
// Сохранение матрицы X в файл FileName
function SaveMatrixToFile(const X: TMatrix; const FileName: string): Boolean;
var
Stream: TFileStream;
RowCount, ColCount, xSize: Cardinal;
begin
RowCount:= Length(X); // Кол-во строк
ColCount:= Length(X[0]); // Кол-во стролбцов
xSize:= RowCount * ColCount * SizeOf(Integer); // Размер матрицы в байтах
try
Stream:= TFileStream.Create(FileName, fmCreate or fmShareExclusive);
try
Stream.Write(RowCount, SizeOf(Cardinal)); // Запись кол-ва строк
Stream.Write(ColCount, SizeOf(Cardinal)); // Запись кол-ва столбцов
Stream.Write(X[0, 0], xSize); // Запись матрицы
finally
Stream.Free();
end;
Result:= True;
except
Result:= False;
end;
end;
// Загрузка матрицы X из файла FileName
function LoadMatrixFromFile(var X: TMatrix; const FileName: string): Boolean;
var
Stream: TFileStream;
RowCount, ColCount, xSize: Cardinal;
begin
try
Stream:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Stream.Read(RowCount, SizeOf(Cardinal)); // Чтение кол-ва строк
Stream.Read(ColCount, SizeOf(Cardinal)); // Чтение кол-ва столбцов
xSize:= RowCount * ColCount * SizeOf(Integer); // Размер матрицы в байтах
SetLength(X, RowCount, ColCount); // Выделение памяти
Stream.Read(X[0, 0], xSize); // Чтение матрицы
finally
Stream.Free();
end;
Result:= True;
except
Result:= False;
end;
end;
Программа, в которой я отлаживал эти функции, торчит здесь.
 |
Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 28 февраля 2011, 08:19
Оценка за ответ: 5
|
Мини-форум вопроса
Всего сообщений: 42; последнее сообщение — 4 марта 2011, 21:55; участников в обсуждении: 4.
Страницы: [1] [2] [3] [Следующая »]
|
min@y™ (статус: Доктор наук), 28 февраля 2011, 13:06 [#1]:
Цитата (Ham_ele_on):
Оценка за ответ: 5
А где камменты?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Ham_ele_on (статус: Посетитель), 28 февраля 2011, 14:48 [#2]:
Очень доступный ответ, жаль, что во время моих поисков в и-нете, не нашёл ничего похожего. решений много но они все "немного не рабочие". самое простое из решений которое встречал, это разложить массив на содержимое и так записать.
|
|
min@y™ (статус: Доктор наук), 28 февраля 2011, 15:02 [#3]:
А не надо ничего искать. Надо включить мозг и сделать. Если ты думаешь, что программирование - это поиск готовых кусков кода в интернете, то ты не программист, а копипастер, и программиста из тебя никогда не получится.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Ham_ele_on (статус: Посетитель), 1 марта 2011, 07:19 [#4]:
я не искал готового решения. частично этот вопрос решился в результате поисков, оставался только вопрос, как длину массива выставить при чтении, я уже хотел использовать tag какого нибудь компонента. совершенно не подумав, что можно в этот же файл сохранить размеры. но как говориться "опыт и половое бессилие, приходят с годами".
P/S.у меня ещё с английским грустно. хелпы трудновато читать.
|
|
min@y™ (статус: Доктор наук), 1 марта 2011, 08:11 [#5]:
Цитата (Ham_ele_on):
P/S.у меня ещё с английским грустно. хелпы трудновато читать.
А вот это очень не есть гут. translate.google.ru тебе в помощь.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 1 марта 2011, 10:13 [#6]:
чтобы длину массива восстановить при чтении, ее вначале нужно где то сохранить. Желательно в тот же файл, где и основные данные. В свойство Tag конечно можно, но если программу закрыть и открыть снова, то его значение потеряется.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Ham_ele_on (статус: Посетитель), 1 марта 2011, 11:13 [#7]:
>Tag конечно можно, но если программу закрыть и открыть снова, то его значение потеряется.
это свойство можно сохранить при выходе FormStorage.
>А вот это очень не есть гут.
уже понял.пытаюсь исправить.
>translate.google.ru тебе в помощь.
пользуюсь, но он не всегда корректно переводит.
|
|
min@y™ (статус: Доктор наук), 1 марта 2011, 11:34 [#8]:
Цитата (Ham_ele_on):
это свойство можно сохранить при выходе FormStorage.
Хватит ерундой заниматься! Мои 2 функции тебе не подошли, что ли?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 1 марта 2011, 12:02 [#9]:
если делать какой то код, который связан с защитой, тогда сохранение таким образом имеет какой то смысл (что бы запутать потенциального врага).
BTW: в коде min@y™ есть парочка некритичных, но все же багов. Код не проверяет, какой размер массива был вычитан с файла.
Но! этот код содержит одну большую ошибку. Он вообще то нерабочий. Так как массив объявлен как TMatrix = array of array of Integer;, то никто не гарантирует, что он будет в памяти располагаться непрерывно.
Но если массиву устанавливать размер с помощью SetLength(X, RowCount, ColCount); , то может быть он и будет непрерывным.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
min@y™ (статус: Доктор наук), 1 марта 2011, 12:29 [#10]:
Цитата (Вадим К):
Но! этот код содержит одну большую ошибку. Он вообще то нерабочий.
Поклёп и 100% неправда. Я этот код не на коленке написал, а в составе отладочной программы.
Цитата (Вадим К):
Так как массив объявлен как TMatrix = array of array of Integer;, то никто не гарантирует, что он будет в памяти располагаться непрерывно.
Я - гарантирую. Если какой-то дурак быдет выделять память как-то иначе, то он сам дурак и я здесь ни причём.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Ham_ele_on (статус: Посетитель), 1 марта 2011, 13:51 [#11]:
Всё нормально, функции рабочие 100%.
про Tag это просто рассуждения были, ну типа я не ждал ответа готового, а тоже шевелил серым веществом в пределах его количества.
в любом случае, есть альтернативный способ сохранения таких массивов.
>Так как массив объявлен как TMatrix = array of array of Integer.
это мне кстати тоже помогло. у меня никак не получалось массив в функцию запихать.
|
|
Вадим К (статус: Академик), 1 марта 2011, 16:33 [#12]:
Гарантировать можно что угодно. Но реальность - суровая штука. Сделал я вот такой примерчик
program test;
Uses sysutils;
{$T+}
{$APPTYPE CONSOLE}
type
tx = array of array of byte;
var i,j:integer;
x:tx;
begin
SetLength(x,3,3);
for i := 0 to 2 do
for j := 0 to 2 do
writeln(format('0x%p, %d', [addr(x[i,j]), cardinal(addr(x[i,j])) - cardinal(addr(x[0,0]))]));
writeln('size = ', cardinal(addr(x[2,2])) - cardinal(addr(x[0,0]))+sizeof(x[0,0]));
writeln('sizeof(tx) = ', sizeof(tx));
end.
Массив я выделил точно так же, как и в приведенном коде в ответе.
Код выводит адреса ячеек памяти, где хранятся элементы массива и смещение от начала массива.
Если высказанное min@y™ было бы правдой, то смещения шли бы последовательно, от 0 и до размер_массива -1.
Но на самом деле код выводит такое
0xB781B028, 0
0xB781B029, 1
0xB781B02A, 2
0xB781B038, 16
0xB781B039, 17
0xB781B03A, 18
0xB781B048, 32
0xB781B049, 33
0xB781B04A, 34
size = 35
sizeof(tx) = 4
Как видно, размер массива должен быть 9 (это 3 на 3), а получилось 35 байт.
P.S. то, что массив не инициализирован никакими значениями не имеет значения. В данном случае интересуют только адреса.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
min@y™ (статус: Доктор наук), 1 марта 2011, 16:44 [#13]:
Цитата (Вадим К):
Как видно, размер массива должен быть 9 (это 3 на 3), а получилось 35 байт.
Размер массива должен быть 36 байт. SizeOf() показывает размер указателя (4 байта), причём совершенно правильно.
Остальное проверю чуть позже.
Кстати, как тогда объяснить, что мои функции отрабатывают правильно? Может компилятор как-то шаманит? Адреса какие-то космические, тебе не кажется?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 1 марта 2011, 16:48 [#14]:
Адреса могут быть космические - у меня этот код под фрипаскалем запускается
Но код проверялся и на реальной делфи. Там вывод такой
0x00860848, 0
0x00860849, 1
0x0086084A, 2
0x00860858, 16
0x00860859, 17
0x0086085A, 18
0x00860868, 32
0x00860869, 33
0x0086086A, 34
size = 35
sizeof(tx) = 4
Галочка "подтверждения прочтения" - вселенское зло.
|
|
min@y™ (статус: Доктор наук), 1 марта 2011, 16:59 [#15]:
Воспроизвести не удалось. Вот я написал функцию:
procedure PrintMatrixMemory(const X: TMatrix);
var
Row, Col: Integer;
begin
for Row:= 0 to High(X) do
for Col:= 0 to High(X[0]) do
WriteLn(' [', Row, ', ', Col, ']', ' = ', X[Row, Col]: 2,
': 0x', IntToHex(Cardinal(Addr(X[Row, Col])), 8));
end;
Вот её вывод в консоль:
Matrix in memory:
[0, 0] = 8: 0x00D00A24
[0, 1] = 5: 0x00D00A28
[0, 2] = 4: 0x00D00A2C
[0, 3] = 4: 0x00D00A30
[0, 4] = 1: 0x00D00A34
[0, 5] = 7: 0x00D00A38
[1, 0] = 6: 0x00D00A48
[1, 1] = 0: 0x00D00A4C
[1, 2] = 0: 0x00D00A50
[1, 3] = 9: 0x00D00A54
[1, 4] = 0: 0x00D00A58
[1, 5] = 9: 0x00D00A5C
[2, 0] = 4: 0x00D00A6C
[2, 1] = 4: 0x00D00A70
[2, 2] = 1: 0x00D00A74
[2, 3] = 5: 0x00D00A78
[2, 4] = 9: 0x00D00A7C
[2, 5] = 3: 0x00D00A80
[3, 0] = 5: 0x00D00A90
[3, 1] = 8: 0x00D00A94
[3, 2] = 8: 0x00D00A98
[3, 3] = 8: 0x00D00A9C
[3, 4] = 3: 0x00D00AA0
[3, 5] = 6: 0x00D00AA4
[4, 0] = 6: 0x00D00AB4
[4, 1] = 9: 0x00D00AB8
[4, 2] = 9: 0x00D00ABC
[4, 3] = 7: 0x00D00AC0
[4, 4] = 0: 0x00D00AC4
[4, 5] = 1: 0x00D00AC8
Как видишь, все адреса идут подряд. Как ты можешь это объяснить?
Выведи у себя абсолютные адреса, посмотрим.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 1 марта 2011, 17:11 [#16]:
В пределах строки, да, адреса идут подряд, но не сплошным потоком. При переходе к следующей строке...
вот тут
[0, 5] = 7: 0x00D00A38
[1, 0] = 6: 0x00D00A48
0x00D00A48 - 0x00D00A38 = 0x10 !!! а не 4, как в других местах.
или тут
[3, 5] = 6: 0x00D00AA4
[4, 0] = 6: 0x00D00AB4
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Ham_ele_on (статус: Посетитель), 1 марта 2011, 18:02 [#17]:
извините если помешал, но может расскажете о чём собственно спор?
|
|
Вадим К (статус: Академик), 1 марта 2011, 18:08 [#18]:
О том, что динамический двумерный массив в памяти не хранится непрерывным куском и приведенный min@y™ код в общем то работать правильно не будет. В некоторых специальных случаях - да, но в общем - нет.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Ham_ele_on (статус: Посетитель), 1 марта 2011, 18:38 [#19]:
>динамический двумерный массив в памяти не хранится непрерывным куском
ну я пока решал проблему сохранения, понял одну вещь, динамический массив это указатели на область памяти, соответственно и хранится он кусками, что логично, а вот почему код не будет правильно работать?
|
|
Вадим К (статус: Академик), 1 марта 2011, 19:16 [#20]:
Хранится оно кусками, а если точнее - строками. Но между строками будут пропуски, которые не нужно сохранять в файл.
Галочка "подтверждения прочтения" - вселенское зло.
|
Страницы: [1] [2] [3] [Следующая »]
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|