Глава 23. Задание " Б ".

Книга адресована школьникам средних и старших классов, желающим испытать себя в «олимпийских схватках». Может быть полезна студентам-первокурсникам и преподавателям информатики.

Модераторы: Oleg_D, Модераторы

Герман
новенький
Сообщения: 26
Зарегистрирован: 27.10.2016 10:11:41

Глава 23. Задание " Б ".

Сообщение Герман »

Задание:
Б) Напишите функцию для определения позиции буквы в заданной строке. Функция должна вернуть позицию первой такой буквы или ноль, если буквы в строке нет. Напишите программу для проверки функции.

В книге с ответами есть ответ на задание " В ".

Вот мои потуги:

Код: Выделить всё

{--- funkcya ---}
function Poisk(const str : string;
                      ch : char) : integer;
var i, N : integer;

begin
  Poisk := 0;
  i := 1;
  repeat
    if str[i]= ch
      then Poisk := 0 + i;
  until Poisk > 0;
end;

{--- glavnaya programma ---}

var S : string;

begin
  Write(' Vvedite stroku, '); Readln(S);
  Writeln(Poisk(S, 'A'));
  Readln;
end.

В чем моя ошибка? Help, please.

Добавлено спустя 16 минут 16 секунд:
Нашел ответ в другой теме:

Код: Выделить всё

function poisk(str:string;ch:char):integer;
var i : integer;
begin
    poisk:=0;
    for i:=1 to length(str) do
      if str[i]=ch then
        begin
          poisk:=i;
          break;
        end
end;


Сбило меня с толку что команда break работает вместе с until.
И все же. Почему мой код не работает?
Zhbr
новенький
Сообщения: 44
Зарегистрирован: 31.01.2014 02:34:21

Сообщение Zhbr »

Счётчик в твоем цикле util не на работает, то есть его вообще нет) i постоянно равна 1, цикл бесконечный получается.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

и, кстати, в repeat... until неправильное условие -- если уж делать этим циклом, то надо проверить размер строки и в условии проверять равно ли ей i.

так как бы не совсем правильно

Код: Выделить всё

 then Poisk := 0 + i;


достаточно

Код: Выделить всё

 then Poisk := i;


кстати, в работающем коде тоже есть небольшая ошибка

Код: Выделить всё

for i:=1 to length(str) do

лучше поменять на

Код: Выделить всё

N:=  length(str);
for i:=1 to N do

дело в том, что вычисление длинны строки в каждой итерации цикла слишком затратно.
Аватара пользователя
bormant
постоялец
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Сообщение bormant »

Лекс Айрин писал(а):дело в том, что вычисление длинны строки в каждой итерации цикла слишком затратно.

Вероятно, чтение документации, в которой прямо сказано, что начальное и конечное значения вычисляются один раз до начала цикла и до инициализации счетчика цикла, еще затратнее...
http://www.freepascal.org/docs-html/ref/refsu59.html
Герман
новенький
Сообщения: 26
Зарегистрирован: 27.10.2016 10:11:41

Сообщение Герман »

Спб за помощь. Все таки я не одолел конструкцию через repeat
until
Аватара пользователя
bormant
постоялец
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Сообщение bormant »

Герман писал(а):Спб за помощь. Все таки я не одолел конструкцию через repeat until

Код: Выделить всё

function Poisk(const s: String; c: Char): Integer;
var i, n: Integer;
begin
  n:=Length(s); i:=0;
  repeat Inc(i) until (i>n) or (s[i]=c);
  if i>n then i:=0;
  Poisk:=i;
end;
или

Код: Выделить всё

function Poisk(const s: String; c: Char): Integer;
var i, n: Integer;
begin
  n:=Length(s); i:=0;
  repeat Inc(i) until (i>n) or (s[i]=c);
  Poisk:=i*Ord(i<=n);
end;
Герман
новенький
Сообщения: 26
Зарегистрирован: 27.10.2016 10:11:41

Сообщение Герман »

Спб. Я еще не дошел в книге до Inc(i).
Аватара пользователя
bormant
постоялец
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Сообщение bormant »

Inc(i) тождественно i:=i+1.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

bormant писал(а):
Лекс Айрин писал(а):дело в том, что вычисление длинны строки в каждой итерации цикла слишком затратно.

Вероятно, чтение документации, в которой прямо сказано, что начальное и конечное значения вычисляются один раз до начала цикла и до инициализации счетчика цикла, еще затратнее...
http://www.freepascal.org/docs-html/ref/refsu59.html

ок. Про этот нюанс я откровенно забыл. Но все равно не стал бы на него надеяться. Ибо это конкретная реализация, на которую программист не должен опираться.(например, длинна строки может поменяться в цикле,(в сторону уменьшения), что может привести к непредсказуемым последствиям.)
Аватара пользователя
bormant
постоялец
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Сообщение bormant »

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

1) нет. Это поведение с незапамятных времён и, если правильно путаю, свойство самого языка, как и неопределенность значения счетчика цикла по завершении цикла не по Break.
2) для меняющейся длины строки, где возможно используют
for i:=Length(s) downto 1 do ...
где невозможно, там и экономия с отдельной переменной теряет смысл, остаются
while (i<=Length(s)) and ... do ...
либо опора на барьер в виде завершающего #0 для строк без предвычисленный длины.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

bormant писал(а):1) нет. Это поведение с незапамятных времён и, если правильно путаю, свойство самого языка, как и неопределенность значения счетчика цикла по завершении цикла не по Break.

Это неважно, так как может поменяться в любой момент. Да и не является это свойством языка -- это метод реализации через ассемблерную инструкцию Loop. А насчет неопределенности... значение счетчика неопределено вне цикла независимо от способа выхода из него. По крайней мере в классическом паскале.
bormant писал(а):2) для меняющейся длины строки, где возможно используют
for i:=Length(s) downto 1 do ...
где невозможно, там и экономия с отдельной переменной теряет смысл, остаются
while (i<=Length(s)) and ... do ...
либо опора на барьер в виде завершающего #0 для строк без предвычисленный длины.

Я бы вообще осторожно использовал здесь for
Аватара пользователя
bormant
постоялец
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Сообщение bormant »

Это может поменяться в любой момент примерно с той же вероятностью, что и полностью выбросить синтаксис Паскаля и заменить его чем-то другим. С 1972 года не менялось, а тут ни с того ни с сего поменяется.
http://www.eah-jena.de/~kleine/history/ ... Report.pdf , стр. 29.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

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

Согласен, но... сколько лет пользовались досом и вдруг появилась винда...
daesher
постоялец
Сообщения: 221
Зарегистрирован: 09.03.2010 21:17:14

Сообщение daesher »

bormant писал(а):Это может поменяться в любой момент примерно с той же вероятностью, что и полностью выбросить синтаксис Паскаля и заменить его чем-то другим. С 1972 года не менялось, а тут ни с того ни с сего поменяется.
http://www.eah-jena.de/~kleine/history/ ... Report.pdf , стр. 29.

Там же чёрным по белому написано
The control variable, the initial value and the final value ... must not be altered by the repeated statement

Короче, изначально действует правило - не менять начальное и конечное значение. Что будет, если оно изменится - по идее, зависит от реализации. Другое дело, что легче реализовать расчёт один раз, чем перепроверять каждый раз.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

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


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

Указанное поведение заточено под массивы со статическим размером. Уже при динамических придется использовать другие методы. Или пользоваться аварийным выходом в виде оператора прерывания цикла. (фактически, запретным goto из тела цикла).
Ответить