Delphi.int.ru — Портал программистов

Вход Регистрация | Забыли пароль?

События

Сегодня:
Вопросы0    Ответы0    Мини-форумы0


Последние:
Вопрос10.11, 12:07 / #6676
Ответ02.08, 00:42 / #6619
Новости30 апреля 2012


Сейчас онлайн:
На сайте — 8
На IRC-канале — 2

Ссылки

Подпрограммы (часть 3)

Автор:
© Ерёмин А.А., 2008
Для любого программного пакета справедливо: как только пользователь полностью изучит все возможности пакета, появится новая версия с новыми функциями.
Номер урока:
21

Решение домашнего задания из урока №20

Домашнее задание, предложенное в прошлом уроке было следующим:

Составить подпрограммы:

  1. Для вычисления факториала указанного числа.
  2. Для преобразования текста, содержащего русские буквы, в верхний регистр.
  3. Для вычисления результата импликации двух логических выражений (A -> B).

Задача 1. Факториалом числа n называется произведение 1*2*3*...*n и обозначается факториал "n!". Факториал числа 0 равен 1. Вычислить факториал можно последовательным умножением чисел 1, 2, 3, ... в цикле. В данном случае вполне подойдёт цикл FOR.

function Factorial(n: Integer): Int64;
var i: Integer;
begin
  Result:=1;
  for i:=2 to n do
    Result:=Result*i;
end;

Обратите внимание, что для выходного значения функции объявлен тип данных Int64. Это сделано по той причине, что факториалы - достаточно большие числа. Проверьте, к примеру, чему равен факториал числа 20... "Обычными" типами данных здесь не обойтись.

Задача 2. В одном из предыдущих уроков вы уже научились работать со строками. Здесь и пригодятся эти умения. Вообще, функции для преобразования регистра текста уже существуют, и работают они гораздо быстрее, чем те же функции, написанные самим программистом (они специальным образом оптимизированы). Но в качестве упражнения решение этой задачи вполне подойдёт. Существуют разные способы выполнения требуемой операции. Например, один из них такой. Мы заранее перечисляем все буквы русского алфавита, причём отдельно указываем буквы в нижнем регистре, и отдельно - в верхнем, но делаем это таким образом, чтобы соответствующие буквы находились на одних и тех же местах. А далее мы просматриваем каждый символ текста и ищем его в списке букв нижнего регистра. Если нашли (т.е. текущий символ - русская буква нижнего регистра), то заменяем её на соответствующую букву верхнего регистра. Как определяем букву для замены? А по позиции - в какой позиции находится "нижняя" буква, в такой же находится и "верхняя". Реализация:

function RusToUpper(Str: String): String;
const
  LetL = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя';
  LetU = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ';
var i: Integer;
begin
  Result:=Str;
  for i:=1 to Length(Str) do
    if Pos(Str[i],LetL) > 0 then
      Result[i]:=LetU[Pos(Str[i],LetL)];
end;

Задача 3. Импликация (лат. implico - тесно связываю) - логическая операция, образующая сложное высказывание из двух высказываний посредством логической связки, соответствующей союзу "если ..., то ...". Импликация ложна лишь в случае истинности первого выражения и ложности второго и истинна во всех остальных случаях. Обозначается импликация стрелкой вправо (A -> B).
Как следует из определения, импликация A -> B будет ложна только в том случае, если A = True и B = False. Так и запишем:

function Implication(A,B: Boolean): Boolean;
begin
  Result:=not(A and not(B))
end;

Введение

Третий и завершающий урок по теме "подпрограммы". В предыдущих двух мы разобрались, что такое подпрограммы, зачем они нужны, а также научились создавать свои собственные подпрограммы и пользоваться ими. В этом уроке будет скорее не новый материал, а дополнение к уже имеющемуся.

Способы передачи параметров в подпрограммы

Существует два способа передачи параметров. До текущего момента мы использовали только один способ - передача по значению (англ. by value). Смысл этого способа в том, что мы передаём подпрограмме конкретное значение - число, текст, логическое значение и т.д. Подпрограмма каким-либо образом использует это значение. При этом, из внешней программы передавать эти параметры можно было как явным указанием значения (например, указав число прямо в коде программы), так и передавая переменную или константу - использовалось соответствующее значение переменной / константы.

