Помощь - Поиск - Пользователи - Календарь
Полная версия: Работа с потоком
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
18192123
В поток записана последовательность целых чисел. Найти минимум и максимум и поменять их местами, не используя дополнительных потоков.

Начала я с того, что попыталась сосчитать первое число, чтоб было с чем сравнивать...
Проблема в том, что если в файле одно число - то оно фиксируется и выводиться (в компонент Memo) как надо, но если больше - приложение вылетает с ошибкой " '1-е число из файла' is not a valid integer value"..
структура файла:
11
22
56
...
и т.д

Объясните, как исправить, чтоб отработало без ошибок?

procedure TForm1.Convert;
var
i, j, k: Word;
c: Char;
l,numb,min,max: Integer;
str:string;
f: Boolean;
S: TStream; // переменная потокового типа
begin
S := TFileStream.Create(FName, fmOpenReadWrite);
//загружаем в поток типа FileStream содержимое файла FName
//тело алгоритма
with S do
begin
Position := 0; // установка указателя потока в начало
i := 0;
k := Size; // в k - размер потока в байтах
Read(c,1);
j:=1;
while (c<>#10)and(i<=k-1) do
begin
inc(i);
inc(j);
str:=str+c;
read(c,1);
end;
min:=StrToInt(str);

memo1.Lines.Add(IntToStr(min));
end
end;


volvo
Цитата
как исправить, чтоб отработало без ошибок?
Вот так:
while (c<>#13)and(i<=k-1) do // <--- Признак конца строки - это #13#10, а не наоборот...
18192123
Цитата(volvo @ 24.04.2008 17:03) *

Вот так:
while (c<>#13)and(i<=k-1) do // <--- Признак конца строки - это #13#10, а не наоборот...


Спасибо большое!)

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


procedure TForm1.Convert;
var
i, j, k: Word;
c: Char;
l,numb,min,max: Integer;
str:string;
f: Boolean;
S: TStream; // переменная потокового типа
begin
S := TFileStream.Create(FName, fmOpenReadWrite);
//загружаем в поток типа FileStream содержимое файла FName
with S do
begin
Position := 0; // установка указателя потока в начало
i := 0;
k := Size; // в k - размер потока в байтах
Read(c,1);
j:=1;
while (c<>#13)and(i<=k-1) do
begin
inc(i);
inc(j);
str:=str+c;
read(c,1);
end;
min:=StrToInt(str);
max:=StrToInt(str);
Position := i+1; // установка указателя потока после 1-го элемента
while i <> k do
begin
Read(c, 1);
inc(i);
j := 1;
while (c <> #13) and (i <= k - 1) do
begin
str:=str+c;
Read(c, 1);
inc(i);
inc(j);
end;
numb:=StrToInt(str);
if numb<min then min:=numb;
if numb>max then max:=numb;

end; {end while i<>k}
// загружаем в Memo1 содержимое преобразованного файла
//Memo1.Lines.LoadFromFile(FName);
memo1.Lines.Add(IntToStr(min)); {ну это просто для собственного контроля) }
memo1.Lines.Add(IntToStr(max));
end
end;



volvo
Во-первых, вот тут:
Цитата
Position := i+1; // установка указателя потока после 1-го элемента
Почему увеличиваешь на 1? Надо на 2, #13#10 - это 2 символа...

Во-вторых, надо при чтении следующего числа сбрасывать str в пустую строку...

А вообще, я бы сделал так:
procedure TForm1.Convert;
var
i, k: Word;
c: Char;
numb,min,max: Integer;
str:string;
S: TStream; // переменная потокового типа
begin
S := TFileStream.Create(FName, fmOpenReadWrite);

min := MaxInt;
max := -MaxInt;

//загружаем в поток типа FileStream содержимое файла FName
with S do begin

Position := 0; i := 0;
k := Size;

repeat
c := #0; str := '';
while (i < k) do begin
read(c, 1);
if c = #13 then break;

inc(i); str := str + c;
end;

numb:=StrToInt(str);
if numb<min then min:=numb;
if numb>max then max:=numb;

Read(c, 1); // read #10
until Position = Size;

memo1.Lines.Add(IntToStr(min));

memo1.Lines.Add(IntToStr(max));
end; // with
end;
18192123
Цитата(volvo @ 24.04.2008 18:25) *

А вообще, я бы сделал так:


Спасибо за объяснение! С этим ясно..

А как теперь переставить местами найденные элементы? Наверное можно "запоминать" кол-во символов для каждого из них ещё в процессе поиска, а ещё нужно позицию мах и мин отследить...А как это осуществить?? И как в принципе осуществить саму перезапись?
18192123
Добавила нахождение позиций максимального и минимального элемента, и запись элементов от этих позиции во вспомогательные..
Только не знаю, как записать вместо одного другое..Объясните пожалуста!


procedure TForm1.Convert;
var
i, j, k,pos_max, pos_min, dl_min, dl_max: Word;
c: Char;
numb,min,max: Integer;
str,help,help1:string;
S: TStream; // переменная потокового типа
begin
S := TFileStream.Create(FName, fmOpenReadWrite);

min := MaxInt;
max := -MaxInt;

//загружаем в поток типа FileStream содержимое файла FName
with S do begin

Position := 0; i := 0;
k := Size;

repeat
c := #0; str := '';
j:=0;
while (i < k) do begin
read(c, 1);
inc(j);
if c = #13 then break;

inc(i); str := str + c;
end;

numb:=StrToInt(str);
if numb<min then
begin
min:=numb;
pos_min:=i-j-1;
dl_min:=j;
end;
if numb>max then
begin
max:=numb;
pos_max:=i-j-1;
dl_max:=j;
end;
position:=pos_min;
for k:=pos_min to pos_min+dl_min do
begin
read(c,1);
help:=help+c;
end;
position:=pos_max;
for k:=pos_max to pos_max+dl_max do
begin
read(c,1);
help1:=help1+c;
end;
Read(c, 1); // read #10
until Position = Size;

memo1.Lines.Add(IntToStr(min));

memo1.Lines.Add(IntToStr(max));
end; // with
end;

18192123
И даже то, что дописала про нахождение позиций не работает - вылетает ошибка..
А про перезапись так и не могу понять...Пожалуста, объясните...
18192123
Вот что я добавила:перезаписала на место максимального миниальный..Но снова ошибка: " '' is not a valid integer value"..

Объясните, что я не так делаю...
18192123
Вот код для предыдущего сообщения..


procedure TForm1.Convert;
var
i, j, k, pos_max, pos_min: integer;
c: Char;
numb,min,max,mins,maxs: Integer;
str,help,help1:string;
S: TStream; // переменная потокового типа
begin
S := TFileStream.Create(FName, fmOpenReadWrite);
numb:=0;
min := MaxInt;
max := -MaxInt;
pos_max:=0;
pos_min:=0;
mins:=0;
maxs:=0;

//загружаем в поток типа FileStream содержимое файла FName
with S do begin

Position := 0; i := 0;
k := Size;
Edit1.Text:=IntToStr(k);
repeat
c := #0; str := '';
j:=0;
while (i < k) do begin
read(c, 1);
inc(i);
if c = #13 then break;
inc(j);
str := str + c;
end;

numb:=StrToInt(str);
if numb<min then
begin
min:=numb;
pos_min:=i-j;
mins:=j;
end;
if numb>max then
begin
max:=numb;
pos_max:=i-j;
maxs:=j;
end;

Read(c, 1); // read #10
inc(i);
until Position = Size;

position:=pos_min;
while (c<>#13) do
begin
position:=pos_min;
inc(pos_min);
read(c,1);
position:=pos_max;
inc(pos_max);
write(c,1);
end;

Free;
memo1.Lines.LoadFromFile(FName);
end; // with
end;



А ещё у мея такой вопрос: я в отладчике обнаружила, что строки


mins:=0;
...........
maxs:=0;
..............
mins:=j;
...........
maxs:=j;



попросту игнорируются отладчиком...почему так???
volvo
Цитата
А ещё у мея такой вопрос: я в отладчике обнаружила, что строки <...> попросту игнорируются отладчиком...почему так???
А почему они не должны игнорироваться? Ты что, где-то используешь mins/maxs? Нет... Вот когда будешь использовать - компилятор будет обрабатывать их изменение...

Вот отработавший код (для случая, когда min и max содержат одинаковое число цифр!!!):

...
//загружаем в поток типа FileStream содержимое файла FName
with S do begin

Position := 0; i := 0;
k := Size;

repeat
c := #0; str := '';
while (i < k) do begin
read(c, 1);
if c = #13 then break;

inc(i); str := str + c;
end;

numb:=StrToInt(str);
if numb<min then begin
min:=numb; pos_min := Position - length(str) - 1;
end;
if numb>max then begin
max:=numb; pos_max := Position - length(str) - 1;
end;

Read(c, 1); // read #10
until Position = Size;

Position := pos_min;
str := IntToStr(max);
for i := 1 to length(str) do begin
Write(str[i], 1);
end;

Position := pos_max;
str := IntToStr(min);

for i := 1 to length(str) do begin
Write(str[i], 1);
end;
end; // with

S.Destroy;
memo1.Lines.LoadFromFile(FName);
...
Если минимальное и максимальное числа состоят из разного количества цифр - придется извращаться дополнительно...
18192123
Цитата(volvo @ 27.04.2008 13:42) *

Если минимальное и максимальное числа состоят из разного количества цифр - придется извращаться дополнительно...

А как быть в этом случае?
Сдвигать остальное на разницу между длинами максимального и минимального элементов?
volvo
Угу... Только следить за тем, чтобы копирование шло в правильном направлении... Если pos_max > pos_min, то проще копировать символы "назад" (перемещая их ближе к концу потока), а если наоборот - то "вперед", перемещая ближе к началу...
18192123
Цитата(volvo @ 27.04.2008 14:11) *

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

а как это лучше (разумнее) сделать?
18192123
Вот моя попытка разобрать случай, если кол-во цифр в максим. и миним. элементах не равно: пока сделала для случая если pos_max>pos_min...

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

Объясните пожалуста, как это исправить?


procedure TForm1.Convert;
var
i, j, k, pos_max, pos_min: integer;
c: Char;
numb,min,max,dif: Integer;
str,help:string;
S: TStream; // переменная потокового типа
begin
S := TFileStream.Create(FName, fmOpenReadWrite);
numb:=0; dif:=0;
min := MaxInt;
max := -MaxInt;
pos_max:=0;
pos_min:=0;
help:='';
with S do begin
Position := 0; i := 0;
k := Size;
while (i<k) do
begin
read(c,1);
inc(i);
help:=help+c;
end;
edit1.Text:=inttostr(k);
Position := 0; i := 0;
k := Size;

repeat
c := #0; str := '';
while (i < k) do begin
read(c, 1);
if c = #13 then break;

inc(i); str := str + c;
end;

numb:=StrToInt(str);
if numb<min then begin
min:=numb; pos_min := Position - length(str) - 1;
end;
if numb>max then begin
max:=numb; pos_max := Position - length(str) - 1;
end;

Read(c, 1); // read #10
until Position = Size;

dif:=Length(IntToStr(max)) - Length(IntToStr(min));
if dif=0 then
begin
Position := pos_min;
str := IntToStr(max);
for i := 1 to length(str) do begin
Write(str[i], 1);
end;
Position := pos_max;
str := IntToStr(min);
for i := 1 to length(str) do begin
Write(str[i], 1);
end;
end {end if dif=0}
else
begin
if pos_max > pos_min then
begin
position:=pos_min+dif;
for i:=pos_min+2 to pos_max-1 do
Write(help[i], 1);
Position := pos_min;
str := IntToStr(max);
for i := 1 to length(str) do
Write(str[i], 1);
Position := pos_max;
str := IntToStr(min);
for i := 1 to length(str) do
Write(str[i], 1);

end {end if pos_max > pos_min}
else
begin
{дописать}
end; {end else pos_max > pos_min}
end; {end else of dif=0}
end; // with

S.Destroy;
memo1.Lines.LoadFromFile(FName);

end;


18192123
Пожалуста, объясните, как избавиться от лишних цифр, остающихся от максимального элемента, рядом с минимальным после изменения их порядка..??
volvo
Лень запускать Дельфи smile.gif , я сделал эмуляцию работы с потоком при помощи строки на FPC:

uses sysutils;
const
s: string =
// '72'#13#10'21543'#13#10'57'#13#10'19'#13#10'14'#13#10'84'; (* 1 *)
'72'#13#10'14'#13#10'57'#13#10'19'#13#10'8874'#13#10'84'; (* 2 *)
var
pos_min, pos_max: integer;
i, j, min, max, delta: integer;
st: string;

begin
writeln(s);
(* // 1
pos_max := 5; max := 21543;
pos_min := 20; min := 14;
*)
// 2
pos_min := 5; min := 14;
pos_max := 17; max := 8874;

delta := length(inttostr(max)) - length(inttostr(min));

if pos_max < pos_min then begin // Первый случай

i := pos_max + length(inttostr(min));
while i < pos_min do begin
s[i] := s[i + delta]; inc(i);
end;

st := inttostr(min);
for i := 1 to length(st) do begin
s[pos_max + i - 1] := st[i]
end;
st := inttostr(max);
for i := 1 to length(st) do begin
s[pos_min - delta + i - 1] := st[i]
end;
end

else begin // Второй случай

i := pos_max + length(inttostr(min)) - 1;
while i - delta > pos_min do begin
s[i] := s[i - delta]; dec(i);
end;

st := inttostr(min);
for i := 1 to length(st) do begin
s[pos_max + delta + i - 1] := st[i]
end;
st := inttostr(max);
for i := 1 to length(st) do begin
s[pos_min + i - 1] := st[i]
end;

end;

writeln('final = ', s);

end.


Вот что программа выводит:
Цитата(Консоль)

Running "g:\programs\pascal\__potok.exe"
72
21543
57
19
14
84
final = 72
14
57
19
21543
84

Running "g:\programs\pascal\__potok.exe"
72
14
57
19
8874
84
final = 72
8874
57
19
14
84
(сначала - первый случай (pos_max < pos_min), потом - второй... Вроде ничего лишнего в строке-результате нет)... В принципе, можно пошаманить и сделать все без двух веток if/else, но так как есть - более понятен алгоритм, поэтому я оставил без "шаманства".
18192123
Снова я что-то напутала...Результаты работы приложения далеко не те, какими должны быть..

Содержимое файла:
45
2
3
1

Результат:
45
2
3
145

Содержимое файла:
1
2
3
45

Результат:
1452
3

1

2

1



dif:=Length(IntToStr(max)) - Length(IntToStr(min));
if pos_max < pos_min then
begin
i := pos_max + length(IntToStr(min));
position:=i;
while i < pos_min do begin
help[i] := help[i + dif];
inc(i);
write(help[i],1);
end;

str := inttostr(min);
position:= pos_max + i - 1;
for i := 1 to length(str) do begin
//help[pos_max + i - 1] := str[i];
write(str[i],1);//write(help[pos_max + i - 1],1);
end;
str := inttostr(max);
position:= pos_min - dif + i - 1;
for i := 1 to length(str) do begin
//help[pos_min - dif + i - 1] := str[i];
write(str[i],1);//write(help[pos_min - dif + i - 1],1);
end;
end {end if pos_max < pos_min}
else
begin
i := pos_max + length(inttostr(min)) - 1;
position:=i;
while i - dif > pos_min do begin
help[i] := help[i - dif];
dec(i);
write(help[i],1);
end;

str := inttostr(min);
position:= pos_max + dif + i - 1;
for i := 1 to length(str) do begin
//help[pos_max + dif + i - 1] := str[i];
write(str[i],1);//write(help[pos_max + dif + i - 1],1);
end;
str := inttostr(max);
position:= pos_min + i - 1;
for i := 1 to length(str) do begin
//help[pos_min + i - 1] := str[i];
write(str[i],1);//write(help[pos_min + i - 1],1);
end;
end; {end else pos_max < pos_min}




Уже и не знаю, что я снова не правильно делаю..Объясните пожалуста!..
volvo
...
delta := length(inttostr(max)) - length(inttostr(min));
if pos_max < pos_min then begin

i := pos_max + length(inttostr(min));
while i < pos_min do begin
S.Position := i + delta; S.Read(C, 1);
S.Position := i; S.Write(C, 1);
inc(i);
end;

str := inttostr(min);
S.Position := pos_max;
for i := 1 to length(str) do begin
S.Write(str[i], 1);
end;
str := inttostr(max);
S.Position := pos_min - delta;
for i := 1 to length(str) do begin
S.Write(str[i], 1);
end;
end

else begin

i := pos_max + length(inttostr(min));
while i - delta > pos_min do begin
S.Position := i - delta; S.Read(C, 1);
S.Position := i; S.Write(C, 1);
dec(i);
end;

str := inttostr(min);
S.Position := pos_max + delta;
for i := 1 to length(str) do begin
S.Write(str[i], 1);
end;
str := inttostr(max);
S.Position := pos_min;
for i := 1 to length(str) do begin
S.Write(str[i], 1);
end;

end;
...


Содержимое файла:
72
11245
57
19
12
84

в Memo:
72
12
57
19
11245
84

Что я делаю не так? smile.gif
18192123
Цитата(volvo @ 27.04.2008 21:05) *


Что я делаю не так? smile.gif

Всё так)) Спасибо большое!!)
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.