Добрый день!
Занимаюсь решением задач из задачника Андрея Столярова. В процессе решения задачи 2.15. возник вопрос.
Задача следующая:
"Написать программу, запрашивающую два числа (высоту буквы и количество таких букв) и печатающую нужное количество букв Z заданной высоты, причем каждая следующая буква Z должна отстоять от предыдущей на один пробел по горизонтали и на половину высоты буквы по вертикали. Например, для чисел 7 и 3 картина должна получиться такая:
*******
*
*
******* *******
* *
* *
******* ******* *******
* *
* *
******* *******
*
*
*******
Программу написал следующую:
rogram z_sequence;
procedure PrintChars(count: integer);
var
i: integer;
begin
for i := 1 to count do
write('*')
end;
procedure PrintSpaces(count: integer);
var
i: integer;
begin
for i := 1 to count do
write(' ')
end;
procedure PrintLineOfDiamondUp(i, z: integer);
begin
if i = 1 then
PrintChars(z)
else
begin
PrintSpaces(z - i);
PrintChars(1)
end;
writeln
end;
procedure PrintLineOfDiamondDown(i, z: integer);
begin
if i = 1 then
exit
else
begin
PrintSpaces(i - 1);
PrintChars(1)
end
end;
procedure PrintFirstHalf(z: integer);
var
i: integer;
begin
for i := 1 to (z div 2) do
PrintLineOfDiamondUp(i, z)
end;
procedure PrintFirstCenterBar(z, n: integer);
begin
if n > 1 then
begin
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
writeln
end
else
PrintChars(z);
writeln
end;
procedure PrintHalf(i, a, z: integer);
var
count: integer;
begin
if i = 1 then
begin
for count := (z div 2) downto 2 do
begin
PrintSpaces(a * z + a);
PrintLineOfDiamondDown(count, z);
writeln
end
end;
if i > 1 then
begin
for count := (z div 2) downto 2 do
begin
PrintSpaces(a * z + a);
PrintLineOfDiamondDown(count, z);
PrintSpaces((z div 2 + 1) + 1 + (z - 2));
PrintChars(1);
writeln
end
end
end;
procedure PrintBar(i, a, z: integer);
begin
if i = 1 then
begin
PrintSpaces(a * z + a);
PrintChars(z);
writeln
end;
if i = 2 then
begin
PrintSpaces(a * z + a);
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
writeln
end;
if i >= 3 then
begin
PrintSpaces(a * z + a);
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
writeln
end
end;
var
i, n, a, z: integer;
begin
repeat
writeln('Enter the letter''s height (5 or more, odd)');
readln(z);
until (z >= 5) and (z mod 2 = 1);
repeat
writeln('Enter the number of the letters');
readln(n);
until (n >= 1);
PrintFirstHalf(z);
PrintFirstCenterBar(z, n);
a := 0;
for i := n downto 1 do
begin
PrintHalf(i, a, z);
PrintBar(i, a, z);
a := a + 1
end
end.
Однако, она выдавала такой результат:
*******
*
*
******* *******
* *
* *
******* ******* *******
* *
* *
******* *******
*
*
*******
т.е. после первой центральной черты печатается лишний перенос строки.
Опытным путем понял, что если в процедуре PrintFirstCenterBar убрать writeln и напечатать вместо
procedure PrintFirstCenterBar(z, n: integer);
begin
if n > 1 then
begin
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
writeln
end
else
PrintChars(z);
writeln
end;
procedure PrintFirstCenterBar(z, n: integer);
begin
if n > 1 then
begin
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
end
else
PrintChars(z);
writeln
end;
программа станет работать корректно.
Но почему так происходит?
Ни PrintChars ни PrintSpaces не печатает перенос строки. В условии после else стоит writeln и если попросить программу напечатать одну букву Z лишнего переноса не произойдет.
Подпрограмма PrintBar
procedure PrintBar(i, a, z: integer);
begin
if i = 1 then
begin
PrintSpaces(a * z + a);
PrintChars(z);
writeln
end;
if i = 2 then
begin
PrintSpaces(a * z + a);
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
writeln
end;
if i >= 3 then
begin
PrintSpaces(a * z + a);
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
PrintSpaces(1);
PrintChars(z);
writeln
end
end;
очень похожа по своей структуре на PrintFirstCenterBar, но там все writeln стоят на своём месте и никакого лишнего переноса строки не вызывают.
Так почему же тогда в подпрограмме PrintFirstCenterBar оператор writeln является лишним?