Но такой способ не всегда удобен. Более того, в случае, если подпрограмма должна вычислить сразу несколько значений, этот способ не принесёт успеха. Именно поэтому существует другой способ передачи параметров - передача по ссылке (англ. by reference). Смысл этого способа в том, что мы передаём не конкретное значение, а ячейку памяти, т.е. переменную. В чём же отличие? А отличие в том, что подпрограмма уже может работать с этой переменной, т.е. не только получать её значение, но и это значение менять! Получается, что мы берём переменную из основной программы, "отдаём" её подпрограмме, та, в свою очередь, производит какие-то манипуляции с ней, и в результате наша переменная получает новое значение и мы можем далее её использовать. Несложно догадаться, что такой подход позволит подпрограмме отдавать сразу несколько значений (причём не обязательно одного типа).

Для передачи по значению никаких изменений в подпрограмму вносить не нужно - это способ передачи по умолчанию. А вот для передачи по ссылке нужно всего лишь в описании подпрограммы добавить слово var перед нужными параметрами.

procedure Proc(a: Integer); //Передача по значению
...
procedure Proc(var a: Integer); //Передача по ссылке

Как нетрудно догадаться, если в процедуре требуется передача по ссылке, соответствующий параметр непременно должен быть переменной. Фиксированного значения там быть не должно. Ошибиться здесь трудно - программа просто не скомпилируется, если вместо переменной будет конкретное значение.

Примерами функций с передачей по ссылке являются широкоизвестные Inc() и Dec(). Вспомните - ведь не нужно писать a:=Inc(a); - достаточно просто Inc(a).

Пример. Любое целое положительное число можно представить в виде n = x2 + y, где x, y - тоже целые положительные числа. Написать подпрограмму, которая для заданного числа находит наибольшее возможное значение x и соответствующее значение y. Например, для 29: x = 5, y = 4.

Определим, что от нас требуется. А требуется от нас подпрограмма, которая принимает на вход число и в результате выдаёт другие два числа. Функцией это сделать не получится, ведь функция может вернуть только одно значение. Выход - процедура с передачей по ссылке. У нас будет 3 параметра: исходное число и две "ячейки" для переменных, куда будут записаны полученные значения. Заголовок процедуры будет таким:

procedure GetXY(n: Word; var x, y: Word);

Тип данных Word выбран специально для того, чтобы отрицательные значения не могли быть переданы процедуре.

Теперь реализация самой функции. Нам нужно найти максимальное значение x. Самый простой способ сделать это - извлечь квадратный корень из числа и округлить его в меньшую сторону. Далее полученный x нужно возвести в квадрат и найти разницу между этим квадратом и исходным числом - вот и число y. Единственное, что нужно учесть - y должен быть положительным числом, а значит не может быть нулём. А нулём он будет в том случае, если квадратный корень из n извлечётся нацело. В этом случае просто уменьшаем x на единицу и пересчитываем y. Окончательный код процедуры:

procedure GetXY(n: Word; var x, y: Word);
begin
  x:=Trunc(Sqrt(n));
  y:=n-Sqr(x);
  if y = 0 then
  begin
    Dec(x);
    y:=n-Sqr(x);
  end;
end;

Проверка работы подпрограммы при нажатии на кнопку:

procedure TForm1.Button1Click(Sender: TObject);
var N,A,B: Word;
begin
  N:=StrToInt(Edit1.Text);
  GetXY(N,A,B);
  Caption:=IntToStr(N)+' = '+IntToStr(a)+'^2 + '+IntToStr(b);
end;

Как видите, передача по ссылке является достаточно удобным механизмом взаимодействия программы и её подпрограмм. Если бы мы захотели решить эту задачу с использованием функций, пришлось бы писать две отдельные функции - одна вычисляла бы x, а другая - y. Что уж говорить о том, что одни и те же вычисления делались бы 2 раза...

На один параметр больше...

Недавно на одном форуме заметил интересное сообщение. Совершенно случайно была обнаружена занятная вещь: если в коде вызова подпрограммы в скобках после указания все параметров добавить запятую, т.е. "намекнуть", что дальше должен быть ещё один параметр, компилятор безо всяких ошибок такую строку кода скушает. Если же сам параметр указать, при компиляции возникнет ошибка. Если добавить больше одной запятой - тоже будет ошибка. Т.е. в нашем примере можно написать:

GetXY(N,A,B,);

Это просто отступление от темы - забавная вещь.

Параметры-константы

