46170 (588390), страница 11

Файл №588390 46170 (Язык С) 11 страница46170 (588390) страница 112016-07-29СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 11)

\)

#DEFINE MAXLEN 1000

116

READLINES(LINEPTR, MAXLINES) /* READ INPUT LINES */ CHAR LINEPTR[]; / FOR SORTING */ INT MAXLINES;

\( INT LEN, NLINES;

CHAR *P, *ALLOC(), LINE[MAXLEN];

NLINES = 0;

WHILE ((LEN = GETLINE(LINE, MAXLEN)) > 0) IF (NLINES >= MAXLINES) RETURN(-1);

ELSE IF ((P = ALLOC(LEN)) == NULL) RETURN (-1);

ELSE \( LINE[LEN-1] = '\0'; /* ZAP NEWLINE */ STRCPY(P,LINE);

LINEPTR[NLINES++] = P;

\) RETURN(NLINES);

\)

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

WRITELINES(LINEPTR, NLINES) /* WRITE OUTPUT LINES */ CHAR *LINEPTR[];

INT NLINES;

\( INT I;

FOR (I = 0; I < NLINES; I++) PRINTF(“%S\N”, LINEPTR[I]);

\)

Существенно новым в этой программе является описание CHAR *LINEPTR[LINES];

которое сообщает, что LINEPTR является массивом из LINES элементов, каждый из которых - указатель на переменные типа CHAR. Это означает, что LINEPTR[I] - указатель на символы, а *LINEPTR[I] извлекает символ.

Так как сам LINEPTR является массивом, который передается функции WRITELINES, с ним можно обращаться как с указателем точно таким же образом, как в наших более ранних приме

рах. Тогда последнюю функцию можно переписать в виде: WRITELINES(LINEPTR, NLINES) /* WRITE OUTPUT LINES */ CHAR *LINEPTR[];

INT NLINES;

\( INT I;

WHILE (--NLINES >= 0) PRINTF(“%S\N”, *LINEPTR++);

\)

здесь *LINEPTR сначала указывает на первую строку; каждое увеличение передвигает указатель на следующую строку, в то время как NLINES убывает до нуля.

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

SORT(V, N) /* SORT STRINGS V[0] ... V[N-1] */

CHAR V[]; / INTO INCREASING ORDER */ INT N;

\( INT GAP, I, J;

CHAR *TEMP;

FOR (GAP = N/2; GAP > 0; GAP /= 2) FOR (I = GAP; I = 0; J -= GAP) \( IF (STRCMP(V[J], V[J+GAP]) <= 0) BREAK;

TEMP = V[J];

V[J] = V[J+GAP];

V[J+GAP] = TEMP;

\)

\)

Так как каждый отдельный элемент массива V (имя формального параметра, соответствующего LINEPTR) является указателем на символы, то и TEMP должен быть указателем на символы, чтобы их было можно копировать друг в друга.

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

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

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

В главе 1 мы отмечали, что поскольку в циклах WHILE и FOR проверка осуществляется до того, как тело цикла выполнится хотя бы один раз, эти циклы оказываются удобными для обеспечения правильной работы программы при граничных значениях, в частности, когда ввода вообще нет. Очень полезно просмотреть все функции программы сортировки, разбираясь, что происходит, если вводимый текст отсутствует.

Упражнение 5-5.

Перепишите функцию READLINES таким образом, чтобы она помещала строки в массив, предоставляемый функцией MAIN, а не в память, управляемую обращениями к функции ALLOC. Насколько быстрее стала программа?

5.9. Инициализация массивов указателей.

Рассмотрим задачу написания функции MONTH_NAME(N), которая возвращает указатель на символьную строку, содержащую имя N-го месяца. Это идеальная задача для применения внутреннего статического массива. Функция MONTH_NAME содержит локальный массив символьных строк и при обращении к ней возвращает указатель нужной строки. Тема настоящего раздела как инициализировать этот массив имен.

CHAR MONTH_NAME(N) / RETURN NAME OF N-TH MONTH */ INT N;

\( STATIC CHAR *NAME[] = \( “ILLEGAL MONTH”, “JANUARY”, “FEBRUARY”, “MARCH”, “APRIL”, “MAY”, “JUN”, “JULY”, “AUGUST”, “SEPTEMBER”, “OCTOBER”, “NOVEMBER”, “DECEMBER”

\);

RETURN ((N 12) ? NAME[0] : NAME[N]);

\)

Описание массива указателей на символы NAME точно такое же, как аналогичное описание LINEPTR в примере с сортировкой.

Инициализатором является просто список символьных строк;

каждая строка присваивается соответствующей позиции в массиве. Более точно, символы I-ой строки помещаются в какое-то иное место, а ее указатель хранится в NAME[I]. Поскольку размер массива NAME не указан, компилятор сам подсчитывает количество инициализаторов и соответственно устанавливает правильное число.

5.10. Указатели и многомерные массивы Начинающие изучать язык “с” иногда становятся в тупик перед вопросом о различии между двумерным массивом и массивом указателей, таким как NAME в приведенном выше примере.

Если имеются описания

INT A[10][10];

INT *B[10];

то A и B можно использовать сходным образом в том смысле, что как A[5][5], так и B[5][5] являются законными ссылками на отдельное число типа INT. Но A - настоящий массив: под него отводится 100 ячеек памяти и для нахождения любого указанного элемента проводятся обычные вычисления с прямоугольными индексами. Для B, однако, описание выделяет только 10 указателей; каждый указатель должен быть установлен так, чтобы он указывал на массив целых. если предположить, что каждый из них указывает на массив из 10 элементов, то тогда где-то будет отведено 100 ячеек памяти плюс еще десять ячеек для указателей. Таким образом, массив указателей использует несколько больший объем памяти и может требовать наличие явного шага инициализации. Но при этом возникают два преимущества: доступ к элементу осуществляется косвенно через указатель, а не посредством умножения и сложения, и строки массива могут иметь различные длины. Это означает, что каждый элемент B не должен обязательно указывать на вектор из 10 элементов; некоторые могут указывать на вектор из двух элементов, другие - из двадцати, а третьи могут вообще ни на что не указывать.

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

Упражнение 5-6.

Перепишите функции DAY_OF_YEAR и MONTH_DAY, используя вместо индексации указатели.

120

5.11. Командная строка аргументов

Системные средства, на которые опирается реализация языка “с”, позволяют передавать командную строку аргументов или параметров начинающей выполняться программе. Когда функция MAIN вызывается к исполнению, она вызывается с двумя аргументами. Первый аргумент (условно называемый ARGC) указывает число аргументов в командной строке, с которыми происходит обращение к программе; второй аргумент (ARGV) является указателем на массив символьных строк, содержащих эти аргументы, по одному в строке. Работа с такими строками - это обычное использование многоуровневых указателей.

Самую простую иллюстрацию этой возможности и необходимых при этом описаний дает программа ECHO, которая просто печатает в одну строку аргументы командной строки, разделяя их пробелами. Таким образом, если дана команда

ECHO HELLO, WORLD то выходом будет HELLO, WORLD по соглашению ARGV[0] является именем, по которому вызывается программа, так что ARGC по меньшей мере равен 1. В приведенном выше примере ARGC равен 3, а ARGV[0], ARGV[1] и ARGV[2] равны соответственно “ECHO”, “HELLO,” и “WORLD”.

Первым фактическим агументом является ARGV[1], а последним ARGV[ARGC-1]. Если ARGC равен 1, то за именем программы не следует никакой командной строки аргументов. Все это показано в ECHO:

MAIN(ARGC, ARGV) /* ECHO ARGUMENTS; 1ST VERSION */ INT ARGC;

CHAR *ARGV[];

