Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Язык Си Керниган, Ричи

Автор: S_Leha
Дата сообщения: 30.07.2003 21:06
Читаю книгу Язык C Кернигана, Ричи. Помогите пожалуйста разобраться.
-----------------------------------------------------------
…программы распреде-
ления памяти. Имеются две функции: функция ALLOC(N) возвра-
щает в качестве своего значения указатель P, который указы-
вает на первую из N последовательных символьных позиций, ко-
торые могут быть использованы вызывающей функцию ALLOC прог-
раммой для хранения символов; функция FREE(P) освобождает
приобретенную таким образом память, так что ее в дальнейшем
можно снова использовать. программа является "элементарной",
потому что обращения к FREE должны производиться в порядке,
обратном тому, в котором производились обращения к ALLOC.

Простейшая реализация состоит в том, чтобы функция раз-
давала отрезки большого символьного массива, которому мы
присвоили имя ALLOCBUF. Этот массив является собственностью
функций ALLOC и FREE. Так как они работают с указателями, а
не с индексами массива, никакой другой функции не нужно
знать имя этого массива. Он может быть описан как внешний
статический, т.е. Он будет локальным по отношению к исходно-
му файлу, содержащему ALLOC и FREE, и невидимым за его пре-
делами. При практической реализации этот массив может даже
не иметь имени; вместо этого он может быть получен в резуль-
тате запроса к операционной системе на указатель некоторого
неименованного блока памяти.

Другой необходимой информацией является то, какая часть
массива ALLOCBUF уже использована. Мы пользуемся указателем
первого свободного элемента, названным ALLOCP. Когда к функ-
ции ALLOC обращаются за выделением N символов, то она прове-
ряет, достаточно ли осталось для этого места в ALLOCBUF. Ес-
ли достаточно, то ALLOC возвращает текущее значение ALLOCP
(т.е. Начало свободного блока), затем увеличивает его на N,
с тем чтобы он указывал на следующую свободную область. Фун-
кция FREE(P) просто полагает ALLOCP равным P при условии,
что P указывает на позицию внутри ALLOCBUF.

Объясните чтобы было понятно
-----------------------------------------------------------

Вот сам код.

DEFINE NULL 0 /* POINTER VALUE FOR ERROR REPORT */
DEFINE ALLOCSIZE 1000 /* SIZE OF AVAILABLE SPACE */

STATIC CHAR ALLOCBUF[ALLOCSIZE];/* STORAGE FOR ALLOC */
STATIC CHAR *ALLOCP = ALLOCBUF; /* NEXT FREE POSITION */

CHAR *ALLOC(N) /* RETURN POINTER TO N CHARACTERS */
INT N;
{
IF (ALLOCP + N <= ALLOCBUF + ALLOCSIZE)
{
ALLOCP += N;
RETURN(ALLOCP - N); /* OLD P */
}
ELSE /* NOT ENOUGH ROOM */
RETURN(NULL);
}
FREE(P) /* FREE STORAGE POINTED BY P */
CHAR *P;
{
IF (P >= ALLOCBUF && P < ALLOCBUF + ALLOCSIZE)
ALLOCP = P;
}
Автор: EAS
Дата сообщения: 31.07.2003 05:59
Странный код прямо скажем. Помоему у тебя K&R в очень поганой версии. Может так тебе понятней станет:

#define NULL 0 /* POINTER VALUE FOR ERROR REPORT */
#define ALLOCSIZE 1000 /* SIZE OF AVAILABLE SPACE */

static char ALLOCBUF[ALLOCSIZE];/* STORAGE FOR ALLOC */
static char *ALLOCP = ALLOCBUF; /* NEXT FREE POSITION */

char* ALLOC(int N) /* RETURN POINTER TO N CHARACTERS */
{
if(ALLOCP + N <= ALLOCBUF + ALLOCSIZE)
{
ALLOCP += N;
return (ALLOCP - N); /* OLD P */
}
else /* NOT ENOUGH ROOM */
{
return NULL;
}
}

void FREE(char *P) /* FREE STORAGE POINTED BY P */
{
if(P >= ALLOCBUF && P < ALLOCBUF + ALLOCSIZE)
{
ALLOCP = P;
}
}

Чуть-чуть ближе к жизни привел . Все равно кривизна, конечно.
IMHO тебе надо нормальное издание взять.

ЗЫ: Или тебе что-то конкретно, по принципу работы не понятно?
Автор: S_Leha
Дата сообщения: 31.07.2003 12:47

