Добрый день друзья. На прошлом занятии мы разобрались с одномерными массивами. Сегодня разберемся с одним их частным случаем — символьными строками.  С ними мы уже даже сталкивались. В самом первом уроке. Помните, выводили на экран строчку Hello world. Каждый символ в этой строке это элемент одномерного массива.

Прочитайте улучшенную версию этого урока «Ввод и вывод символьных строк».

В новой версии:

  • Ещё более доступное объяснение
  • Дополнительные материалы
  • 12 задач на программирование с автоматической проверкой решения
Рис.1. Символьный массив
Как мы уже знаем, для хранения символов используются элементы типа  char.  Значит для хранения строки, мы можем использовать массив таких элементов. Единственным отличием такого массива, будет являться последний элемент. Компьютеру же как-то надо понимать, когда строка заканчивается? Это мы с вами видим, а у компьютера мозги кремниевые, он только нулики и единички понимает, и в них же и хранит всю информацию. Поэтому выбрали специальный символ, которым обозначается конец строки. Это символ с кодом нуль , его обозначают следующим символом –  ‘\0’. Помните, я рассказывал про то, что первые 32 значения в таблице кодов ASCII застолблены под служебные символы. Вот это пример одного из них, самого первого.  Изменим пример на картинке выше, чтобы он больше соответствовал действительности. 
Рис 2. Символьная строка
 

Объявление и инициализация строк.

Как мы уже разобрались, необходимо использовать для хранения строк массив символов. Никаких фокусов тут нет, и объявление массива символов стандартное.  
 
Листинг 14.1

char str[10];
Но сейчас это просто массив символов, а никакая не строка. Чтобы это стало строкой, необходимо, чтобы последним в массиве символов был символ ‘\0’. 
В объявленном выше массиве всего 10 элементов. Если мы будем его использовать для хранения строки, нам стоит учитывать, что один элемент (последний) у нас всегда будет занят, символом конца строки.
После того, как мы объявили массив символов, в нем будет записан мусор. В этом можно убедиться, выполнив следующую программу.
Листинг14.2
#include <stdio.h> 
int main(){
      char str[17];
      printf(«%s\n», str);
      return(0);
}
Рис.3. Символьный массив после объявления
Как видите, для вывода строк можно использовать стандартную функцию printf(), для которой предусмотрен специальный спецификатор %s. В остальном никаких отличий здесь нет.
Теперь разберемся, как присвоить значение строке. Есть несколько способов. 
  • Как и любая переменная, строка может быть инициализирована (т.е. ей присвоено некоторое значение) непосредственно при её объявлении.
Листинг14.3
#include <stdio.h> 
int main(){
      char str[17]=«Hello world»;
      printf(«%s\n», str);
      return(0);
}
При таком объявлении и инициализации,  все свободные символы, так и останутся заполненными мусором либо обнулятся. Тут в зависимости от компилятора. Вы можете это проверить самостоятельно. Это будет первым заданием для самостоятельного выполнения к этому уроку.
  • Мы можем не задавать при инициализации размер массива.
Листинг 14.4
#include <stdio.h> 
int main(){
      char str[]=«Hello world»;
      printf(«%s\n», str);
      return(0); 
}
В этом случае, компилятор сам посчитает количество символов для хранения строки в кавычках, и сам учтет заключительный символ ‘\0’. В данном случае массив strбудет из 12 элементов.
Кстати, посмотрите на следующую программу.  Она наглядно иллюстрирует, что массив символов, без завершающего ‘\0’  это не строка.
Листинг 14.5
#include <stdio.h> 
int main(){
      char str[5];
      str[0]=‘a’;
      str[2]=‘b’;
      printf(«%s\n», str);
      return(0); 
}
Результат работы этой программы представлен на следующем рисунке.
Рис. 4. Вывод на экран символьного массива без нулевого элемента в конце
 Как можете заметить, вывелись первый символ, потом один символ пропущенный (с мусором), дальше второй символ, сохраненный нами в программе, а дальше пошел неконтролируемый мусор. Не контролируемый потому что непонятно даже, сколько там символов вывелось, но явно не оставшиеся два символа.

Ввод и вывод строк.

Теперь рассмотрим, как можно ввести  строку символов с клавиатуры.
Возникает естественное желание воспользоваться стандартной функцией scanf(). Попробуем.
Листинг14.6
#include <stdio.h> 
int main(){
      char str[17];
      scanf(«%s», str);
      printf(«%s\n»,str);
      return(0); 
}
Выполним эту программу. Введем, уже привычное нам, Hello world.
Результат работы программы на следующем рисунке.
Рис.5 Ввод строки с использованием функции scanf().
Как видите, в строку сохранилось лишь первое слово. Все дело в реализации функции scanf. Она считает пробел разделителем. Получается, таким способом мы можем считать лишь строку, которая не содержит пробелов, т.е. мы можем считать одно слово.
Кстати, вы обратили внимание, что я не поставил перед именем массива знак &, чтобы получить его адрес?  Это не ошибка. Просто имя массива, без указания номера элемента в квадратных скобках, ссылается на адрес первого элемента массива. Т.е. нам тут не нужно получать адрес, он и так у нас есть.  Это касается не только символьных массивов, а любых. Но пока это не особо важно. С этим мы столкнемся, когда будем изучать указатели.   
Вернемся к нашим баранам, как говорится.  Мы хотели считать строку. Раз scanf() надежд возложенных на неё не оправдала, должна быть какая-то другая функция. И она, конечно же, есть. 
Функция gets().
Мы снова не будем углубляться в развернутый синтаксис, кому интересно, тот может подробно посмотреть в любом справочнике.
Функция getsпринимает в качестве своего аргумента массив символов, в который она и записывает считываемую из стандартного потока ввода строку. Концом ввода строки является  символ перенос строки ‘\n’, т.е. когда мы нажмем Enter на клавиатуре.   Этот символ последним считывается и при записи в массив заменяется  символом конца строки ’\0’.
Следующая программа читает введенную строку и выводит её на экран.
Листинг 14.7
#include <stdio.h> 
int main(){
      char str[17];
      gets(str);
      printf(«%s\n»,str);
      return(0); 
}
Результат работы программы, на следующем рисунке.
Рис. 6. Ввод строки с использованием функции gets()
Как видите, мы избавились от нашей проблемы. Но есть более важная проблема. Когда мы предоставляем пользователю вводить строку, мы не знаем, сколько он символов введет. Может так случиться, что мы объявили массив на 10 элементов, а пользователь ввел 30. Тогда возникнет ошибка – переполнение буфера. Поэтому использовать эту функцию использовать нужно очень осторожно, либо не использовать вообще. А что же тогда использовать?
Функция fgets().
 Сразу рассмотрим пример её использования.
Листинг 14.8
#include <stdio.h>
int main(){
      char str[10];
      fgets(str,10,stdin);
      printf(«%s\n»,str);
      return(0); 
}
Функция принимает три аргумента.
  1. Массив символов, в который необходимо записать  вводимую строку.
  2. Количество символов, которые может считать функция с учетом символа конца строки. В нашем случае это 10, т.е. рабочих из них девять, и один зарезервирован для конца строки.
  3. Откуда читать данные. В нашем случае указан стандартный поток ввода.
Попробуем в нашей программе Листинг 14.8 ввести нашу строку Hello world. В ней 12 символов.
Результат выполнения.
Рис.7. Ввод с помощью функции fgets().
Как видите, даже если мы введем больше, то функция считает только определенное ей количество символов. Не больше.
Есть еще одно отличие. Функция gets() глотала наш перенос строки, превращая его в символ конца строки. А вот функция fgets() его не «проглатывает». Введем, какую-нибудь строку меньше 10 символов. И посмотрим что будет.
Рис.8. Иллюстрация особенностей ввода функции fgets().
Как видите, получилось два переноса строки. Один из самой строки, другой из-за формат строки вывода.  
С вводом разобрались. Теперь поколдуем над выводом. Кроме стандартного printf() есть еще несколько функций. По аналогии с функциями ввода.
Функции puts(), fputs().
Синтаксис будет понятен из следующего примера
Листинг 14.9
#include <stdio.h> 
int main(){
      char str[12];
      fgets(str,12,stdin);
      puts(str);
      fputs(str, stdout);
      return(0); 
}
Результат выполнения это программы:
Рис.9. Использование стандартных функций вывода строки puts(), fputs(). Особенности вывода.
Как видите, функция puts является обратной к функции gets(). Она выводит строку заменяя символ конца строки на символ переноса строки. И поэтому то, что выводи функция fputs() оказывается на новой строке. А вот функция fputs()дополнительного переноса строки не делает. 
На этом на сегодня всё. На следующем уроке будем разбирать стандартные функции, которые работают со строками.

Задания для самостоятельной практической работы.

  •  На вход программе подается строка, длинной не более 100 символов. Напишите программу, которая определяет длину этой строки, без учета нулевого символа.
  • Напишите программу, которая переводит данную строку в нижний регистр. Т.е. и строки «Hello WorlD» должна получиться строка «hello world»
  • На вход программе подается строка, длинной не более 100 символов. Определить, является ли она перевертышем. Например, как слово «шалаш» или «топот». Учтите что строка может содержать пробелы, их учитывать не нужно. Например, строка «А роза упала на лапу Азора» будет являться перевертышем.
  • Пользователь вводит две строки. Необходимо сравнить их между собой, и вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать не нужно. Т.е строки «Hello WorlD» и «hello world» считаются двумя одинаковыми строками.
  • Напишите программу, которая читает из файла строку, длинной не более 200 символов. И считает количество вхождения в строку всех используемых в ней символов,без учета регистра. На вход поступает строка состоящая из букв латинского алфавита и пробелов. Программа должна вывести в первой строке длину введенной строки. В следующих строках встречаемые символы и их количество. Например, для строки «hello world», вывод будет следующим.

11
d — 1
e — 1

h — 1
l — 3
o — 2
r — 1
w — 1
probel — 1

  • Капитан Флинт зарыл клад на Острове сокровищ. Есть описание, как найти клад. Описание состоит из строк вида: «North 5», где первое слово – одно из «North», «South», «East», «West», а второе целое число – количество шагов, необходимое пройти в этом направлении. Напишите программу, которая по описанию пути к кладу определяет точные координаты клада, считая, что начало координат находится в начале пути, ось OX направлена на восток, ось OY – на север. На вход подается последовательность строк указанного формата. На выходе программа должна вывести координаты клада – два целых числа через пробел

Например:
Вход:

North 5
East 3
South 1
Выход: 3 4.

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

От KaDeaT