Разбор примеров из книги
Модераторы: Oleg_D, Модераторы
Блин, вот я дурак.
Это же мы в цикле for просто делаем предельное число в двое меньше. А не режим саму строку, значение строки не меняется. Я уже понял, спасибо, теперь спокоен!
Это же мы в цикле for просто делаем предельное число в двое меньше. А не режим саму строку, значение строки не меняется. Я уже понял, спасибо, теперь спокоен!
Опять к вам:
В двух словах, придумал сам себе программу, есть n слов, нужно вывести все после первых трех (скажем есть 5 слов, нужно 2 последнии), слова написаны через пробел и не одна строка в файле, а несколько.
В рипит: я проганяю строку, если нахожу пробел, то inc(k) и присваиваю j значение i на месте пробела. Когда будет k=3 заканчиваю цикл.
И перехожу к for-to-do там от места окончание (на каком i закончилась предыдущая строка), я от того места считываю символы и записываю в h.
У меня что-то не рабобает. Возможно, код кривой, долгий, тупой, но пожалуйста, поправьте его на моей основе. Если можете то сделайте более простой, чтобы я разобрал его.
Код: Выделить всё
function Datas: string;
var h, w, s: string;
k, i, j: integer;
begin
read (FileIN, s);
k:=0;
repeat
for i:=1 to length (s) do
if s[i]=' ' then begin k:=k+1; j:=i;
if k=3 then break;
end;
until k=3;
h:='';
for j:=i to length(s) do h:=h+s[i];
datas:=h;
end;
begin
assign (FileIN, 'C:\Users\IN.txt');
reset (FileIN);
while not eof (FileIN) do begin
writeln(datas); readln(filein);
end;
close (FileIN);
end.В двух словах, придумал сам себе программу, есть n слов, нужно вывести все после первых трех (скажем есть 5 слов, нужно 2 последнии), слова написаны через пробел и не одна строка в файле, а несколько.
В рипит: я проганяю строку, если нахожу пробел, то inc(k) и присваиваю j значение i на месте пробела. Когда будет k=3 заканчиваю цикл.
И перехожу к for-to-do там от места окончание (на каком i закончилась предыдущая строка), я от того места считываю символы и записываю в h.
У меня что-то не рабобает. Возможно, код кривой, долгий, тупой, но пожалуйста, поправьте его на моей основе. Если можете то сделайте более простой, чтобы я разобрал его.
deka47 писал(а):придумал сам себе программу, есть n слов, нужно вывести все после первых трех (скажем есть 5 слов, нужно 2 последнии), слова написаны через пробел и не одна строка в файле, а несколько.
Как вариант:
Код: Выделить всё
const
words_to_skip = 3;
var
s: string;
i, w: integer;
begin
w := 0; { счётчик слов }
writeln('Введите текст, для завершения в Linux Ctrl+D, в Windows/DOS - Ctrl+Z:');
while not eof do begin
readln(s);
if w < words_to_skip then begin { выделяем слова, разделитель - пробел }
i := 1;
while (w < words_to_skip) and (i <= length(s)) do begin
while (i <= length(s)) and (s[i] = ' ') do inc(i); { пропустим пробелы }
if i <= length(s) then begin { если строка не кончилась, мы в начале слова ... }
while (i <= length(s)) and (s[i] <> ' ') do inc(i); { ... найдём конец слова ... }
inc(w); { ... и увеличим счётчик слов }
end;
if w = words_to_skip then begin { все слова найдены ... }
{ ... пропустим пробелы и выведем остаток строки }
while (i <= length(s)) and (s[i] = ' ') do inc(i);
if i <= length(s) then writeln('> ', copy(s, i, length(s)));
end;
end;
end else { выводим введённое как есть }
writeln('> ', s);
end;
end.
Код: Выделить всё
> имя_откомпилированной_программы < имя_файла_с_данными
Добавлено спустя 12 минут 15 секунд:
deka47 писал(а):Код: Выделить всё
k := 0;
repeat
for i := 1 to length(s) do
if s[i] = ' ' then begin
k := k + 1;
j := i;
if k = 3 then break;
end;
until k = 3;
Что будет, если в строке s нет 3-х пробелов? Правильно, k не достигнет значения 3. Когда в этом случае завершится цикл repeat until k = 3; ?
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
Что-то не могу понять смысл задачи в главе 48 раздел "А слабо" б):
Это как сделать? Слово ведь состоит из байтов,1 символ = 1 байт.Нужно сделать циклический сдвиг каждого байта в слове или как?
...Напишите функции для циклического сдвига слова влево и вправо...
Это как сделать? Слово ведь состоит из байтов,1 символ = 1 байт.Нужно сделать циклический сдвиг каждого байта в слове или как?
Разница будет только в числе циклов: 8 - для байта, 16 - для Word, 32 - для Longint.
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
Oleg_D писал(а):Разница будет только в числе циклов: 8 - для байта, 16 - для Word, 32 - для Longint.
С числами всё ясно.Но со словом возникают непонятки.например я вожу слово "да" . получаем 2 байта без учёта нулевого.
10100100 10100000 ,сдвигаем влево ==> 01001001 01000001 и получаем сдово "IA" .Или нужно сдвигать каждый байт отдельно?
10100100 10100000 ,сдвигаем влево ==> 01001001 01000001 правда в данном примере результат такой же как и в первом.Так что ли?
Или вы всё-таки вы имели ввиду число,а не слово?
Ой, извините, я сначала не понял вопроса.
Под словом программисты обычно понимают некое машинное слово, которое, в зависимости от разрядности процессора, составляет 1, 2, 4 или более байтов.
Другими словами это числа, а не строки символов. См. также стр. 219, там я сказал об этом.
Под словом программисты обычно понимают некое машинное слово, которое, в зависимости от разрядности процессора, составляет 1, 2, 4 или более байтов.
Другими словами это числа, а не строки символов. См. также стр. 219, там я сказал об этом.
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
Вот что у меня получилось.Написал для типа byte.
Почему пришлось для сдвига влево отключать проверку диапозонов иначе если число больше 127 ,то runtime error 201?
Код: Выделить всё
function testbit(arg,bit:byte):boolean;
begin
testbit:=(arg and (1 shl bit))<>0;
end;
function writenum(arg:byte):string;
var
s:string;i:byte;
c:char;
begin
s:='';
for i:=1 to 8 do begin
c:=char ((arg mod 2)+ord('0'));
s:=c+s;
arg:=arg div 2;
end;
writenum:=s;
end;
procedure rotatebyte(var n:byte;c:char);
var flag:boolean;
begin
case c of
'l' : begin
flag:=testbit(n,7);
{$R-}
n:=n shl 1;
{$R+}
if flag then
n:=1 or n;
end;
'r' : begin
flag:=testbit(n,0);
n:=n shr 1;
if flag then
n:=128 or n;
end;
end;
end;
var
num:byte;
ch:char;
begin
writeln('введите число от 0 до 255');
readln(num);
if not (num in [0..255]) then
writeln('не корректный ввод');
writeln(writenum(num));
writeln('сдвиг влево или вправо l/r ? ');
repeat
readln(ch);
if not (ch in ['l','r']) then
writeln('не корректный ввод');
until ch in ['l','r'];
rotatebyte(num,ch);
writeln(writenum(num));
readln
end.Почему пришлось для сдвига влево отключать проверку диапозонов иначе если число больше 127 ,то runtime error 201?
Не запускал, но глазами проверил, всё нормально вроде бы.
А отключать проверку диапазонов надо потому, что при сдвиге влево числа, содержащего 1 в старшем бите, как раз и происходит такое "нарушение". Но в данном случае мы понимаем причину и допускаем это "нарушение" сознательно.
А отключать проверку диапазонов надо потому, что при сдвиге влево числа, содержащего 1 в старшем бите, как раз и происходит такое "нарушение". Но в данном случае мы понимаем причину и допускаем это "нарушение" сознательно.
Можно много короче: Тестовый прогон:
Добавлено спустя 21 минуту 50 секунд:
И ещё замечание по поводу отключения проверки диапазонов (range check). Безопаснее это делать как-то так:В таком случае, если файл собирается с {$R+}, отключение подействует только на нужный участок кода. Если файл собирается с {$R-}, не произойдёт включения опции на остаток файла, как это было бы в первоначальном примере с незащищённой {$R+} после кода работы со сдвигами. Иными словами, состояние директивы компиляции {$R} вне интересующего нас кода изменено не будет.
Код: Выделить всё
function rotatebyte(n: byte; right: boolean): byte;
begin
if right
then rotatebyte := (n shr 1) or (n shl 7)
else rotatebyte := (n shl 1) or (n shr 7);
end;
function byte2bin(b: byte): string;
var
i: integer;
s: string[8];
begin
s := '';
for i := 7 downto 0 do begin
s := chr(ord('0') + b and 1) + s;
b := b shr 1;
end;
byte2bin := s;
end;
var
number: byte;
direction: char;
begin
write('Введите число [0..255]: '); readln(number);
repeat
write('Введите направление сдвига (l/r): '); readln(direction);
if not (direction in ['l', 'r']) then writeln('*** Ошибка: некорректный ввод');
until direction in ['l', 'r'];
writeln('Было: ', byte2bin(number));
writeln('Стало: ', byte2bin(rotatebyte(number, direction = 'r')));
end.
Код: Выделить всё
Введите число [0..255]: $a5
Введите направление сдвига (l/r): l
Было: 10100101
Стало: 01001011
Добавлено спустя 21 минуту 50 секунд:
И ещё замечание по поводу отключения проверки диапазонов (range check). Безопаснее это делать как-то так:
Код: Выделить всё
function rotatebyte(n: byte; right: boolean): byte;
begin
{$IFOPT R+}{$DEFINE RANGE_ON}{$R-}{$ENDIF}
if right
then rotatebyte := (n shr 1) or (n shl 7)
else rotatebyte := (n shl 1) or (n shr 7);
{$IFDEF RANGE_ON}{$UNDEF RANGE_ON}{$R+}{$ENDIF}
end;
bormant писал(а):В таком случае, если файл собирается с {$R+}, отключение подействует только на нужный участок кода. Если файл собирается с {$R-}, не произойдёт включения опции на остаток файла, как это было бы в первоначальном примере с незащищённой {$R+} после кода работы со сдвигами. Иными словами, состояние директивы компиляции {$R} вне интересующего нас кода изменено не будет.
Спасибо, прекрасные примеры и пояснения. Только условную компиляцию мы здесь ещё не проходили, -- об этом в 60-й главе.
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
Глава 49 разбор программы "Крестики-нолики".
чтение из файла
Изначально вы заполняете матрицу значением false.
Далее
Получается что если символ в строке '+' ,то элементу матрицы присваиваем true ,иначе false.Зачем тогда нужна процедура fillchar,если оба значения всё равно присваиваются матрице.
чтение из файла
Код: Выделить всё
procedure ReadDesk(var F: Text);Изначально вы заполняете матрицу значением false.
Код: Выделить всё
FillChar(Desk, SizeOf(Desk), false);Далее
Код: Выделить всё
Desk[y,x]:= S[x]='+'; Получается что если символ в строке '+' ,то элементу матрицы присваиваем true ,иначе false.Зачем тогда нужна процедура fillchar,если оба значения всё равно присваиваются матрице.
Вот цикл ввода матрицы:
Если файл (или строка) окажется короче, чем требуется, то матрица всё равно будет заполнена определённым образом.
А иначе, без предварительной очистки, там остался бы "мусор".
Код: Выделить всё
while not Eof(F) and (y<=Cy) do begin
Readln(F, S);
x:=1;
while (x<=Length(S)) and (x<=Cx) do begin
Desk[y,x]:= S[x]='+';
Inc(x);
end;
Inc(y);
end
Если файл (или строка) окажется короче, чем требуется, то матрица всё равно будет заполнена определённым образом.
А иначе, без предварительной очистки, там остался бы "мусор".
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
Ясно,к данной программе это не относится.Но на будущее пригодится.
Добавлено спустя 1 час 26 минут 10 секунд:
У меня ещё вопрос по предыдущей программе "Купеческая задачо о пересечении границ" (империя).
Когда нам нужно создать новое множество,мы объявляем пустое множество и добавляем новый элемент к предыдущему значению.
Как быть при работе с массивом множеств?Нужно ли множества массива объявлять пустыми?
В вашей программе этого нет,но я на всякий случай делал так:
Добавлено спустя 1 час 26 минут 10 секунд:
У меня ещё вопрос по предыдущей программе "Купеческая задачо о пересечении границ" (империя).
Когда нам нужно создать новое множество,мы объявляем пустое множество и добавляем новый элемент к предыдущему значению.
Как быть при работе с массивом множеств?Нужно ли множества массива объявлять пустыми?
В вашей программе этого нет,но я на всякий случай делал так:
Код: Выделить всё
procedure ReadSet(var aFile: text; var aSet : TBoundSet);
var k : integer;
begin
aSet:=[];
while not seekEoln(aFile) do begin
Read(aFile, k);
aSet:= aSet+[k];
end;
Readln (aFile);
end; Paster Fob писал(а): aSet:=[];
Да, это правильно. А я упустил очистку множества, надо поправить.
Современные компиляторы автоматически очищают секцию глобальных переменных, и оттого следствия таких пропусков не всегда проявляются.
Но привычка явной инициализации -- это хорошая привычка.
