* C for Dummies * Aleph * 2000-08-21 * 008 *
-----[00]----------[Quote of Day]-----------------------------------------
Profanity: the universal programming language
-----[01]----------[Hot News]---------------------------------------------
1. Фрагменты документации по Borland C/C++
Несмотря на прошедшие 10 лет, многое осталось в силе со времен TC 2.0
В любом случае, эта документация окажется полезной при переходе к более
новым версиям.
DOS Part of Compiler
http://members.xoom.com/c4dummies/files/BC++DOSHelp502.zip (167,714)
http://members.xoom.com/c4dummies/files/BC++Tools502.zip (107,768)
The C/C++ Language Reference
http://members.xoom.com/c4dummies/files/BC++Help502.zip (933,595)
http://www.dore.ru/library/ccpp/c_func.zip (1,368,778)
или
http://members.xoom.com/c4dummies/files/BC++WinHelp45.zip (1,326,573)
C++ Preprocessor 16/32
http://members.xoom.com/c4dummies/files/cpp52.zip (159,018)
2. Andrew Koenig "C Traps and Pitfalls" (Eng)
AT&T Bell Laboratories, Murray Hill, New Jersey 07974
http://www.dore.ru/library/ccpp/ctraps.pdf (103,954)
или
http://members.xoom.com/c4dummies/files/ctraps.zip (85,853)
Какому-то умнику пришло в голову закатать это в PDF, но, по счастью,
английский текст все еще можно извлечь просто через COPY/PASTE
BTW: Счастливым обладателям полного пакета Adobe Acrobat (НЕ Acrobat
Reader), могу порекомендовать два плагина (Plug-In), независимой
фирмы для конвертирования PDF в HTML или TIFF/BMP.
Url: http://www.netsales.net/img/com/bcl/mag41d.exe (HTML)
size: 1330644
Url: http://www.netsales.net/img/com/bcl/free40d.exe (TIFF/BMP)
size: 1261349
Если возникнут проблемы с инсталляцией - пишите, это решается.
-----[02]----------[Blah-Blah-Blah]---------------------------------------
Взято здесь:
http://www.nagual.pp.ru/~ache/dijkstra.html
ПРОГРАММИСТСКИЕ БАСНИ
Несколько слов об авторе. Эдсгер Дейкстра (Edsger W. Dijkstra) - один из
тех людей, с именем которых связано превращение программирования из
шаманства в науку. Работы Э. Дейкстры уже сегодня можно назвать
классическими.
Одной из форм научной деятельности Дейкстры являются письма, которые он
время от времени посылает своим корреспондентам (а также нанимателям: живя
в Голландии в г. Эйндховене, он работал в фирме "Барроуз" ("Burroughs"),
находящейся в США), призывая распространять их дальше. Сборник, содержащий
некоторые из этих писем, был опубликован в 1982 г. Когда взгляды Э.
Дейкстры стали известны широкому кругу программистов, они вызвали сильную
(и далеко не всегда положительную) реакцию.
***
Как быть, если правда колет глаза?
Иногда мы обнаруживаем неприятные истины. И когда это происходит, попадаем
в затруднительное положение, поскольку утаить их - научная нечестность,
сказать же правду - значит вызвать огонь на себя. Если эти истины
достаточно неприемлемы, то ваши слушатели психологически неспособны
принять их и вы будете ославлены как абсолютно лишенный здравого смысла,
опасно революционный, глупый, коварный или какой-то еще там человек. (Не
говоря уже о том, что, настаивая на таких истинах, вы обеспечите себе
непопулярность во многих кругах и вообще не обойдетесь без персонального
риска. Вспомните Галилео Галилея...)
Информатика (computer science) выглядит тяжело больной от такого
противоречия. В целом она хранит молчание и стремится избежать конфликта,
переключая внимание на другое (например, в отношении Кобола вы можете либо
бороться с болезнью, либо делать вид, что ее не существует: многие
факультеты информатики выбирают второй, более простой путь). Но, собратья,
я спрашиваю вас: разве это честно ? Не подрывает ли наше затянувшееся
молчание единства информатики ? Прилично ли сохранять молчание ? Если нет,
то как об этом говорить ?
Чтобы подбросить вам идей, касающихся этой проблемы, перечислю некоторые
из таких истин. (Почти все знакомые мне ученые-программисты согласятся в
основном со всеми из них. Однако мы вынуждены позволить миру действовать
так, как будто мы их не знаем).
Программирование - одна из наиболее трудных отраслей прикладной
математики: слабым (poor) математикам лучше оставаться чистыми (pure)
математиками.
Научно-технические расчеты - простейшее применение вычислительной техники.
Средства, которые мы применяем, оказывают глубокое (и тонкое) влияние на
наши способы мышления и, следовательно, на нашу способность мыслить.
Fortran - "младенческое расстройство" с двадцатилетним стажем -
безнадежно неадекватен какому бы то ни было применению ЭВМ сегодня: он
слишком неуклюж, слишком опасен и слишком дорог, чтобы его применять.
PL/I - "роковая болезнь" - принадлежит скорее к области проблем, чем к
области решений.
Практически невозможно научить хорошо программировать студентов,
ориентированных первоначально на Basic: как потенциальные программисты
они умственно оболванены без надежды на исцеление.
Использование Cobol калечит ум. Его преподавание, следовательно, должно
рассматриваться как уголовное преступление.
APL - ошибка, доведенная до совершенства. Это язык будущего для
программистской техники прошлого: он открывает новую эру для любителей
кодирования.
Проблемы управления в целом и базами данных в частности чрезвычайно сложны
для людей, которые думают на смеси "ЕС-овского с нижегородским"
(буквальный перевод: в терминах фирмы IBM, смешанных с неряшливым
английским).
Об использовании языка: невозможно заточить карандаш тупым топором. Столь
же тщетно пытаться сделать это десятком тупых топоров.
Помимо математических способностей, жизненно важным качеством программиста
является исключительно хорошее владение родным языком.
Многие компании, которые поставили себя в зависимость от оборудования
фирмы IBM (и, поступив так, продали душу дьяволу), потерпят крах под весом
неуправляемой сложности своих систем обработки данных.
Ни научная дисциплина, ни крепкая профессия не могут быть основаны на
технических ошибках министерства обороны и производителей ЭВМ.
Использование антропоморфной терминологии в отношении вычислительных
систем - признак профессиональной незрелости.
Провозглашая себя работающими в области программного обеспечения
(software), слабые (soft) ученые делают себя еще более смешными (но не
менее опасными). Вопреки своему названию, software (буквально: мягкое
оборудование) требует [жесточайше] твердой научной дисциплины для своей
поддержки.
В старые добрые времена физики повторяли опыты друг друга, чтобы быть
уверенными в результатах. Сейчас они придерживаются Фортрана, перенимая
друг у друга программы с ошибками.
Проекты, предлагающие программирование на естественном языке, гибельны по
своей сути.
Разве не достаточен этот список, чтобы дать повод для беспокойства? Но
что мы собираемся делать? Вероятно, заняться повседневными делами...
Если предположение о том, что "вы предпочли бы, чтобы я не волновал вас
пустяками, посылая вам это", справедливо, то можете добавить его к списку
неприятных истин.
-----[03]----------[Topic]------------------------------------------------
Preprocessor. Memory Models.
-----[04]----------[Body]-------------------------------------------------
Preprocessor
------------
#pragma
-------
Это последняя, еще не рассмотренная нами директива препроцессора.
В Turbo C 2.0 ее использование очень ограничено, но современные
компиляторы обеспечивают гораздо больше возможностей.
Сначала, процитирую документацию.
> Директива pragma (ANSI Си 3.8.6)
> --------------------------------
>
> Турбо Си поддерживает директиву #pragma, которая (как и error), неясно
> определяется в стандарте ANSI. Ее целью является разрешить
> специализированные директивы по форме:
>
> #pragma <имя директивы>
>
> С помощью #pragma Турбо Си может определить любые директивы, которые
> ему требуются, без вмешательства других компиляторов, поддерживающих
> #pragma. Почему ? Потому что, по определению, если компилятор не
> опознал имя директивы, то он игнорирует директиву #pragma.
>
>
> #pragma inline
> --------------
>
> Турбо Си распознает три директивы #pragma. Первая:
>
> #pragma inline
>
> Эта директива эквивалентна опции компилятора -B. Она сообщает
> компилятору о том, что в программе присутствуют ассемблерные команды
> (см. главу 12). Наилучшее ее расположение - начало файла, т.к.
> компилятор самоперезапускается с опцией -B сразу, как только встретится
> #pragma inline. На самом деле, вы можете опустить и опцию -B, и
> директиву #pragma inline, т.к. компилятор все равно
> самоперезапускается, как только встретит asm операторы; целью этой
> опции и директивы является экономия времени компиляции.
>
>
> #pragma warn
> ------------
>
> Вторая #pragma директива - это #pragma warn
>
> Данная директива позволяет не принимать во внимание специальную опцию
> командной строки -wxxx (или спецификацию Display warnings...On).
>
> Например, если исходный текст программы содержит директивы:
>
> #pragma warn +xxx
> #pragma warn -yyy
> #pragma warn .zzz
>
> то xxx включит вывод пользователю предупреждений (если даже в подменю
> O/C/Errors/ она была выключена); yyy выключит вывод сообщений; а zzz
> восстановит первоначальное значение, которое было в начале компиляции
> файла.
>
> Полный список трехзначных аббревиатур и предупреждений, которые они
> включают и выключают, приведен в Приложении Справочного Руководства по
> Турбо Си.
>
>
> #pragma-директива saveregs
>
> Эта pragma-директива гарантирует что huge-функции не изменят значения
> любых регистров введенных до этого. Эта директива иногда нужна для
> организации интерфейса с языком ассемблера. Директива может быть
> размещена непосредственно перед определяемой функцией. Тогда она будет
> применена только к этой функции.
Замечу, что в документации к BC++ 5.02 описания этих директив повторены
слово в слово - за 10 лет ничего не изменилось. Но, зато, добавилось много
новых директив, с которыми я Вам рекомендую ознакомиться по BC++ Help 5.02
Memory Models
-------------
Как мы уже говорили, Turbo C использует шесть моделей памяти.
Цитирую документацию:
> Tiny (Крохотная)
> ----------------
>
> Как вы можете предположить, это самая маленькая из моделей памяти. Все
> четыре сегментных регистра (DS,CS,SS,ES) указывают на один и тот же
> адрес, поэтому вы имеете всего 64К для всех программ, данных и
> массивов. В этом случае используются только near-указатели.
> Используйте эту модель, когда у вас маленькая оперативная память.
> Программы с крохотной моделью памяти могут быть переведены в .COM
> формат.
>
> Small (Малая)
> -------------
>
> Программный сегмент и сегмент данных различны и не перекрываются,
> поэтому у вас есть 64К для программ и 64К для статических данных.
> Сегменты стека и дополнительные сегменты данных начинаются с того же
> адреса, что и сегмент данных. В этом случае используются только
> near-указатели. Это наилучшая модель для большинства реализаций.
>
> Medium (Средняя)
> ----------------
>
> Far-указатели используются для программ, но не для данных. В результате
> статические данные ограничены 64К, но программа может иметь величину до
> 1М. Эта модель является наилучшей для больших программ, которые не
> хранят в памяти больших объемов данных.
>
> Compact (Компактная)
> --------------------
>
> Прямо противоположна средней, т.е. far-указатели используются для
> данных, а не для программ. Программы ограничиваются величиной в 64К, а
> данные (но не статические) могут быть до 1Мб. Эта модель наиболее
> удобна, если ваша программа маленькая, но вам необходимо адресовать
> большие объемы данных.
>
> Large (Большая)
> ---------------
>
> Far-указатели используются как для программы, так и для данных. И
> программа, и данные занимают область до 1М; эта модель необходима
> только для очень больших программных продуктов.
>
> Huge (Огромная)
> ---------------
>
> Far-указатели используются для программы и для данных. Турбо Cи обычно
> ограничивает величину статических данных до 64К; огромная модель памяти
> снимает это ограничение, позволяя статическим данным занимать
> пространство более 64К.
Модели памяти - это то, как компилятор обращается с доступной ему памятью
компьютера и не имеют ничего общего ни с размером установленной у Вас
физической памяти, ни со способами доступа к ней.
Замечу, что компиляторы Microsoft для DOS и Win16 также используют эти же
самые модели памяти. (В Win32 используется Flat модель памяти).
Объяснение моделей памяти невозможно без понимания архитектуры процессора
x86, так что рекомендую к следующему выпуску освежить Ваши знания в этой
области.
-----[05]----------[Feedback]---------------------------------------------
Два вопроса от подписчика, предпочитающего английский (английский вариант
ответа ушел дайректом):
Q. Ya ochin' ploho ponimau pointers is koda *. Vot primer:
int word_len(const char* s)
{
const char* start = s;
while (*s != ' ' && *s != '\0')
{
s++;
}
return s - start;
}
A. Легко видеть (даже из названия), что перед нами функция для подсчета
длины слова, которое передается как параметр в виде указателя на
символьную строку s. Напомню, что в C имя массива одновременно является
и указателем на него.
Заметьте, что s объявлен указателем на константный массив типа char,
что не позволяет функции word_len() изменять значения элементов
массива. Эта простая предосторожность заметно повышает устойчивость
кода к ошибкам.
На что указывает указатель s ?
Предположим, мы имеем размещенную где-то в памяти по адресу SSSS:OOOO
текстовую строку "Test String".
+ <--- SSSS:OOOO (Start Here)
|
------------------------------------------------------
| T | e | s | t | ' ' | S | t | r | i | n | g | '\0' |
------------------------------------------------------
Где SSSS - Segment и OOOO - Offset.
Примем, для простоты, что строка s начинается с границы сегмента и
смещение равно нулю, то есть OOOO = 0000.
Тогда, первая буква нашей строки s "Test String", расположена в памяти
по адресу SSSS:0000, следующая - по адресу SSSS:0001 итд.
Segment Offset Letter
------- ------ ------
SSSS 0000 T
SSSS 0001 e
SSSS 0002 s
SSSS 0003 t
SSSS 0004 ' '
SSSS 0005 S
SSSS 0006 t
SSSS 0007 r
SSSS 0008 i
SSSS 0009 n
SSSS 000A g
SSSS 000B '\0'
Заметим, что абсолютное значение сегмента SSSS нас не интересует, так
как оно одинаково для всех символов строки.
Я явно обозначил символы ' ' (Space) и '\0' (NULL), так они
используются в программе. Символьная строка в C всегда заканчивается
завершающим нулем. Часто Вы можете встретить запись ASCIIZ (от Zero) -
ASCII строка, оканчивающаяся нулем.
Это соглашение привычно и понятно тем, кто перешел к C от Ассемблера,
но в корне отличается от принятого в Pascal и (частично) в Delphi, где
нет символа конца строки (EOS - End of String), а длина строки хранится
в явном виде, как префикс (LString: Length + String).
Разберем теперь работу функции word_len()
Для удобства, я перенумеровал строки.
1 int word_len(const char* s)
2 {
3 const char* start = s;
4
5 while (*s != ' ' && *s != '\0')
6 {
7 s++;
8 }
9
A return s - start;
B }
В нашем примере функция word_len получает указатель s = SSSS:0000
В строке 3 мы сохраняем это значение, присвоив его константному
указателю start. Константность означает, что этот указатель не может
быть изменен после того, как ему присвоено начальное значение.
start = SSSS:0000
Это хороший стиль, оберегающий от неприятностей.
В строке 5 начинается цикл с предусловием. Если условие истинно, цикл
выполняется, если нет - управление передается следующему оператору. Все
что находится между парой фигурных скобок {} (braces), рассматривается
как один составной оператор.
Предусловие (*s != ' ' && *s != '\0') является логической комбинацией
двух других логических условий (использован оператор логическое И -
конъюнкция):
*s != ' '
Оператор * (разыменование указателя) означает получение значения того
элемента, на который указывает указатель.
В нашем случае указатель s = SSSS:0000 и *s = 'T', то есть тому
элементу, на который указывает s.
Очевидно, 'T' != ' ' (символ T отличен от пробела) и это условие
истинно.
Также очевидно, истинно и второе условие: символ T отличен от нуля.
Таким образом, предусловие истинно и цикл выполняется.
Тело цикла содержит только один оператор: s++
В строке 7 значение указателя s инкрементируется (оператор ++).
Таким образом, значение указателя s теперь изменилось на s = SSSS:0001,
и разыменование указателя *s даст теперь символ по адресу SSSS:0001,
то есть 'e'.
Предусловие в строке 5 даст значение true и цикл выполнится еще раз.
Так будет продолжаться, пока на четвертом шаге s не получит значение
s = SSSS:0004, и разыменование указателя *s не даст нам символ ' '.
Предусловие в строке 5 окажется, наконец, ложным и управление будет
передано к строке A.
В строке A вычисляется и возвращается назад в вызывающую функцию
разность s - start.
Как мы помним, в start сохранено начальное значение указателя s:
start = SSSS:0000
s имеет теперь новое значение
s = SSSS:0004
Вычисляем разность
s - start = (SSSS:0004) - (SSSS:0000) = 4
Таким образом, мы вычислили длину слова Test.
Надо сказать, что хотя пример, очевидно, взят из учебника по C, на самом
деле это пример того как НЕ надо работать с указателями.
В самом начале я предупредил Вас и Вы мне поверили, что сегмент SSSS
всегда тот же и его значением можно не интересоваться.
Я Вас не обманул и в данном случае это действительно верно.
Но дело в том, что сам 20-битный адрес вовсе не обязательно будет
представлен именно в такой (нормализованной) форме. На самом деле, это
будет справедливо только для плоской (flat) модели памяти. В Turbo C этому
условию отвечает только (почти никогда не используемая) модель памяти
HUGE.
Поэтому правильно эта программа должна быть записана по другому, например,
так:
1 short word_len(const char* s)
2 {
3 short len = 0;
4
5 while (*s != ' ' && *s != '\0')
6 {
7 ++s;
8 ++len;
9 }
A
B return len;
C }
Дополнительная переменная len служит счетчиком цикла и инкрементируется на
каждом шаге (где это возможно, я предпочитаю префиксную а не постфиксную
форму оператора ++). Также, я заменил int на short (что, вообще говоря,
эквивалентно в TC 2.0), так как размера переменной типа short всегда будет
достаточно для хранения длины любого английского слова.
Кроме того, есть и еще одно усовершенствование, которое мне хотелось бы
сделать в программе - оно касается стиля. Подробнее я расскажу об этом
позднее, пока же только замечу, что оно называется Венгерской нотацией и
состоит в приписывании к идентификаторам префиксов, указывающих тип
переменной.
Существуют как ярые сторонники, так и фанатичные противники этой формы
записи. Я принадлежу к умеренным :-)
Итак, в новых обозначениях, функция будет выглядеть так:
1 short WordLen(const char* pszWord)
2 {
3 short iLen = 0;
4
5 if (!pszWord || !(*pszWord))
6 return 0;
7
8 while (*pszWord && *pszWord != ' ')
9 {
A ++pszWord;
B ++iLen;
C }
D
E return iLen;
F }
Обратите внимание на дополнительное условие в строке 5:
Если передан недопустимый (NULL) указатель или пустая строка,
то никакие вычисления не производятся, а сразу возвращается 0.
Скобки в выражении !(*pszWord) на самом деле необязательны, вспомните
таблицу предшествования и порядка связывания из выпуска 5:
> Precedence of Operators
>
> Priority Operator Order of evaluation
>
> 1 () [] . -> left to right
> 2 ! ~ - ++ -- & * (type) sizeof right to left
> 3 * / % left to right
> 4 + - left to right
> 5 << >> left to right
> 6 < <= > >= left to right
> 7 == != left to right
> 8 & left to right
> 9 ^ left to right
> 10 | left to right
> 11 && left to right
> 12 || left to right
> 13 ?: right to left
> 14 = += -= etc. right to left
> 15 , left to right
Синтаксический разбор будет произведен справа налево, так что указатель
сначала будет разыменован и только потом от него будет взято логическое
отрицание, но введение скобок делает это выражение ясным с первого
взгляда, без того, чтобы заставить Вас вспоминать или отыскивать
Precedence Table :-)
Последнее, что осталось сделать, поверить теорию практикой ...
/* ****************************************************************** **
@@ POINTER - A program for testing Operations with Pointers
** ****************************************************************** */
#include <stdio.h>
short WordLen(const char* pszWord)
{
short iLen = 0;
if (!pszWord || !(*pszWord))
return 0;
while (*pszWord && *pszWord != ' ')
{
++pszWord;
++iLen;
}
return iLen;
}
#pragma argused /* Not work in Turbo C 2.0 */
void main
(
int argc, /* argument's count */
char** argv /* array of arguments */
)
{
clrscr();
printf("\nLength of word: %s - %d chrs.\n",argv[1],WordLen(argv[1]));
}
/* ****************************************************************** **
@@ The End
** ****************************************************************** */
А вот результат работы (параметр "Test String" передан в командной строке):
> C:\TEST>pointer.exe Test String
>
> Length of word: Test - 4 chrs.
Помню, всех главнее королева -
Ходит взад-вперед и вправо-влево,
Ну а кони - только буквой "Г"
Вл. Высоцкий
"Честь шахматной короны"
Разбор этой (и еще нескольких классических задач на рекурсию) у меня в
планах, но отнюдь не ближайших выпусков.
Тем не менее, раз вопрос задан, сделаю некоторые пояснения.
Q. I have one more question:
"There is a square chess board 8 by 8. The program has to present the
path of the chess horse that stepped over each cell of the chess board.
Each step has to be visited just once. The starting point is up to the
programmer"
And my question is about the horse..if i make 2dim array 8 by 8 and put
the horse on square 0,0 how do i tell it to move 2 squares right and 1
down and so on.
A. Классическая задача об обходе шахматной доски ходом шахматного коня.
Превосходное рекурсивное решение (полный разбор) можно найти в книге
Н. Вирта "Алгоритмы + Структуры данных = Программы".
Со временем, мы до него доберемся :-)
Пока же я предпочел бы не столь изящное, но более простое итеративное
решение.
Итак, имеется шахматная доска 8x8.
Необходимо посетить все поля и точно по одному разу. Очевидно,
необходим учет посещенных полей. На первый взгляд, все что нам
требуется, это определить двумерный массив логических переменных
Visited размером 8*8, принимающих одно из двух значений - true или
false, так что мы всегда можем узнать, посещал ли шахматный конь данное
поле.
В C, к сожалению, в отличие от Fortran или C++, нет типа boolean.
Разумеется, всегда можно использовать битовый массив или символьный
тип.
Тогда, например, учет посещенных полей можно организовать так:
char cVisited[8][8]; /* Declare 2D array */
memset(cVisited,0,sizeof(cVisited)); /* Set to all to false */
cVisited[0][0] = 1; /* First step */
Может однако случиться, что для выбранного Вами алгоритма желательно
учитывать очередность посещений (например, для отката на шаг). В этом
случае, удобнее хранить в массиве не только информацию о том, что
данная клетка посещалась, но и номер посещения. Например, так:
const short NEVER_VISITED = -1;
short iVisited[8][8]; /* Declare 2D array */
memset(iVisited,NEVER_VISITED,sizeof(iVisited));
iVisited[0][0] = 0; /* First step */
Просмотр этого массива позволит установить поля, которые еще не
посещались и проверить их достижимость из данной клетки доски.
Чтобы не загромождать изложение деталями, в дальнейшем я придерживаюсь
нотации C++, используя тип bool и однострочный комментарий //.
Определяем константу
const short MAX_CELL = 63; // Count from Zero
В самом внешнем цикле требуется обойти все клетки, проверяя
для каждой возможность быть стартовым полем, с которого
можно обойти все остальные клетки доски.
for (short k = 0; k < MAX_CELL; ++k)
{
// Try next start cell
}
Шахматный конь имеет 8 степеней свободы (вариантов хода), хотя не все
из них могут быть реализованы в данной конкретной позиции.
const short HORSE_FREENESS = 8;
В каждой клетке доски мы последовательно пытаемся реализовать эти
возможные ходы.
for (short l = 0; l < HORSE_FREENESS; ++l)
{
// Try next Horse's Freeness
}
Необходима проверка, достижима ли из данной клетки доски
другая клетка, которую мы еще не посещали.
bool CanJumpNextCell(CurrentCell)
{
// This func. check, if one from unvisited
// cells can be reached from current cell
}
И, разумеется, для каждой клетки доски гам необходимо сохранять ее
статус.
struct HorseState
{
bool bVisited;
short iStepNumber;
short iFreeness;
};
typedef struct HorseState Status;
Status Board[8][8];
Сейчас, для каждой клетки доски мы знаем:
1. Посещалось ли это поле.
2. Если да, то на каком шаге.
3. Число попыток уже сделанных с этого поля.
Дальнейшее очевидно: мы пытаем продвигать шахматного коня на все новые
еще свободные поля.
Если в какой-то момент мы оказываемся на последнем поле (сделано 63
шага), решение найдено и хранится в массиве Board.
Если на каком-то шаге мы не можем перейти ни на одно свободное поле,
необходимо вернуться на шаг назад (backtracing) и повторить попытку.
Если мы уже откатились до стартовой клетки и исчерпали все попытки -
эта клетка не годится и мы должны пробовать следующую.
Если мы безуспешно перебрали все клетки - задача не имеет решения.
-----[06]----------[Info]-------------------------------------------------
Вопросы и замечания принимаются по адресу: aleph@canada.com
Предыдущие выпуски доступны со страницы архива:
http://www.subscribe.ru/archive/comp.prog.c4dummies/
или (в упакованном виде):
http://members.xoom.com/c4dummies/archive/000.zip
. . .
http://members.xoom.com/c4dummies/archive/007.zip
Рассылка дублируется (только текстовый вариант) с сервера www.egroups.com
Подписка: c4d-subscribe@egroups.com
-----[--]----------[The End]----------------------------------------------
© Gazlan 2009 * gazlan@yandex.ru
|