Цитата:
Или тебе что-то конкретно, по принципу работы не понятно?

Мне не понятен смысл функции ALLOC
---------------------------------------------------------------------------------------------------------
#define NULL 0
#define ALLOCSIZE 1000

static char ALLOCBUF[ALLOCSIZE]; /* Правильно я понимаю, что в этот массив нужно забить символы? */

static char *ALLOCP = ALLOCBUF;

char* ALLOC(int N) /* Почему имя функции определенно как указатель? */
{
if(ALLOCP + N <= ALLOCBUF + ALLOCSIZE) /* Сравнение чего здесь происходит? */
{
ALLOCP += N;
return (ALLOCP - N);
}
else
{
return NULL;
}
}

void FREE(char *P) /* С чем работает эта функция? */
{
if(P >= ALLOCBUF && P < ALLOCBUF + ALLOCSIZE) /* Опять же, что здесь сравнивается?*/
{
ALLOCP = P;
}
}

Автор: FireBrizz
Дата сообщения: 31.07.2003 13:25
S_Leha

Цитата:
Правильно я понимаю, что в этот массив нужно забить символы?

неа, char - это тип данных, в ДОС размер 1 байт (просто так удобно задавать массивы - типа 1000 байт)

Цитата:
Почему имя функции определенно как указатель?

потомучто она возврашает указатель (ну или адрес первого из выделенных N байтов)

Цитата:
Сравнение чего здесь происходит?

Определяется достаточно ли в буфере места под еще N байт

Цитата:
С чем работает эта функция?

С указателем на область которую пользователь возвращает буфферу

Цитата:
Опять же, что здесь сравнивается?

проверяется лежит ли начало данной области в буффере

Ну а функция - выделяет N байт в своем буфере (ну нету в C оператора new - чтобы работать с массивом переменной длины к примеру)
Автор: S Leha
Дата сообщения: 31.07.2003 20:10
Вот теперь я все понял! Спасибо.

Добавлено
У меня есть еще несколько вопросов, с которыми я не могу разобраться.

1. "При достижении конца файла функция getchar() возвращает значение EOF" - что за файл?
2. Чем double отличается от float ?
3. "if( c >= '0' && c <= '9' ) определяет, является ли символ в С цифрой, и если это так, то численное значение этой цыфры определяется по формуле С - '0' " - разъясните пожалуйста, что за формула?


Цитата:
тебе надо нормальное издание взять.

Книгу только в магазине можно купить или она есть в Интернете?
Автор: EAS
Дата сообщения: 01.08.2003 03:31
S Leha
Извини конечно, но IMHО тебе надо либо СРОЧНО книжку менять, либо читать ее сначала (про синтаксис и т.п.).

Цитата:
"При достижении конца файла функция getchar() возвращает значение EOF" - что за файл?

getchar() возвращает EOF при ошибке чтения из stdin

Цитата:
Чем double отличается от float

double -- 8 байт (1.7E+/-308, 15 значащих цифр); float -- 4 байта (3.4E+/-38, ~7 зн.цифр)

Цитата:
if( c >= '0' && c <= '9' ) определяет, является ли символ в С цифрой

Угу

Цитата:
по формуле С - '0'

Символы цифр имеют ASCII-коды с 0x30 (0) по 0x39 (9). Написать '0' или 0x30 или 48 -- одно и тоже. Например, если char C = '8' (== 0x38) получаем в символах: '8' - '0' == 8; в числах: 0x38 - 0x30 == 0x08

Цитата:
Книгу только в магазине можно купить или она есть в Интернете?

Есть в магазине, есть в инете (напр. h**p://www.rusdoc.ru, h**p://www.citforum.ru и т.д.), здесь можешь спросить http://forum.ru-board.com/topic.cgi?forum=35&bm=1&topic=15098#1
Автор: S Leha
Дата сообщения: 01.08.2003 07:23

Цитата:
...читать ее сначала

Уже начал.

Цитата:
getchar() возвращает EOF при ошибке чтения из stdin

Да, но она также возвращает EOF при достижении конца файла ввода. Как достич этого конца?
Автор: f_serg
Дата сообщения: 01.08.2003 08:51
S Leha

Цитата:
Как достич этого конца?

Где? В Досе Ctrl-Z, в *nix-е Ctrl-D.
Автор: S Leha
Дата сообщения: 01.08.2003 19:41
Подскажите, почему я не могу работать с функциями графики?
При попытки запуска вот что:

BGI ERROR: GRAPHICS NOT INITIALIZED (USE 'INITGRAPH')
Думаю, что нужно как то это инициализировать.

Работаю в Turbo C 2.01
Автор: rew
Дата сообщения: 01.08.2003 20:06
читай хелп к initgraph
Автор: S Leha
Дата сообщения: 02.08.2003 16:14
Вопросик:
Как описать внешнюю переменную в функции неявным описанием по контексту?
Автор: mymuss
Дата сообщения: 02.08.2003 18:11
EAS

Цитата:
char - это тип данных, в ДОС размер 1 байт

Я бы даже сказал: везде гарантировано 1 байт

Цитата:
double -- 8 байт (1.7E+/-308, 15 значащих цифр); float -- 4 байта (3.4E+/-38, ~7 зн.цифр)

Не факт.

S Leha

Цитата:
Как описать внешнюю переменную в функции неявным описанием по контексту?

Не понимаю: что такое "внешняя переменная" и что такое "описание по контексту".
Если тебе нужно описать переменную которая определена где-то в другом файле - используй модификатор extern. Если тебе нужно получить доступ к переменной, которая не находится в области видимости данной функции (т.е. не глобальная, не определенная в данной функции) то тебе остается лишь передавать ее как параметр.
Автор: S Leha
Дата сообщения: 03.08.2003 12:11

Цитата:
Не понимаю: что такое "внешняя переменная" и что такое "описание по контексту".

Внешняя, думаю глобальная, а "описание по контексту" - сам не понял.

Вот текст из K&R:
Внешняя переменная должна быть определена вне всех функ-
ций; при этом ей выделяется фактическое место в памяти. Та-
кая переменная должна быть также описана в каждой функции,
которая собирается ее использовать; это можно сделать либо
явным описанием EXTERN, либо неявным по контексту.

Автор: mymuss
Дата сообщения: 03.08.2003 22:49
S Leha
Мда, у тебя действительно ОЧЕНЬ плохая версия КР. Срочно найди другую.

Вот как это место выглядит в оригинале:

Цитата:
An external variable must be defined, exactly once, outside of any function; this sets aside
storage for it. The variable must also be declared in each function that wants to access it; this
states the type of the variable. The declaration may be an explicit extern statement or may be implicit from context.

("The C Programming Language. Second Edition" Prentice Hall).

А через 2 абзаца объясняется как обойтись без extern:

Цитата:
In certain circumstances, the extern declaration can be omitted. If the definition of the
external variable occurs in the source file before its use in a particular function, then there is
no need for an extern declaration in the function.
Автор: BugFixer
Дата сообщения: 04.08.2003 09:05
S_Leha

Цитата:
if(ALLOCP + N <= ALLOCBUF + ALLOCSIZE) /* Сравнение чего здесь происходит? */
......
void FREE(char *P) /* С чем работает эта функция? */
............
if(P >= ALLOCBUF && P < ALLOCBUF + ALLOCSIZE) /* Опять же, что здесь сравнивается?*/

Основная проблема (с моей точки зрения): товариСЧ не понимает сути указателей и арифметики, с ними связаной.

А книжка действительно старая, там даже примеры на "оригинальном" C&R С (я на нём последний раз писал хоть что-нибудь году эдак в 87, однако!)
Автор: S Leha
Дата сообщения: 04.08.2003 21:09

Цитата:
Основная проблема (с моей точки зрения): товариСЧ не понимает сути указателей и арифметики, с ними связаной.

Да нет теперь я въехал. Я просто думал, что эти функции должны работать c символами, а не с памятью. А про A = &s[0]; *(A + 1), A - I - тоже пока все понимаю.

Добавлено
С помощью этой тему передо мной открылось много нюансов языка. Теперь могу двигаться дальше и спокойно выполнять упражнения.
Книгу(электронную) я пытался найти, но ничего не вышло, вот попробую счаЗ поискать.
Автор: BugFixer
Дата сообщения: 05.08.2003 15:12
S Leha

Цитата:
Я просто думал, что эти функции должны работать c символами, а не с памятью.

А куда же эти символы засовывать, как не в память?
Автор: BugFixer
Дата сообщения: 06.08.2003 04:35
S Leha

Цитата:
A = &s[0];

Видимо, описано это так:
char *A;
char s[N];
тогда выражение A = &s[0]; абсолютно эквивалентно выражению A = s;

И вообще, байтовые массивы можно смело рассматривать как указатель на память, в которой это лежит
Автор: mymuss
Дата сообщения: 06.08.2003 06:14
S Leha

Цитата:
Книгу(электронную) я пытался найти, но ничего не вышло

Спросил бы у меня что-ли...
Смотри в ПМ
Автор: S Leha
Дата сообщения: 06.08.2003 20:43

Цитата:
Смотри в ПМ

А ПМ это где?


Добавлено
Объясните мне вот эти упражнения. Мне не понятно само задание.

Упражнение 1-19
---------------
Напишите программу DETAB, которая заменяет табуляции во
вводе на нужное число пробелов так, чтобы промежуток дости-
гал следующей табуляционной остановки. Предположите фиксиро-
ванный набор табуляционных остановок, например, через каждые
N позиций.

Упражнение 1-20
----------------
Напишите программу ENTAB, которая заменяет строки пробе-
лов минимальным числом табуляций и пробелов, достигая при
этом тех же самых промежутков. Используйте те же табуляцион-
ные остановки, как и в DETAB.

Упражнение 1-21
----------------
Напишите программу для "сгибания" длинных вводимых строк
после последнего отличного от пробела символа, стоящего до
столбца N ввода, где N - параметр. убедитесь, что ваша прог-
рамма делает что-то разумное с очень длинными строками и в
случае, когда перед указанным столбцом нет ни табуляций, ни
пробелов.
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------

А эти понятны, но не имею представления, как их выполнить. Намекните на нужные действия, но только намекните.

Упражнение 1-22
----------------
Напишите программу удаления из "C"-программы всех ком-
ментариев. Не забывайте аккуратно обращаться с "закавыченны-
ми" строками и символьными константами.

Упражнение 1-23
----------------
Напишите программу проверки "C"-программы на элементар-
ные синтаксические ошибки, такие как несоответствие круглых,
квадратных и фигурных скобок. Не забудьте о кавычках, как
одиночных, так и двойных, и о комментариях. (Эта программа
весьма сложна, если вы будете писать ее для самого общего
случая).
Автор: woffer
Дата сообщения: 06.08.2003 21:59
1-22
>работа с текстом

1-23
>1-22
>работа со стеком

S Leha ты просил намекнуть, боюсь лишнее писать
Автор: mymuss
Дата сообщения: 07.08.2003 04:00

Цитата:
А ПМ это где?

Вверху ссылка "Личный ящик"

PS: Кстати, у меня когда-то тоже возник этот вопрос Почему именно ПМ, а не ЛЯ? Private Messanging что ли...


Цитата:
Объясните мне вот эти упражнения. Мне не понятно само задание

1) Табуляция
Когда нажимаешь на клаве "TAB", оно отправляет специальный символ, который в функциях типа printf итд можно указывать при помощи \t
Исторически сложилось, что этот символ часто соответствует отступу на 8 символов (особенно в разных текстовых редакторах)
НО: тут подразумевают, что \t не всегда именно 8 символов, но всегда "выравнивает" текст по столбцу с номером кратным 8. Блин, хреновый из меня объяснятель
Короче пример: "123456789\t0" будет выглядеть так: "123456789 0" (пробелов 7, а не 8, потому что иначе было бы 9 цифр + 8 пробелов = 17 символов, не кратно 8)

2) "Сгибание"
Наверное, имелось ввиду wordwrap. Т.е. надо сделать переносы по словам (как в ворде).
Автор: S Leha
Дата сообщения: 09.08.2003 21:32
Все таки не могу я понять, что нужно сделать (DETAB). Объясните.
Автор: woffer
Дата сообщения: 09.08.2003 23:18
S Leha
Насколько я правильно понял (имхо криво написано ), нужно следущее

если ты вводишь "\t1234\t5",
должно получиться следущее: [8 пробелов]1234[4 пробела]5
то есть все '\t' должны оканчиваться на границе, кратной N (обычно 8, но не обязательно)
первый \t полный, ибо 8 кратно N;
второй - нет, потомучто 8+4+8=20 не кратно N, следовательно, отрезаем от него 4 пробела.
Автор: S_Leha
Дата сообщения: 19.08.2003 20:41
Перенос строк, Detab, Entab я сделал.
А вот эти не могу.

Упражнение 1.23. Напишите программу, убирающую все комментарии из любой Си- программы. Не забудьте должным образом обработать строки символов и строковые константы. Комментарии в Си не могут быть вложены друг в друга.

Упражнение 1.24. Напишите программу, проверяющую Си-программы на элементарные синтаксические ошибки вроде несбалансированности скобок всех видов. Не забудьте о кавычках (одиночных и двойных), эскейп-последовательностях (\...) и комментариях. (Это сложная программа, если писать ее для общего случая.)

Разве можно программой редактировать исходный текст?
Автор: BugFixer
Дата сообщения: 20.08.2003 05:40
S_Leha

Цитата:
Упражнение 1.23. Напишите программу, убирающую все комментарии из любой Си- программы. Не забудьте должным образом обработать строки символов и строковые константы. Комментарии в Си не могут быть вложены друг в друга.

1. Открываешь на чтение внешний файл, который будет правиться. Назовём его "вход".
2. Открываешь на запись ещё один внешний файл, в который будет писать исправленое. Назовём его "выход". (В принципе, это может быть один и тот же файл, но для начала сделай разные.)
3. Начинаешь читать "вход" байт за байтом, отыскивая комментарии. Пока не комментарий, прочитаный байт пишешь в "выход". Прочитал - проверил - записал.
3.1. Нашли комментарий типа "//" - перестаём писать то, что до конца строки. Т.е. вычитываем по прежнему, но ничего не пишем. При этом нам глубоко по барабану, какие символы там встретились, если это не конец строки. Нашли конец строки - записали его в "выход". Режим поиска изменили на поиск комментария. Опять же, не комментарий - прочитаный байт пишешь в "выход".
3.2. Нашли комментарий типа "/*" Всё то же самое, но ищем не конец строки, а последовательность "*/" - "закрывающую скобку" При этом радостно пропускаем комментарии типа "//"и " /*" - они нас ничуть не интересуют!
3.3. Единственное исключение во всём этом - неожиданный конец файла "вход" (комментарий не закрыт - надо ругнуться!)
4. Добрели до конца файла "вход". Закрываем оба файла. Победа!
5. Открой файл "выход" и тщательно проверь.


Цитата:
Упражнение 1.24. Напишите программу, проверяющую Си-программы на элементарные синтаксические ошибки вроде несбалансированности скобок всех видов. Не забудьте о кавычках (одиночных и двойных), эскейп-последовательностях (\...) и комментариях. (Это сложная программа, если писать ее для общего случая.)

По сути то же самое, что и комментарии "/*" и "*/". Только скобки бывают разные (сбалансированность надо проверять раздельно для каждого вида скобок и более тщательно расписывать, что у нас есть скобка )
Автор: albatros
Дата сообщения: 20.08.2003 13:09
S_Leha
У меня есть "The C Programming Language", 2nd edition, Kernighan and Ritchie Answers to Exercises, там есть решения для всех упражнений. Если надо, могу скинуть тебе на мыло, сабж маленький. Но лучше пользуйся им только когда сам все перепробовал и не получается все равно, а то пользы будет мало. Кроме того, одну и ту же задачу можно решить по разному: они решили так, ты можешь решить по другому.
Автор: S_Leha
Дата сообщения: 20.08.2003 19:03
BugFixer
Принцип я понял(за что спасибо), а вот

Цитата:
1. Открываешь на чтение внешний файл, который будет правиться. Назовём его "вход".
2. Открываешь на запись ещё один внешний файл, в который будет писать исправленое. Назовём его "выход".

нет. Во всем том, что я прочел до этих заданий не было объяснений о работе с 2мя файлами.

albatros
Если пришлешь, буду благодарен.
Загляни в Личный ящик.



Автор: albatros
Дата сообщения: 20.08.2003 19:12
S_Leha

Цитата:
albatros
Если пришлешь, буду благодарен.
Загляни в Личный ящик.

Послал на указанный адрес.

Добавлено
Кстати, в топике, где ты спрашивал о BCC 5.5 написано кам им пользоваться и как настроить http://forum.ru-board.com/topic.cgi?forum=33&bm=1&topic=1861#1
Автор: BugFixer
Дата сообщения: 21.08.2003 05:51
S_Leha

Цитата:
Принцип я понял(за что спасибо)

Замечательно!


Цитата:
нет. Во всем том, что я прочел до этих заданий не было объяснений о работе с 2мя файлами.

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

А чем тебя так пугает работа с файлами?

Ну и ладно! Давай представим, что это просто char b[2048], в который каким-то неинтересным в данный момент способом некто написал текст програмы, которую надо исправить И - вперёд!

Страницы: 123

Предыдущая тема: Delphi Console ShellExecuteEX


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.