Есть ещё одна модификация параметров подпрограммы. Можно любой из них сделать константой. Нужно это в случае, если вы хотите контроллировать свой код на предмет отсутствия команд для изменения значения входного параметра. Делается это добавлением слова const перед переменной в заголовке.

Например, мы хотим для нашей предыдущей задачи находить x и y не для числа n, а для n+1. Для этого добавим в тело подпрограммы соответствующую строку:

procedure GetXY(n: Word; var x, y: Word);
begin
  Inc(n);
  ...

Но теперь, если мы сделаем параметр n константой, компилятор выдаст ошибку на только что добавленной строке:

procedure GetXY(const n: Word; var x, y: Word);
begin
  Inc(n);
  ...
[DCC Error] E2064 Left side cannot be assigned to

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

Необязательные параметры

Часто подпрограммы имеют большое количество параметров, что подчёркивает их универсальность и обширность выполняемых действий. Однако во многих случаях одни и те же параметры имеют одинаковое значение, т.е. среди вариантов значений одного параметра есть наиболее популярный. В этом случае для упрощения вызова подпрограмм часть параметров делают необязательными. Необязательный параметр может быть передан подпрограмме, а может и быть опущен. Для того случая, когда он опущен, имеется его исходное значение, которое подпрограмма и будет использовать.

Например, процедура Inc() может увеличивать значение переменной не только на единицу, но и на произвольное число - у неё есть второй параметр, отвечающий за эту величину, но параметр этот необязательный. Таким образом, если второй параметр указан - функция прибавляет указанное число единиц, а если параметр отсутствует - прибавляет единицу, которая задана как значение этого параметра по умолчанию. Понять, какие параметры обязательные, а какие - нет, можно по всплывающей подсказке с параметрами функции, которая появляется после набора открывающей скобки в редакторе кода:

Список параметров процедуры Inc()

Необязательные параметры указываются в квадратных скобках.

Удобно, согласитесь? Сейчас мы научимся делать необязательные параметры и в своих подпрограммах.

Для начала стоит отметить, что необязательные параметры должны находиться среди всех параметров в конце. Понятно почему - ведь если необязательный параметр будет в середине, откуда компилятор узнает, присутствует здесь этот параметр или нет? Если бы были разные типы данных - понять это было бы возможно, но если одинаковые (например, все параметры - числа), то ошибка неизбежна и поэтому самым разумным выходом является расположение необязательных параметров в конце.
Теперь о том, как сделать параметры необязательными. А здесь всё крайне просто - если указать значение по умолчанию, то параметр и станет необязательным. Указывается значение самым обычным образом - после имени аргумента и типа данных ставится знак равенства "=" и далее значение.

Пример. Создадим функцию, вычисляющую десятичный логарифм заданного числа или логарифм по указанному основанию.

function Logarithm(Num: Real; Base: Real = 10): Real;
begin
  Result:=Ln(Num)/Ln(Base)
end;

В описанной функции параметр, отвечающий за основание логарифма, необязательный. Его исходное значение - 10. Если при вызове функции этот параметр будет опущен, основание будет 10, а если будет задан - будет вычислен логарифм по указанному основанию. Откуда появилась в формула в теле функции не спрашивайте, а лучше загляните в учебник математики :-)

Посмотрите количество параметров функции CreateProcess():

Параметры функции CreateProcess()

Согласитесь - каждый раз писать такое количество параметров просто невыносимо. В данном случае необязательные параметры вполне могут решить проблему. Но на самом деле, для этой функции написаны несколько "обёрток", т.е. функций, принимающий только самые необходимые параметры, а все остальные остаются одинаковыми.

Привязка подпрограмм к форме

Если подпрограммы простые и занимаются, к примеру, арифметическими вычислениями, они могут просто располагаться в коде и прекрасно себя чувствовать. Однако, если вы попытаетесь из подпрограммы обратиться, скажем, к форме, или к её компонентам, ничего не выйдет - подпрограмма ничего не знает о вашей форме. Для того, чтобы из подпрограммы работать с компонентами формы, нужно выполнить кое-какие действия - сделать подпрограмму методом формы. Подробнее о том, что такое метод и как создаются методы для объектов, мы рассмотрим позже, когда будем знакомиться с объектно-ориентированным программированием. Сейчас же моей целью является просто показать, как это делается, чтобы вы могли делать точно так же в своих программах.

