Стив Саммит. Язык си в вопросах и ответах.Библиотечные функции.

Стив Саммит. Язык си в вопросах и ответах.Библиотечные функции. Ответы на вопросы разбиты по темам:

1. Нулевые указатели

2. Указатели и массивы.

3. Выделение памяти

4. Выражения

5. ANSI C

6. Препроцессор С.

7. Списки аргументов переменной длины.

8. Булевы выражения и переменные.

9. Структуры, перечисления и объединения.

10. Декларации.

11. Cтандартный ввод/вывод.

12. Библиотечные функции.

13. Lint.

14. Стиль.

15. Операции с плавающей точкой.

16. Интерфейс с операционной системой.

17. Разное (Пребразование Fortran -> C , грамматики для YACC и т.п.)

Библиотечные функции.

12.1    Почему strncpy не всегда завершает строку-результат символом ‘\0’?

О:    strncpy    была задумана для обработки теперь уже устаревших структур данных — «строк» фиксированной длины, не обязательно завершающихся символом  ‘\0’.  И, надо сказать, strncpy не совсем удобно использовать в других случаях, поскольку часто придется добавлять символ ‘\0’ вручную.

12.2    Я пытаюсь сортировать массив строк с помощью qsort, используя для сравнения strcmp, но у меня    ничего не получается.

О:    Когда Вы говорите о «массиве строк», то, видимо, имеете    в виду «массив    указателей на char». Аргументы функции сравнения, работающей в паре с qsort — это указатели на сравниваемые объекты,    в данном случае — указатели на указатели    на char. (Конечно, strcmp работает просто с указателями на    char).
Аргументы процедуры сравнения описаны как «обобщенные указатели» const void * или char *. Они должны быть превращены в то, что они представляют на самом деле, т.е. (char **) и дальше нужно раскрыть ссылку с помощью * ; тогда strcmp получит именно то, что нужно для сравнения.  Напишите функцию сравнения примерно так:
int pstrcmp(p1, p2)      /* сравнить строки, используя    указатели */ char *p1, *p2;      /* const void    * для ANSI C */ { return strcmp(*(char **)p1, *(char **)p2); }
Имейте в виду, что в K&R II Разд. 5.11 обсуждается функция qsort, которая    отличается от стандартной.

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

О:    Преобразования должны быть сделаны внутри функци сравнения, которая должна быть объявлена как принимающая аргументы    типа «обобщенных указателей (const void * или char *) как это описано в вопросе 12.2. Функция    сравнения может    выглядеть так:
int mystructcmp(p1, p2) char    *p1, *p2;       /* const void * для ANSI C */ { struct mystruct *sp1    = (struct mystruct *)p1; struct mystruct *sp2    = (struct mystruct *)p2;
/* теперь сравнивайте sp1->что-угодно и  sp2-> … */ }
(С другой стороны, если сортируются указатели на структуры, необходима косвенная адресация, как в вопросе 12.2:
sp1 = *(struct mystruct **)p1 .)

12.4    Как преобразовать числа    в строки (операция, противоположная atoi)? Есть ли    функция    itoa?

О:    Просто используйте sprintf. (Необходимо    будет выделить память для результата, см.    вопросы    3.1 и 3.2. Беспокоиться, что sprintf — слишком    сильное    средство, которое может    привести к перерасходу памяти и увеличению времени выполнения,    нет оснований. На практике sprintf    работает хорошо).
Смотри: K&R I Разд.3.6 c. 60; K&R II Разд.3.6 c. 64.

12.5    Как получить дату или время в С программе?

О:    Просто используйте функции time, ctime,    и/или localtime. (Эти функции    существуют многие годы,    они включены в стандарт    ANSI). Вот простой пример:
#include <stdio.h> #include <time.h>
main() { time_t now = time((time_t *)NULL); printf(«It’s %.24s.\n», ctime(&now)); return 0; }
Смотри: ANSI Разд. 4.12 .

12.6    Я знаю, что библиотечная функция localtime разбивает значение time_t по отдельным членам структуры tm, а функция ctime превращает time_t в строку символов.  А как проделать обратную операцию перевода структуры tm или строки символов в значение time_t?

О:      Стандарт ANSI определяет библиотеную функцию mktime, которая преобразует структуру tm в time_t. Если Ваш компилятор не поддерживает mktime, воспользуйтесь одной из общедоступных версий этой функции.
Перевод    строки в значение time_t выполнить сложнее из-за большого количества форматов дат    и времени, которые должны быть распознаны. Некоторые компиляторы поддерживают функцию strptime; другая популярная функция — partime широко распространяется с пакетом RCS, но нет уверенности, что эти функции войдут в Стандарт.
Смотри: K&R II Разд. B10 c. 256; H&S Разд. 20.4 c. 361; ANSI Разд. 4.12.2.3 .

12.7    Как прибавить n дней к дате? Как вычислить разность двух дат?

О:    Вошедшие в стандарт ANSI/ISO функции mktime и difftime могут помочь при решении обеих проблем. mktime() поддерживает ненормализованные даты, т.е. можно прямо взять заполненную структуру tm, увеличить или уменьшить член tm_mday,    затем вызвать mktime(),    чтобы нормализовать члены year, month, и day  (и преобразовать в значение time_t). difftime() вычисляет разность в    секундах между двумя величинами типа time_t. mktime() можно использовать для вычисления    значения time_t разности    двух дат. (Заметьте, однако, что все эти приемы возможны лишь для дат, которые могут быть представлены значением типа time_t; кроме того, из-за переходов на летнее и зимнее время продолжительность дня не точно равна 86400 сек.). Cм. также вопросы 12.6 и 17.28.
Смотри: K&R II Разд. B10 c. 256; H&S Разд. 20.4, 20.5 c. 361-362; ANSI Разд. 4.12.2.2, 4.12.2.3 .

12.8    Мне нужен генератор случайных чисел.

О:    В стандартной библиотеке С есть    функция    rand().    Реализация этой функции в Вашем компиляторе может не быть идеальной, но и создание лучшей функции может оказаться очень непростым.
Смотри: ANSI Разд. 4.10.2.1 c. 154; Knuth Vol. 2 Chap. 3 c. 1-177.

12.9    Как получить случайные целые числа в определенном диапазоне?

О:    Очевидный способ
rand() % N
где N, конечно, интервал, довольно плох, ведь поведение младших бит во многих генераторах случайных чисел огорчает своей неслучайностью.  (См. вопрос 12.11).  Лучше попробуйте нечто вроде
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
Если Вам не нравится употребление чисел с плавающей точкой, попробуйте
rand() / (RAND_MAX / N + 1)
Оба метода требуют знания RAND_MAX (согласно ANSI, RAND_MAX определен в <stdlib.h>. Предполагается, что N много меньше RAND_MAX.

12.10   Каждый раз при запуске программы функция rand() выдает одну и ту же последовательность чисел.

О:      Можно вызвать srand() для случайной инициализации генератора случайных чисел. В качестве аргумента для srand() часто используется текущее время, или время, прошедшее до нажатия на клавишу (хотя едва ли существует мобильная процедура определения времен нажатия на клавиши; см.  вопрос 16.10).
Смотри: ANSI Разд. 4.10.2.2 c. 154.

12.11   Мне необходима случайная величина, имеющая два значения true/false. Я использую rand() % 2, но получается неслучайная последовательность 0,1,0,1,0….

О:      Некачественные генераторы случайных чисел (попавшие, к несчастью, в состав некоторых компиляторов) не очень то случайны, когда речь идет о младших битах. Попробуйте использовать старшие биты. См. вопрос 12.9.

12.12   ———-

12.13   Я все время получаю сообщения об ошибках — не определены библиотечные функции, но я включаю все необходимые головные файлы.

О:      Иногда (особенно для нестандартных функций) следует явно указывать, какие библиотеки нужны при компоновке программы. См. также вопрос 15.2.

12.14   Я по-прежнему получаю сообщения, что библиотечные функции не определены, хотя и использую ключ -l, чтобы явно указать библиотеки во время компоновки.

О:    Многие компоновщики делают один    проход по списку объектных файлов и библиотек, которые Вы    указали, извлекая из библиотек только те функции, удовлетворяющие ссылки, которые _к этому моменту_ оказались неопределенными. Следовательно,    порядок    относительно объектных файлов, в котором перечислены библиотеки, важен; обычно    просмотр библиотек нужно делать в самом конце. (Например, в операционной системе UNIX помещайте ключи    -l в самом конце командной строки).

12.15    Мне необходим исходный текст программы,    которая    осуществляет поиск заданной строки.

О:      Ищите библиотеку regesp (поставляется со многими UNIX — системами) или достаньте пакет regexp Генри Спенсера (Henry Spencer) (cs.toronto.edu директорий pub/regexp.shar.Z). См. также вопрос 17.12.

12.16   Как разбить командную строку на разделенные пробельными литерами аргументы (что-то вроде argc и argv в main)?

О:    В большинстве компиляторов имеется функция strtok, хотя    она требует    хитроумного обращения, а ее возможности    могут Вас не удовлетворить (например, работа в случае кавычек).
Смотри: ANSI Разд. 4.11.5.8; K&R II Разд.B3 c. 250; H&S Разд. 15.7; PCS c. 178.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *