Форум программистов, компьютерный форум, киберфорум
Pascal (Паскаль)
Войти
Регистрация
Восстановить пароль
Другие темы раздела
Pascal Установить в Debian что-нибудь похожее интерфейсом IDE на Turbo Pascal https://www.cyberforum.ru/ pascal/ thread1260862.html
Подскажите, что и как можно установить в Debian что-нибудь похожее интерфейсом IDE на Turbo Pascal. Спасибо. Добавлено через 3 минуты Да, ещё желательно, чтоб была совместимость с синтаксисом...
Pascal В массиве удалить все элементы кратные заданному числу
Задать три массива: один случайными целыми числами, второй вещественными положительными числами, третий - целыми числами в диапазоне значений от h до f. В первом массиве удалить все элементы кратные...
Вывести K-e степени чисел из заданного набора Pascal
Вариант4. Даны целые числа K, N и набор из N вещественных чисел: A1, A2, …,AN. Вывести K-e степени чисел из данного набора: (A1)^K, (A2)^K, …, (AN)^K. ^cтепень
Pascal Вычислить значение y в зависимости от х функции очень нуждаюсь в помощи.. нужно вычислить значение y в зависимости от х функции... https://www.cyberforum.ru/ pascal/ thread1260635.html
Pascal Задать массив вещественными числами от а до в, в количестве n и найти сумму всех цифр чисел кратных трем https://www.cyberforum.ru/ pascal/ thread1260321.html
Задать массив вещественными числами от а до в , в количестве n и найти сумму всех цифр чисел кратных трем
Задать массив целыми числами в диапазоне [0.100] и удалить все элементы , у которых последняя цифра 8 Pascal
Задать массив целыми числами в диапазоне и удалить все элементы , у которых последняя цифра 8
Pascal Если в строке, размещенной в динамической памяти, нет символа +, то оставить текст без изменения
Если в строке,размещенной в динамической памяти,нет символа +,то оставить текст без изменения, иначе каждую из цифр, предшествующую первому вхождению символа + заменить символом -.помогите сделать на...
Pascal Найти в последовательности самую длинную подпоследовательность, состоящую только из положительных чисел Найти в заданной последовательности самую длинную подпоследовательность, состоящую только из положительных чисел. используя текстовые файлы https://www.cyberforum.ru/ pascal/ thread1260267.html
Pascal Написать программу, в которой задается число, а компьютер его угадывает https://www.cyberforum.ru/ pascal/ thread1259883.html
помогите пожалуйста, написать программу, в которой я задаю число, а компьютер угадывает это число. количество попыток ограничено ?
Pascal Дан текст содержащий сведения об успеваемости учащихся. Определить средний балл каждого ученика Задача:Дан текст содержащий сведения об успеваемости учащихся, разделенное запятой.Каждое сведение содержит фамилию, имя ученика и оценки по 4 предметам, и заканчивается ".". Определить средний... https://www.cyberforum.ru/ pascal/ thread1259643.html
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
30867 / 20189 / 7874
Регистрация: 22.10.2011
Сообщений: 35,049
Записей в блоге: 6
22.09.2014, 21:22  [ТС] 0

Как не надо писать программы

22.09.2014, 21:22. Просмотров 17381. Ответов 4
Метки (Все метки)

Ответ


(заканчиваем)

Паскаль - это язык с очень мощной системой типов. Если правильно использовать этот факт, то можно ловить некоторые ошибки в программе еще на этапе компиляции. Например:
(неправильное использование)
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type
  Direction = (left, right, up, down);
  RPoint = record
    X, Y: integer;
  end;
  
{ Здесь могут быть еще описания типов }
 
const
  deltas: array[left .. down] of RPoint = (
    (X:-1; Y:0), (X:+1; Y:0), (X:0; Y:-1), (X:0; Y:+1)
  );
  currPos: RPoint = (X:10; Y:10);
var
  dir: Direction;
 
{ где-то в тексте программы }
  dir := left;
  Inc(currPos.X, deltas[dir].X);
  Inc(currPos.Y, deltas[dir].Y);