Рассмотрим конкретный пример. Пусть у нас на форме есть 3 кнопки - Button1, Button2 и Button3. Нам требуется из разных мест программы то включать эти кнопки, то выключать (через свойство Enabled). Чтобы не копировать один и тот же код, лучше написать подпрограмму, которая будет делать всё необходимое. Итак, вот наша процедура:

procedure EnableButtons(Enabled: Boolean);
begin
  Button1.Enabled:=Enabled;
  Button2.Enabled:=Enabled;
  Button3.Enabled:=Enabled
end;

Всё бы ничего, но при компиляции получаем ошибку: [DCC Error] Unit1.pas(29): E2003 Undeclared identifier: 'Button1'. Процедура "не видит" кнопку Button1. А точнее, не видит она и остальные две - это первое из сообщений об ошибке.

Итак, чтобы "привязать" процедуру к форме, мы должны сделать следующее:

1) В заголовке процедуры перед названием должны добавить имя класса формы. Имя класса формы в Delphi автоматически формируется из буквы "T" и имени самой формы. Т.е. для формы Form1 имя класса TForm1. Имя вы можете увидеть в модуле в разделе var - там описана сама форма:

Класс формы Form1 - TForm1 (редактор кода)

Между именем класса формы и именем подпрограммы должна стоять точка. В результате заголовок процедуры станет таким:

procedure TForm1.EnableButtons(Enabled: Boolean);

2) Теперь нужно добавить заголовок метода в описание самой формы. Для этого нужно скопировать заголовок нашей процедуры в секцию private или public в раздел type, где описана наша форма. Единственное, что ещё нужно сделать - удалить название класса формы в скопированной строке. В результате получим:

Подпрограмма в описании класса формы

Выбор раздела - private или public в каждом случае следует определять отдельно. Всё, что описано в private, доступно только в рамках данной формы. А всё, что описано в public, доступно из других форм и модулей. К примеру, если в вашей программе две формы и из второй нужно запускать процедуру, заголовок следует скопировать в public.

На этом "привязка" процедуры к форме завершена. Теперь программа скомпилируется без ошибок. Осталось только выяснить, как запускать созданную подпрограмму. А здесь никаких сложностей нет - подпрограмма доступна как имя_формы.имя_подпрограммы. В нашем случае это Form1.EnableButtons. Однако, такая запись необходима только если вы вызываете подпрограмму откуда-то извне, например из другой формы. Если вызов происходит откуда-то из самой Form1, можно обращаться к процедуре просто по имени. Например, поместим на форму TCheckBox и в обработчике его события OnClick напишем:

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  EnableButtons(CheckBox1.Checked)
end;

Теперь, если флажок установлен, кнопки активны, а если снят - неактивны.

А если, например, есть Form2 и CheckBox2 на ней, то обработчик будет такой:

procedure TForm2.CheckBox2Click(Sender: TObject);
begin
  Form1.EnableButtons(CheckBox2.Checked)
end;

Заключение

В сегодняшнем уроке мы рассмотрели способы передачи параметров в подпрограммы, необязательные параметры, а также научились осуществлять взаимодействие между подпрограммами и компонентами формы. Теперь вам известно всё, чтобы правильно создавать свои подпрограммы. Домашнего задания в этот раз нет - экспериментируйте самостоятельно. В следующий раз мы перейдём к новой теме. Успехов!

Автор: Ерёмин А.А.

Статья добавлена: 4 июня 2008

Следующая статья: Обучающий курс. 22. Простые типы данных »

Рейтинг статьи: 5.00 Голосов: 11 Ваша оценка:

Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.


Статьи, похожие по тематике

 

Для вставки ссылки на данную статью на другом сайте используйте следующий HTML-код:

Ссылка для форумов (BBCode):

Быстрая вставка ссылки на статью в сообщениях на сайте:
{{a:121}} (буква a — латинская) — только адрес статьи (URL);
{{статья:121}} — полноценная HTML-ссылка на статью (текст ссылки — название статьи).

Поделитесь ссылкой в социальных сетях:


Комментарии читателей к данной статье

zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 19:05):

А создание "procedure TForm2.CheckBox2Click" в последнем примере, вообще доставило чувство ГЛУБОКОГО УДОВЛЕТВОРЕНИЯ!
zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 18:26):

{"Привязка подпрограмм к форме" работает при обращении программно из Form1:}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
CheckBox1: TCheckBox;
procedure CheckBox1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure EnableButtons(Enabled: Boolean);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.EnableButtons(Enabled: Boolean);
begin
Button1.Enabled:=Enabled;
Button2.Enabled:=Enabled;
Button3.Enabled:=Enabled
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
EnableButtons(CheckBox1.Checked)
end;
end.
zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 18:03):

{Пример с необязательными параметрами работает в такой комплектации:}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Num: Real;
implementation
{$R *.dfm}
function Logarithm(Num: Real; Base: Real = 10): Real;
begin
Result:=Ln(Num)/Ln(Base)
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Num:=StrToFloat(Edit1.Text);
Label1.Caption:='логарифм по указанному основанию = '+FloatToStr(Logarithm(Num));
end;
end.
zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 15:58):

Фрагмент: "Параметры-константы",- не понял совсем.
zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 15:53):

{Пример "передача по ссылке " Обучающий курс. 21. Подпрограммы (часть 3) работает:}
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }

end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
procedure GetXY(n: Word; var x, y: Word);
begin
x:=Trunc(Sqrt(n));
y:=n-Sqr(x);
if y = 0 then
begin
Dec(x);
y:=n-Sqr(x);
end;
end;
var N,A,B: Word;
begin
N:=StrToInt(Edit1.Text);
GetXY(N,A,B);
Label1.Caption:=IntToStr(N)+' = '+IntToStr(a)+'^2 + '+IntToStr(b);
end;

end.
zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 10:19):

Задача №3 заработала:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
Button1: TButton;
CheckBox3: TCheckBox;
procedure Button1Click(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
procedure CheckBox2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
A: Boolean; //"Пойдем на концерт! Я билет достал! (билет есть или врет)
B: Boolean; //"Ура! Я с тобой пойду! (пойдет на концерт или врет)
implementation
{$R *.dfm}
procedure TForm1.CheckBox1Click(Sender: TObject);

begin
A:= CheckBox1.Checked
end;

procedure TForm1.CheckBox2Click(Sender: TObject);

begin
B:= CheckBox2.Checked
end;

procedure TForm1.Button1Click(Sender: TObject);
function Implication(A,B: Boolean): Boolean;
begin
Result:=not(A and not(B))
end;
begin
CheckBox3.Checked := Implication(A,B); {импликация A -> B будет ложна
только в том случае, если A = True и B = False,
то есть: ты билеты уже достал, но она врет и не пойдет с тобой на концерт}
end;

end.
zvygin1964
Репутация: нет

zvygin1964 (2 декабря 2013, 10:18):

Задача №2 заработала при:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
function RusToUpper(Str: String): String;
const
LetL = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя';
LetU = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ';
var i: Integer;
begin
Result:=Str;
for i:=1 to Length(Str) do
if Pos(Str[i],LetL) > 0 then
Result[i]:=LetU[Pos(Str[i],LetL)];
end;
var
N1: string;
begin
N1:=Edit1.Text;
Label1.Caption:='заглавные и прописные кирилические символы написаны только как заглавные = '+RusToUpper(N1);
end;

end.
zvygin1964
Репутация: нет

zvygin1964 (1 декабря 2013, 22:27):

Первое задание заработало при:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
function Factorial(n: Integer): Int64;
var i: Integer;
begin
Result:=1;
for i:=2 to n do
Result:=Result*i;
end;
var n: Integer;
begin
n:=StrToInt(Edit1.Text);
Label1.Caption:='Факториал обозначается как "n!" = 1*2*3*...*n = '+IntToStr(Factorial(n));
end;

end.
antoca
Репутация: +1

antoca (9 августа 2010, 18:34):

Объедки и методы всякие это самое поганое в паскале да и не только. Для них нужно неаналитическое мышление.
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (25 ноября 2009, 15:49):

Чтобы использовать кавычку, нужно её написать дважды подряд. А вариант с указанием кода символа тоже, безусловно, применим.
Andrush
Репутация: нет

Andrush (25 ноября 2009, 01:17):

Сделал 2ое задание,затем решил переводить с английского на русский(qwerty = йцукен),но возникла трудность с буквой "э",ведь на английской раскладке это ковычка(').Значит функцию pos() здесь не применить.Из урока 18-Символ с некоторым кодом N записывают так: #N.На ум пришло
var S:Char;Str:string;
{...}
S:=#39;
pos(S,Str)//и т.д.
Объясните,пожалуйста,чего я не так понял?

Оставлять комментарии к статьям могут только зарегистрированные пользователи.