IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

 
 Ответить  Открыть новую тему 
> Работа с потоком
18192123
сообщение 24.04.2008 14:05
Сообщение #1


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


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

Начала я с того, что попыталась сосчитать первое число, чтоб было с чем сравнивать...
Проблема в том, что если в файле одно число - то оно фиксируется и выводиться (в компонент 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;




Сообщение отредактировано: 18192123 - 24.04.2008 14:14
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 24.04.2008 16:03
Сообщение #2


Гость






Цитата
как исправить, чтоб отработало без ошибок?
Вот так:
while (c<>#13)and(i<=k-1) do // <--- Признак конца строки - это #13#10, а не наоборот...
 К началу страницы 
+ Ответить 
18192123
сообщение 24.04.2008 16:53
Сообщение #3


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(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;



 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 24.04.2008 17:25
Сообщение #4


Гость






Во-первых, вот тут:
Цитата
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
сообщение 24.04.2008 18:14
Сообщение #5


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 24.04.2008 18:25) *

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


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

А как теперь переставить местами найденные элементы? Наверное можно "запоминать" кол-во символов для каждого из них ещё в процессе поиска, а ещё нужно позицию мах и мин отследить...А как это осуществить?? И как в принципе осуществить саму перезапись?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
18192123
сообщение 24.04.2008 19:48
Сообщение #6


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Добавила нахождение позиций максимального и минимального элемента, и запись элементов от этих позиции во вспомогательные..
Только не знаю, как записать вместо одного другое..Объясните пожалуста!


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 - 24.04.2008 20:42
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
18192123
сообщение 24.04.2008 22:09
Сообщение #7


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


И даже то, что дописала про нахождение позиций не работает - вылетает ошибка..
А про перезапись так и не могу понять...Пожалуста, объясните...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
18192123
сообщение 24.04.2008 22:31
Сообщение #8


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Вот что я добавила:перезаписала на место максимального миниальный..Но снова ошибка: " '' is not a valid integer value"..

Объясните, что я не так делаю...

Сообщение отредактировано: 18192123 - 27.04.2008 12:25
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
18192123
сообщение 27.04.2008 12:30
Сообщение #9


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Вот код для предыдущего сообщения..


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;



попросту игнорируются отладчиком...почему так???
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 27.04.2008 12:42
Сообщение #10


Гость






Цитата
А ещё у мея такой вопрос: я в отладчике обнаружила, что строки <...> попросту игнорируются отладчиком...почему так???
А почему они не должны игнорироваться? Ты что, где-то используешь 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
сообщение 27.04.2008 13:03
Сообщение #11


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 27.04.2008 13:42) *

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

А как быть в этом случае?
Сдвигать остальное на разницу между длинами максимального и минимального элементов?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 27.04.2008 13:11
Сообщение #12


Гость






Угу... Только следить за тем, чтобы копирование шло в правильном направлении... Если pos_max > pos_min, то проще копировать символы "назад" (перемещая их ближе к концу потока), а если наоборот - то "вперед", перемещая ближе к началу...
 К началу страницы 
+ Ответить 
18192123
сообщение 27.04.2008 13:18
Сообщение #13


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 27.04.2008 14:11) *

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

а как это лучше (разумнее) сделать?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
18192123
сообщение 27.04.2008 15:13
Сообщение #14


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Вот моя попытка разобрать случай, если кол-во цифр в максим. и миним. элементах не равно: пока сделала для случая если 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;


 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
18192123
сообщение 27.04.2008 17:17
Сообщение #15


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Пожалуста, объясните, как избавиться от лишних цифр, остающихся от максимального элемента, рядом с минимальным после изменения их порядка..??
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 27.04.2008 18:35
Сообщение #16


Гость






Лень запускать Дельфи 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
сообщение 27.04.2008 19:34
Сообщение #17


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Снова я что-то напутала...Результаты работы приложения далеко не те, какими должны быть..

Содержимое файла:
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}
       



Уже и не знаю, что я снова не правильно делаю..Объясните пожалуста!..
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 27.04.2008 20:05
Сообщение #18


Гость






...
  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
сообщение 27.04.2008 20:36
Сообщение #19


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 27.04.2008 21:05) *


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

Всё так)) Спасибо большое!!)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия 20.07.2025 0:37
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"