Почему неправильное? Потому что при внесении в программу дополнений тип Direction мог измениться, например, стать таким:
Pascal
1
2
3
4
5
type
  Direction = (
    left, right, up, down,
    leftup, leftdown, rightup, rightdown
  );
, но изменение типа Direction никак не заставляет программиста изменить и константу Deltas, хотя именно это было бы самым логичным. Если при измененном Direction значение Dir станет равно leftup (или любому другому добавленному значению), программа немедленно вылетит с ошибкой. А если не включен контроль индексов - то еще хуже, будет портить память, и результаты ее работы вообще станут невменяемыми.
(правильное решение)
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
type
  Direction = (left, right, up, down);
  RPoint = record
    X, Y: integer;
  end;
 
const
  { !!! Описание deltas изменилось !!! }
  deltas: array[Direction] of RPoint = (
    (X:-1; Y:0), (X:+1; Y:0), (X:0; Y:-1), (X:0; Y:+1)
  );
  currPos: RPoint = (X:10; Y:10);
Теперь при добавлении новых значений в тип Direction, программа не откомпилируется до тех пор, пока не будет изменена и константа deltas (точнее - пока она не будет содержать ровно столько элементов, сколько значений в типе Direction). Что сохранит программисту нервы при отладке программы.

Повторяю: Паскаль - это язык с очень мощной системой типов. Пользуйтесь этим. Не экономьте на введении новых типов в свою программу. Простое описание типа не увеличивает размер exe-файла программы, какого бы большого размера не был описываемый тип. Т.е., не экономьте подобным образом (описанием типа [1 .. 1], я имею в виду):
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{ Чуть выше я говорил, что не надо выключать $R }
{$R+}
Type
  arrType = Array[1 .. 1] of Integer;
  PArrType = ^arrType;
  { для реализации динамического массива,
    если кто не догадался }
 
var
  P: PArrType;
  i: integer;
 
begin
  { Если теперь сделать так: }
  GetMem(P, 1024 * SizeOf(Integer));
  for i := 1 to 1024 do
    P^[ i ] := i; {, то программа вылетит при i = 2 }
  FreeMem(P, 1024 * SizeOf(Integer));
end.
Почему программа вылетит? Да потому, что компилятору все равно, сколько памяти вы реально выделили под массив. Все, что он знает - это то, что переменная P указывает на массив, индексы которого изменяются от 1 до 1, то есть, на массив из одного элемента. При обращении по индексу, лежащему вне этого интервала возникает ошибка. Для того, чтобы программа заработала, надо отключить проверку индексов, при этом вы остаетесь без диагностики ошибок в других местах программы. Не будете же вы каждый раз когда дело касается чтения/записи в массив выключать контроль границ, а потом - сразу включать?
Решается это очень просто:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{$R+}
Type
  arrType = Array[1 .. MaxInt div SizeOf(Integer)] of Integer;
  PArrType = ^arrType;
 
var
  P: PArrType;
  i: integer;
 
begin
  GetMem(P, 1024 * SizeOf(Integer));
  for i := 1 to 1024 do
    P^[ i ] := i; { Все прекрасно работает ... }
  FreeMem(P, 1024 * SizeOf(Integer));
end.
, и контроль границ остался включенным.

Еще один пример, когда описание нового типа помогает справиться с задачей быстрее/проще, чем было без него. Всем хорошо известная задача: поменять в матрице вторую и четвертую строку. "Ну, чего тут сложного," - говорит новичок, и лихо пишет программу:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const
  A: array[1 .. 5, 1 .. 5] of integer = (
    (11, 12, 13, 14, 15),
    (21, 22, 23, 24, 25),
    (31, 32, 33, 34, 35),
    (41, 42, 43, 44, 45),
    (51, 52, 53, 54, 55)
  );
 
var
  i, j, T: integer;
begin
  for i := 1 to 5 do
  begin
    for j := 1 to 5 do write(A[i, j]:4);
    writeln;
  end;
  writeln;
 
  for j := 1 to 5 do
  begin
    T := A[2, j]; A[2, j] := A[4, j]; A[4, j] := T;
  end;
 
 
  for i := 1 to 5 do
  begin
    for j := 1 to 5 do write(A[i, j]:4);
    writeln;
  end;
  writeln;
end.
Все прекрасно, все работает. Только это же самое можно было сделать вот так:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
type
  TVector = array[1 .. 5] of Integer;
const
  A: array[1 .. 5] of TVector = (
    (11, 12, 13, 14, 15),
    (21, 22, 23, 24, 25),
    (31, 32, 33, 34, 35),
    (41, 42, 43, 44, 45),
    (51, 52, 53, 54, 55)
  );
 
var
  i, j: integer;
  T: TVector;
begin
  for i := 1 to 5 do
  begin
    for j := 1 to 5 do write(A[i, j]:4);
    writeln;
  end;
  writeln;
 
  { С массивами работаем, как с любым простым типом }
  T := A[2]; A[2] := A[4]; A[4] := T;
 
  for i := 1 to 5 do
  begin
    for j := 1 to 5 do write(A[i, j]:4);
    writeln;
  end;
  writeln;
end.
Не знаю, как вам, но мне второй способ нравится больше...

Ну, и еще кое-что. Я постоянно говорю об этом на форумах, но все время встречаю ошибки, связанные с нежеланием придерживаться этого простого совета: объявляйте переменную как можно ближе к тому месту, где она должна использоваться. Особенно это касается счетчиков цикла. Вот программа, иллюстрирующая ошибку:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var
  arr: array[1 .. 5] of integer;
  i: integer;
 
procedure print;
begin
  for i := 1 to 5 do write(arr[ i ]:3);
  writeln;
end;
 
begin
  for i := 1 to 5 do
  begin
    arr[ i ] := 10 * i;
    print;
  end;
end.
, и сидим, гадаем, почему программа не показывает процесс заполнения массива. Да потому, что переменная i описана глобально, изменяется внутри процедуры, и после первого же вызова процедуры ее значение превышает конечное для цикла... Причем, это никак не фиксируется компилятором. Никаким. Вот если попробовать изменить значение этой переменной внутри цикла, то современные компиляторы (Дельфи, FPC) забьют тревогу: нельзя модифицировать переменную цикла. А изменение глобальной переменной не приводит к ругани компилятора.

Вот так надо было писать программку:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
type
  arrType = array[1 .. 5] of integer;
 
{
  передаем массив как параметр, а не описываем его глобально !!!
}
procedure print(const arr: arrType);
var i: integer; { максимально близко к месту использования }
begin
  for i := 1 to 5 do write(arr[ i ]:3);
  writeln;
end;
 
var
  arr: arrType;
  i: integer; { это - для цикла заполнения массива }
 
begin
  for i := 1 to 5 do
  begin
    arr[ i ] := 10 * i;
    print(arr);
  end;
end.
, тогда программа работает, как ожидалось.
И еще одно уточнение, касающееся этой программы: заметили в 14-ой строке, что я не написал:
Pascal
1
2
var
  arr: array[1 .. 5] of integer;
?
Повторяю еще раз: Паскаль - это язык с очень мощной системой типов, и это накладывает свои требования: даже две переменных (казалось бы одинакового типа)
Pascal
1
2
3
var
  a: array[1 .. 5] of integer;
  b: array[1 .. 5] of integer;
на самом деле имеют совершенно разный тип, потому что описаны похожие, но разные с точки зрения компилятора конструкции. Чтобы тип был действительно один и тот же, надо описать его в разделе type, и потом использовать для обеих переменных. Вот тогда у компилятора претензий не будет.

Вернуться к обсуждению:
Как не надо писать программы
8
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.09.2014, 21:22
Готовые ответы и решения:

Как писать программы?
Подскажите как чайнику написать прогу

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

Как писать программы с неравенствами?
как вообще писать программы с неравенствами ??? решите эту ((a*x)/(x+b))>0 с чего начать:(

Литература: как писать программы в паскале
Пожалуйста,напишите список литературы где очень доходчиво написанно как писать программы в паскале

4
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.