Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
const char * p1 = "Клингон"; // рекомендуемое использование
Тем не менее, инициализация строковым литералом массива, отличного const, не влечет за собой проблем такого рода, поскольку массив получает копию исходной строки.
Короче говоря, не используйте указатель на строковый литерал, если вы планируете изменять строку.
Массивы символьных строк
Часто удобно иметь массив символьных строк. Тогда для доступа к разным строкам можно применять индекс. В листинге 11.4 продемонстрированы два подхода: массив указателей на строки и массив из массивов типа char.
Символьные строки и строковые функции 427
размер mytalents: 40, размер yourtalents: 200
Во многих отношениях массивы mytalents и yourtalents очень похожи. Каждый представляет по пять строк. Когда используется один индекс, как в mytalents [0] и yourtalents [0], результатом будет одиночная строка. Подобно тому, как значением mytalents [1] [2] является ' ч', т.е. третий символ во второй строке, представленной массивом mytalents, yourtalents [1] [2] — это 'ж', т.е. третий символ второй строки, представленной массивом yourtalents. Оба массива инициализируются в одинаковой манере.
Но имеются и различия. Массив mytalents — это массив из пяти указателей, занимающий в нашей системе 40 байтов. Но yourtalents — массив, состоящий из пяти массивов по 40 значений char и занимающий в нашей системе 200 байтов. Таким образом, тип массива mytalents отличается от типа yourtalents, несмотря на то, что и mytalents [0], и yourtalents [0] — это строки. Указатели в mytalents указывают на места размещения строковых литералов, применяемых для инициализации, которые хранятся в статической памяти. Однако массивы в yourtalents содержат копии строковых литералов, в результате чего каждая строка сохраняется дважды.
428 глава 11
Более того, распределение памяти в массивах неэффективно, т.к. все элементы yourtalents должны иметь одинаковый размер, и этот размер должен быть достаточно большим, чтобы вместить самую длинную строку.
Один из способов восприятия этого различия — представление yourtalents в виде прямоугольного двумерного массива, все строки которого имеют одинаковую длину, в данном случае 40 байтов. В то же время mytalents можно представить в виде зубчатого массива с варьирующейся длиной строк. Эти два вида массивов показаны на рис. 11.2. (В действительности строки, на которые указывают элементы массива mytalents, не обязательно должны храниться последовательно в памяти, однако рисунок задуман в качестве иллюстрации различий в требованиях к хранению.)
Смысл всего сказанного в том, что при представлении набора строк, предназначенных для отображения, массив указателей более эффективен, чем массив символьных массивов. Однако существует и ограничение. Поскольку указатели в массиве mytalents указывают на строковые литералы, эти строки не должны изменяться. Тем не менее, содержимое массива yourtalents может изменяться. Поэтому, если предполагается изменение строк или требуется зарезервировать память для ввода строк, не следует использовать указатели на строковые литералы.
Рис. 11.2. Прямоугольные и зубчатые массивы
Символьные строки и строковые функции 429
Указатели и строки
Возможно, вы уже заметили, что в этом обсуждении строк мы периодически ссылаемся на указатели. Большинство операций со строками в С фактически работают с указателями. В качестве примера рассмотрим короткую программу в листинге 11.5.
Листинг 11.5. Программа p_and_s. с
На заметку!
Если ваш компилятор не поддерживает спецификатор %р, замените его %u или %iu.
Глядя на эту программу, можно подумать, что она создает копию строки "Не позволяйте себя запутать ! ", и на первый взгляд вывод подтверждает это предположение:
Не позволяйте себя запутать ! !
mesg = Не позволяйте себя запутать!; smesg = 0x0012ff48; value = 0х0040а000
copy = Не позволяйте себя запутать!; &сору = 0x0012ff44; value = 0х0040а000
Но давайте взглянем на вывод printf() более внимательно. Прежде всего, значения mesg и сору выводятся в виде строки (%s). Здесь нет никакого сюрприза; все строки выглядят как "Не позволяйте себя запутать ! ".
Следующий элемент в каждой строке представляет адрес определенного указателя. Для конкретного запуска два указателя mesg и сору хранятся, соответственно, в ячейках 0x0012ff48 и 0x0012ff44.
Теперь обратите внимание на завершающий элемент по имени value. Это значение заданного указателя. Значением указателя является адрес, который он содержит. Как видите, mesg указывает на ячейку 0х0040а000, и то же самое можно сказать о сору. Следовательно, сама строка не копировалась. Оператор сору = mesg; всего лишь создает второй указатель, ссылающийся на ту же строку.
Тогда зачем все эти предосторожности? Почему бы просто не скопировать всю строку? Задайте себе вопрос: что эффективнее — копировать один адрес или, скажем, 50 отдельных элементов? Часто для решения задачи вполне достаточно только адреса. Если вам действительно необходима копия строки, т.е. ее дубликат, можете воспользоваться функцией strcpy() или strncpy(), как будет показано далее в главе.
Теперь, когда мы обсудили определение строк внутри программы, давайте переключимся на строки, вводимые с клавиатуры.
430 глава 11
Ввод строк
Если в программе нужно ввести строку, понадобится сначала зарезервировать пространство для хранения этой строки и затем с помощью функции ввода извлечь строку.
Создание пространства под строку
Первое действие связано с подготовкой места, куда будет помещена строка после ее чтения. Как упоминалось ранее, это означает выделение пространства, достаточного для последующего чтения строк. Не следует ожидать, что компьютер подсчитает длину строки во время ее чтения и выделит необходимое пространство. Компьютер нс будет делать это (если только вы не напишете специальную функцию). Например, предположим, что имеется такой код:
char *name;
scanf("%s", name);
Возможно, компилятор примет этот код, скорее всего, выдав предупреждение, но при чтении пате строка может быть записана поверх данных или кода вашей программы и вызвать ее аварийное завершение. Причина в том, что функция scanf() копирует информацию по адресу, предоставленному аргументом, а в этом случае аргументом является неинициализированный указатель; name может указывать куда угодно. Большинство программистов находят такую ситуацию крайне забавной, но только не в собственных программах.
Проще всего решить эту проблему, включив в объявление явный размер массива:
char name[81];
Теперь name представляет собой адрес зарезервированного блока памяти размером 81 байт. Другая возможность предполагает применение функций выделения памяти из библиотеки С, и мы рассмотрим их в главе 12.
Читать дальшеИнтервал:
Закладка: