Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

методички.C++ / С Fundamentals

.pdf
Скачиваний:
76
Добавлен:
24.02.2016
Размер:
1.38 Mб
Скачать

нуль. По окончании работы со строкой вызовите функцию free(), чтобы вернуть зарезервированную память обратно в кучу, сделав ее доступной для будущих вызовов функции malloc():

free(stringPtr);

Чтобы обратиться к отдельным символам строки, вы можете использовать квадратные скобки. Например, чтобы отобразить третий символ в строке, адресуемой указателем stringPtr, можно написать:

printf("%c", stringPtr[2]);

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

Нулевые строки и нулевые символы

В программировании на С нуль имеет много значений, и важно понимать различные значения нуля.

Нулевой символ \0 имеет ASCII-значение, равное нулю, и обычно в программах представляется символической константой NULL.

Строка с завершающим нулем представляет собой массив с нулевым символом после последнего значащего символа в строке. Все строки

должны иметь одну дополнительную позицию для завершающего нулевого символа.

Нулевая строка это строка, которая начинается с нулевого символа. Длина нулевой строки равна нулю, но ее размер в памяти может занимать больше одного байта. Литеральная нулевая строка записывается как “”.

Нулевой указатель на строку не адресует никаких достоверных данных он не является эквивалентом нулевой строки. Чтобы создать нулевой указатель на строку, присвойте указателю значение NULL. Чтобы создать нулевую строку, присвойте NULL первому символу строки.

Наконец, символ 0является обычным символом, содержащимся в таблице ASCII, и имеющим десятичный код 48.

Строковые функции

Существует богатая библиотека строковых функций, и все они начинаются с букв str, что позволяет легко находить их в описании библиотек. Чтобы использовать эти функции, включите в начало вашего файла заголовочный файл string.h:

#include <string.h>

© Кафедра информатики БГУИР. Мелещенко А.А.

121

Отображение строк

Чтобы отобразить строку на экране, передайте ее функции printf(). Например, следующие две строки создают, инициализируют и отображают строку с именем company:

char company[] = ″Intel Corporation″; printf(company);

Вообще говоря, громоздкая функция printf() предназначена для решения более сложных задач форматированного вывода. Для того чтобы отобразить текст и начать новую строку, проще вызвать небольшую функцию puts() из файла stdio.h:

char processor[] = ″Pentium IV″; puts(processor);

А вот для вывода форматированных строк printf() незаменима: printf(″Как жаль, что у моего компьютера нет %s!″, processor);

Чтение строк

Кроме отображения строк, большинству программ нужно также вводить символы с клавиатуры, дисковых файлов и других источников. Чтобы прочитать строку символов, выполните оператор типа:

scanf(″%80s″, string);

Спецификатор ″%80s″ указывает на то, что будет прочитано не более 80 символов, что позволяет избежать переполнения строки. Затем вы можете отобразить результат:

puts(string);

Если вы захотите испытать этот метод ввода строк, вы можете столкнуться с одной проблемой. Функция scanf() завершит ввод на первом же пробеле или символе табуляции, или при нажатии клавиши <Enter>. Например, если вы введете Это строка”, в строке запомнится только Это”. Чтобы ввести строки, содержащие пробелы, используйте библиотечную функцию gets():

puts(″Введите строку: ″); gets(string);

К сожалению, функция gets() не защищает пользователей от ввода большего количества символов, чем может вместить строка. Например, объявим такую строку:

char string[10];

Тогда при вводе 11-го и последующих символов функция gets() будет принимать их, записывая за пределами строки поверх данных, которые, к своему несчастью, оказались в этой области. Чтобы предотвратить подобные ошибки, используйте буферы ввода большого размера (обычно берется размер 128 байтов):

char string[128];

© Кафедра информатики БГУИР. Мелещенко А.А.

122

Преобразование строк в значения

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

Используйте функцию atof() для преобразования строк ASCII в значения с плавающей запятой типа double (несмотря на то, что функция называется atof(), что означает «из ASCII во float», результат будет иметь тип double). Для преобразования строк в целые значения воспользуйтесь функцией atoi() из ASCII в integer»). А функция atol() поможет в преобразовании строк в значения типа long. Все три функции описаны в файле stdlib.h.

Два листинга демонстрируют использование этих функций. Листинг 4.1 преобразует введенную строку в целые значения в различных форматах. Скомпилируйте и запустите эту программу, а затем введите целое число.

Листинг 4.1 convert.c (преобразование строки в целые значения)

1:#include <stdio.h>

2:#include <stdlib.h>

4:int main(void)

5:{

6:int value;

7:char string[128];

9:printf(″Enter value: ″);

10:gets(string);

11:value = atoi(string);

12:printf(″Value in decimal = %d\n″, value);

13:printf(″Value in hex = %#x\n″, value);

14:printf(″Value in octal = %o\n″, value);

15:return 0;

16:}

Чтобы поместить введенный с клавиатуры текст в строку, программа пользуется функцией gets(). В свою очередь, функция atoi() преобразует эту строку в целое значение, присваивая его переменной value (строка 11). Затем

три оператора printf() отображают значение переменной value в десятичном (%d), шестнадцатеричном(%#x) и восьмеричном(%o) форматах.

Чтобы преобразовать строки в значения типа long int, используйте функцию atol(). Например, вы могли бы заменить объявление в строке 6 на long value, а затем в строке 11 выполнить оператор value = atol(string).

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

© Кафедра информатики БГУИР. Мелещенко А.А.

123

Листинг 4.2 kilo.c (преобразование миль в километры)

1:#include <stdio.h>

2:#include <stdlib.h>

4:int main(void)

5:{

6:double miles;

7:char string[128];

9:printf(″Convert miles to kilometers\n″);

10:printf(″How many miles? ″);

11:gets(string);

12:miles = atof(string);

13:printf(″kilometers = %lf\n″, miles * 1.609344);

14:return 0;

15:}

Встроке 12 функция atof() преобразует введенный текст в значение с плавающей запятой типа double, присваивая его переменной miles. Затем оператор printf() отображает значение miles, умноженное на приблизительное число километров в одной миле (1.609344).

Определение длины строк

Длина строки определяется просто. Для этого нужно передать указатель на строку функции strlen(), которая возвратит длину строки в символах. В следующем примере

char *s = "Любая строка"; int len = strlen(s);

переменная len устанавливается равной длине строки, адресуемой указателем s. Листинг 4.3 показывает, как использовать функцию strlen().

Листинг 4.3. length.c (использование функции strlen())

1:#include <stdio.h>

2:#include <string.h>

3:

4: #define MAXLEN 128 5:

6:int main(void)

7:{

8:

char string[MAXLEN]; /* место для 255 символов */

9:

 

10:printf ("\nEnter a string: ");

11:gets(string);

12: puts("");

/* начать новую строку */

13:puts(string);

14:printf("Length = %d characters\n", strlen(string));

15:return 0;

© Кафедра информатики БГУИР. Мелещенко А.А.

124

16: }

Строка 8 определяет строковую переменную string, которая принимает ввод. После того как вы введете строку, программа передаст переменную string функции strlen(), которая вычислит длину строки в символах (строка 14). Оператор printf() в этой же строке листинга отобразит вычисленное значение.

Копирование строк

Оператор присваивания для строк не определен. Если s1 и s2 символьные массивы, вы не сможете скопировать один в другой следующим образом:

s1 = s2; /* ??? */

Данный оператор не компилируется. Но если s1 и s2 объявить как указатели типа char *, компилятор согласится с этим оператором, хотя вряд ли вы получите ожидаемый результат. Вместо копирования символов оператор s1 = s2 скопирует значение указателя s2 в указатель s1. Указатель s1, таким образом, будет указывать на то же место в памяти, что и s2, а информация, которую он адресовал до этого, может быть утеряна.

Чтобы корректно скопировать одну строку в другую, вызовите функ- цию strcpy(). Для двух указателей s1 и s2 типа char * оператор

strcpy(s1, s2);

копирует символы, адресуемые указателем s2, в память, адресуемую указателем s1, включая завершающие нули. Ответственность за то, что принимающая строка будет иметь достаточно места для хранения новой, лежит на вас.

Функция strncpy() аналогична по действию функции strcpy(), однако она позволяет ограничивать количество копируемых символов. Оператор

strncpy(s1, s2, 10);

скопирует 10 символов из строки, адресуемой указателем s2, в область памяти, адресуемую указателем s1. Если строка s2 имеет больше 10 символов, то результат усекается. Если же меньше неиспользуемые байты устанавливаются равными нулю.

Дублирование строк

В больших программах с множеством строковых переменных готовить специальные буферы для функции gets() слишком утомительно. Хорошо бы иметь такую функцию, которая позволяла бы вводить строку с клавиатуры и запоминать ее в куче, чтобы строка занимала ровно столько байтов, сколько требуется. Долой напрасные затраты памяти!

Листинги 4.4 и 4.5 образуют один небольшой модуль с единственной функцией GetStringAt(), которая удовлетворяет этим требованиям. Файл

© Кафедра информатики БГУИР. Мелещенко А.А.

125

gets.h – заголовочный: он содержит только объявления и прототип функции. Файл gets.c – это отдельный модуль, в котором описана функция GetStringAt(). Ни один из этих файлов не является законченной программой.

Листинг 4.4. gets.h (заголовочный файл для gets.c)

1: /* gets.h – заголовочный файл для gets.с */ 2:

3: #define MAXLEN 128 /* максимальный размер строки */ 4:

5: char *GetStringAt(int size);

Листинг 4.5. gets.c (описание функции получения строки)

1:#include <stdio.h>

2:#include <string.h>

3:#include <conio.h>

4:#include "gets.h"

6:/* Замечание: это не полная программа. Вы должны

7: скомпоновать этот модуль с главной программой. */ 8:

9:char *GetStringAt(int size)

10:{

11:

char buffer[MAXLEN];

/* временный

буфер ввода */

12:

int i = 0;

/*

индекс буфера */

13:

char с;

/*

принимает

введенные символы */

14:

 

 

 

 

15:if ((size > MAXLEN) || (size <= 0)) /* проверить размер */

16:size = MAXLEN;

17: while (--size > 0) { /* ввод строки */

18:с = getchar();

19:if (с == ′\n′)

20:size = 0;

21:else

22:buffer[i++] = с;

23:}

24:buffer[i] = ′\0′; /* завершение строки нулем */

25:return strdup(buffer); /* возвращение копии buffer */

26:}

Модуль в листинге 4.5 включает свой собственный заголовочный файл (строка 4), который определяет константу MAXLEN и объявляет прототип функции GetStringAt().

Оператор if в строке 15 проверяет параметр size. Если его значение находится вне заданного диапазона, то ему присваивается значение MAXLEN. В строке 17 цикл while вызывает функцию getchar() (строка 18), которая ожидает, пока вы введете символ. Программа присваивает этот

символ переменной с и проверяет его на совпадение с управляющим символом \n’ («новая строка», означающая, что вы нажали <Enter>). Если

© Кафедра информатики БГУИР. Мелещенко А.А.

126

это условие оказалось выполненным, программа устанавливает параметр size равным нулю, завершая тем самым цикл while. В противном случае

программа присваивает значение переменной с элементу массива buffer с индексом i. Индекс инкрементируется оператором ++ для подготовки к вводу

следующего символа

Замечание. Выполните цикл while в пошаговом режиме отладчика, на- блюдая при этом за значениями переменных buffer, с и i. Это хороший способ узнать, как цикл while вводит строку.

В строке 24 добавляется завершающий нулевой символ, служащий признаком конца строки. И, наконец, строка 25 возвращает результат функции GetStringAt(). Этот оператор передает строку buffer функции strdup(), которая размещает копию строки в динамической памяти.

Новая строка занимает столько памяти, сколько необходимо. Если переменная s имеет тип char *, то оператор

s = strdup("Двойная тревога");

выделит ровно 16 байтов памяти кучи, скопирует в эту область памяти 15- символьную строку Двойная тревогаплюс завершающий нуль и возвратит адрес этой области. По окончании работы со строкой следует освободить эту область памяти обычным способом:

free(s);

Предупреждение. Вы можете модифицировать строки, создаваемые функцией strdup(), но при этом не должны расширять их за пределы отведенных им объемов памяти. Если все-таки это необходимо сделать, скопируйте вашу строку в новый, больший по размеру буфер, зарезервированный функцией malloc(), после чего освободите память, которую строка занимала ранее.

Листинг 4.6 представляет собой основную программу, которая использует функцию GetStringAt(), объявленную в файле gets.h и описанную в модуле gets.c. Чтобы создать работающую программу, вы должны скомпоновать эти модули вместе. Для этого откройте новый файл проекта, добавьте в него модули duped.c и gets.c, а затем выполните команду Run. Эта команда: 1) скомпилирует модуль gets.c, создавая объектный файл с именем gets.obj, 2) скомпилирует модуль duped.c и создаст объектный файл duped.obj, 3) скомпонует эти два объектных файла и 4) создаст файл duped.exe, который вы можете запускать на исполнение.

Листинг 4.6. duped.c (использование функции GetStringAt())

1:#include <stdio.h>

2:#include <conio.h>

3:#include <string.h>

4:#include <alloc.h>

5:#include "gets.h"

7:#define PROMPT "String: " /* приглашение на ввод */

© Кафедра информатики БГУИР. Мелещенко А.А.

127

8:

9:int main(void)

10:{

11:char *s; /* указатель на результат функции GetStringAt()*/

13:clrscr();

14:printf(PROMT);

15:s = GetStringAt(MAXLEN);

16:if (s) {

17:puts("Your entry is: ");

18:puts(s);

19:printf("Length = %d characters\n", strlen(s));

20:free(s);

21:} else

22:puts("Error duplicating string!");

23:return 0;

24:}

Строка 15 вызывает функцию GetStringAt(), передавая ей в виде параметра максимальную длину строки. В строке 16 программа проверяет результат функции GetStringAt(). Если она возвращает нуль, это значит, что функция strdup() не смогла создать копию строки, возможно, из-за недостатка памяти в куче. Обратите внимание также на освобождение памяти в строке 20 после того, как строка оказывается больше не нужной.

Упражнение. Создайте рекурсивную версию функции GetStringAt().

Сравнение строк

С помощью функции GetStringAt() вы можете написать программу, которая предлагает ввести пароль. Чтобы определить, правильный ли вы ввели пароль, листинг 4.7 вызывает функцию strcmp(), которая сравнивает две строки.

Программа password вызывает функцию GetStringAt() из модуля gets.c. Чтобы создать исполняемый файл, вы должны скомпоновать программу с этим модулем. Для компиляции, компоновки и выполнения программы создайте файл проекта под именем password, добавьте в него модули password.c и gets.c, а затем выполните команду Run. (Если программа не запуститься, попробуйте команду Build All. Проверьте также имена маршрутов каталогов в проекте).

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

Листинг 4.7. password.c (предложение ввести пароль)

1: #include <stdio.h>

© Кафедра информатики БГУИР. Мелещенко А.А.

128

2:#include <conio.h>

3:#include <string.h>

4:#include <alloc.h>

5:#include "gets.h"

7:#define FALSE 0

8:#define TRUE 1

9:#define PASSWORD "Informatics"

10:#define PROMPT "Enter password: "

12:int main(void)

13:{

14:char *s;

15:int done = FALSE;

17:clrscr();

18:while (!done) {

19:printf(PROMPT);

20:s = GetStringAt(MAXLEN);

21:clrscr();

22:if (!s) {

23:puts("Error: Out of memory");

24:return 1;

25:} else {

26:done = (strcmp(s, PASSWORD) == 0);

27:if (!done)

28:puts("Error in password! Type "PASSWORD" to quit");

29:free(s); /* освобождаем память */

30:}

31:}

32:clrscr();

33:puts("Correct password given");

34:return 0;

35:}

В строке 26 показано, как сравнивать две строки. Оператор done = (strcmp(s, PASSWORD) == 0);

устанавливает переменную done равной значению «истина», если строка, адресуемая указателем s, равна строке Informatics”, представленной константой PASSWORD.

Если i переменная типа int, и если s1 и s2 указатели на char, то

оператор

i = strcmp(s1, s2);

установит i равной –1 или другому отрицательному числу, если строка, адресуемая указателем s1, в алфавитном порядке меньше строки, адресуемой указателем s2. Если строки в точности совпадают, функция возвратит нуль. Если строка s1 в алфавитном порядке больше строки s2, она вернет +1 или другое положительное число.

© Кафедра информатики БГУИР. Мелещенко А.А.

129

Функция strcmp() чувствительна к регистру букв при сравнении строчные буквы считаются большими, чем их прописные эквиваленты (так как буквы нижнего регистра имеют большие ASCII-значения, чем буквы верхнего регистра). Для сравнения двух строк без учета регистра вызовите функцию stricmp(). Буква i означает «ignore case» («игнорировать регистр»). Эта функция действует аналогично функции strcmp(), но перед сравнением преобразует все буквы в прописные. Например, если сравнение выполнять с помощью функции strcmp(), то строка Appleалфавитно окажется меньше строки apple”. Если же для сравнения использовать функцию stricmp(), эти строки будут считаться идентичными.

Чтобы сравнить только часть двух строк, используйте функцию strncmp(). Например, оператор

i = strncmp(s1, s2, 2);

установит целую переменную i равной нулю только в том случае, если первые два символа строк, адресуемых указателями s1 и s2, в точности совпадают. Для сравнения части строк без учета регистра вызывайте функцию strnicmp().

Конкатенация строк

Конкатенация двух строк означает их соединение, при этом создается новая, более длинная строка. При объявлении строки

char original[128] = "Проверка ";

оператор

strcat(original, "связи");

превратит первоначальную строку original в Проверка связи”.

При вызове функции strcat() убедитесь, что первый аргумент типа char * инициализирован и имеет достаточно места, чтобы запомнить результат, в противном случае может возникнуть серьезная ошибка.

Функция strcat() возвращает адрес результирующей строки (совпадающий с ее первым параметром) и может использоваться как каскад нескольких вызовов функций:

strcat(strcat(s1, s2), s3);

Этот оператор добавляет строку, адресуемую s2, и строку, адресуемую s3, к строке, адресуемой s1, что эквивалентно двум отдельным операторам:

strcat(s1, s2); strcat(s1, s3);

Листинг 4.8 показывает, как использовать функцию strcat() для решения типичной проблемы получения полного имени человека из фамилии, имени и отчества, запомненных по отдельности, например в базе данных. Скомпилируйте программу concat аналогично предыдущим примерам: откройте новый файл проекта, добавьте в него модули concat.c и gets.c и запустите программу на исполнение. Введите фамилию, имя и

© Кафедра информатики БГУИР. Мелещенко А.А.

130

Соседние файлы в папке методички.C++