\( INT I;

FOR (I = 1; I < ARGC; I++) PRINTF(“%S%C”, ARGV[I], (I

\)

Поскольку ARGV является указателем на массив указателей, то существует несколько способов написания этой программы, использующих работу с указателем, а не с индексацией массива.

Мы продемонстрируем два варианта.

MAIN(ARGC, ARGV) /* ECHO ARGUMENTS; 2ND VERSION */ INT ARGC;

CHAR *ARGV[];

\( WHILE (--ARGC > 0) PRINTF(“%S%C”,*++ARGV, (ARGC > 1) ? ' ' : '\N');

\)

Так как ARGV является указателем на начало массива строк-аргументов, то, увеличив его на 1 (++ARGV), мы вынуждаем его указывать на подлинный аргумент ARGV[1], а не на ARGV[0].

Каждое последующее увеличение передвигает его на следующий аргумент; при этом *ARGV становится указателем на этот аргумент. одновременно величина ARGC уменьшается; когда она обратится в нуль, все аргументы будут уже напечатаны.

Другой вариант: MAIN(ARGC, ARGV) /* ECHO ARGUMENTS; 3RD VERSION */ INT ARGC;

CHAR *ARGV[];

\( WHILE (--ARGC > 0) PRINTF((ARGC > 1) ? “%S” : “%S\N”, *++ARGV);

\)

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

Как второй пример, давайте внесем некоторые усовершенствования в программу отыскания заданной комбинации символов из главы 4. Если вы помните, мы поместили искомую комбинацию глубоко внутрь программы, что очевидно является совершенно неудовлетворительным. Следуя утилите GREP системы UNIX, давайте изменим программу так, чтобы эта комбинация указывалась в качестве первого аргумента строки.

#DEFINE MAXLINE 1000 MAIN(ARGC, ARGV) /* FIND PATTERN FROM FIRST ARGUMENT */ INT ARGC;

CHAR *ARGV[];

\( CHAR LINE[MAXLINE];

IF (ARGC != 2) PRINTF (“USAGE: FIND PATTERN\N”);

ELSE WHILE (GETLINE(LINE, MAXLINE) > 0) IF (INDEX(LINE, ARGV[1] >= 0) PRINTF(“%S”, LINE);

\)

Теперь может быть развита основная модель, иллюстрирующая дальнейшее использование указателей. Предположим, что нам надо предусмотреть два необязательных аргумента. Один утверждает: “напечатать все строки за исключением тех, которые содержат данную комбинацию”, второй гласит: “перед каждой выводимой строкой должен печататься ее номер”.

Общепринятым соглашением в “с”-программах является то, что аргумент, начинающийся со знака минус, вводит необязательный признак или параметр. Если мы, для того, чтобы сообщить об инверсии, выберем -X, а для указания о нумерации нужных строк выберем -N(“номер”), то команда

FIND -X -N THE при входных данных NOW IS THE TIME FOR ALL GOOD MEN TO COME TO THE AID OF THEIR PARTY.

Должна выдать 2:FOR ALL GOOD MEN Нужно, чтобы необязательные аргументы могли располагаться в произвольном порядке, и чтобы остальная часть программы не зависела от количества фактически присутствующих аргументов. в частности, вызов функции INDEX не должен содержать ссылку на ARGV[2], когда присутствует один необязательный аргумент, и на ARGV[1], когда его нет. Более того, для пользователей удобно, чтобы необязательные аргументы можно было объединить в виде:

FIND -NX THE вот сама программа:

#DEFINE MAXLINE 1000 MAIN(ARGC, ARGV) /* FIND PATTERN FROM FIRST ARGUMENT */ INT ARGC;

CHAR *ARGV[];

\( CHAR LINE[MAXLINE], *S;

LONG LINENO = 0;

INT EXCEPT = 0, NUMBER = 0;

WHILE (--ARGC > 0 && (*++ARGV)[0] == '-') FOR (S = ARGV[0]+1; *S != '\0'; S++) SWITCH (*S) \( CASE 'X': EXCEPT = 1;

BREAK;

123

CASE 'N': NUMBER = 1;

BREAK;

DEFAULT: PRINTF(“FIND: ILLEGAL OPTION %C\N”, *S);

ARGC = 0;

BREAK;

\) IF (ARGC != 1) PRINTF(“USAGE: FIND -X -N PATTERN\N”);

ELSE WHILE (GETLINе(LINE, MAXLINE) > 0) \( LINENO++;

IF ((INDEX(LINE, *ARGV) >= 0) != EXCEPT) \ IF (NUMBER) PRINTF(“%LD: “, LINENO);

PRINTF(“%S”, LINE);

\)

\) \)

Аргумент ARGV увеличивается перед каждым необязательным аргументом, в то время как аргумент ARGC уменьшается. если нет ошибок, то в конце цикла величина ARGC должна равняться 1, а *ARGV должно указывать на заданную комбинацию. Обратите внимание на то, что *++ARGV является указателем аргументной строки; (*++ARGV)[0] - ее первый символ. Круглые скобки здесь необходимы, потому что без них выражение бы приняло совершенно отличный (и неправильный) вид *++(ARGV[0]). Другой правильной формой была бы **++ARGV.

Упражнение 5-7.

Напишите программу ADD, вычисляющую обратное польское выражение из командной строки. Например, ADD 2 3 4 + * вычисляет 2*(3+4).

Упражнение 5-8.

Модифицируйте программы ENTAB и DETAB (указанные в качестве упражнений в главе 1) так, чтобы они получали список табуляционных остановок в качестве аргументов. Если аргументы отсутствуют, используйте стандартную установку табуляций.

Упражнение 5-9.

Расширьте ENTAB и DETAB таким образом, чтобы они воспринимали сокращенную нотацию ENTAB M +N

124

означающую табуляционные остановки через каждые N столбцов, начиная со столбца M. Выберите удобное (для пользователя) поведение функции по умолчанию.

Упражнение 5-10.

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

TAIL -N печатает последние N строк. программа должна действовать рационально, какими бы неразумными ни были бы ввод или значение N. Составьте программу так, чтобы она оптимальным образом использовала доступную память: строки должны храниться, как в функции SORT, а не в двумерном массиве фиксированного размера.

5.12. Указатели на функции В языке “с” сами функции не являются переменными, но имеется возможность определить указатель на функцию, который можно обрабатывать, передавать другим функциям, помещать в массивы и т.д. Мы проиллюстрируем это, проведя модификацию написанной ранее программы сортировки так, чтобы при задании необязательного аргумента -N она бы сортировала строки ввода численно, а не лексикографически.

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

Именно такой подход используется в нашей новой программе сортировки.

Как и прежде, лексикографическое сравнение двух строк осуществляется функцией STRCMP, а перестановка функцией SWAP; нам нужна еще функция NUMCMP, сравнивающая две строки на основе численного значения и возвращающая условное указание того же вида, что и STRCMP. Эти три функции описываются в MAIN и указатели на них передаются в SORT. В свою очередь функция SORT обращается к этим функциям через их указатели.

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

#DEFINE LINES 100 /* MAX NUMBER OF LINES TO BE SORTED */ MAIN(ARGC, ARGV) /* SORT INPUT LINES */ INT ARGC;

CHAR *ARGV[];

Характеристики

Тип файла
Документ
Размер
1,37 Mb
Материал
Учебное заведение
Неизвестно

Список файлов ВКР

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7071
Авторов
на СтудИзбе
257
Средний доход
с одного платного файла
Обучение Подробнее