Использование символа NULL

Символьная информация и строки

Для символьных данных в C++ введен тип char. Для представления символьной информации используются символы, символьные переменные и текстовые константы.

 

Пример 63

const char c=’c’; /*символ – занимает один байт, его значение не меняется*/

char a,b; /*символьные переменные, занимают по одному байту, значения меняются*/

const char *s=“Пример строки\n” ; //текстовая константа

 

Строка в C++ – это массив символов, заканчивающийся нуль-символом – ‘\0’ (нуль-терминатором). По положению нуль-терминатора определяется фактическая длина строки (рис. 22). Количество элементов в таком массиве на 1 больше, чем изображение строки.

 

 

Рис. 22. Представление строки и символа

 

Символьная строка представляет собой массив символов, за которыми следует символ NULL ('\0'). При объявлении символьной строки объявляется массив типа char. Когда программа позднее присваивает символы строке, она отвечает за добавление символа NULL, который представляет конец строки.

Если используются строковые константы, заключенные в двойные кавычки, компилятор C++ автоматически добавляет символ NULL. Большинство функций C++ используют символ NULL для определения последнего символа строки.

1.2.1 Как 'А' отличается от "А"

При рассмотрении программ на C++ можно встретить символы, заключенные в одинарные кавычки (например, 'А') и символы, заключенные вдвойные кавычки ("А"). Символ внутри одинарных кавычек представляет собой символьную константу. Компилятор C++ выделяет только один байт памяти для хранения символьной константы. Однако символ в двойных кавычках представляет собой строковую константу — указанный символ и символ NULL (добавляемый компилятором). Таким образом, компилятор будет выделять два байта для символьной строки.

 

 

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

 

Пример 64

void main()

{

char s1[12]=“string1”;

int k=sizeof(s1);

cout<<s1<<”\t”<<k<<endl;

char s2[]=“string2”;

k=sizeof(s2);

cout<<s2<<“\t”<<k<<endl;

char s3[]={’s’,’t’,’r’,’i’,’n’,’g’,’3’}

k=sizeof(s3);

cout<<s3<<”\t”<<k<<endl;

char *s4=“string4”; //указатель на строку, ее нельзя изменить

k=sizeof(s4);

cout<<s4<<”\t”<<k<<endl;

}

Результаты:

string1 10 – выделено 10 байтов, в том числе под \0

string2 8 – выделено 8 байтов (7+1байт под \0)

string3 8 – выделено 8 байтов (7+1байт под \0)

string4 4 – размер указателя

 

Если количество символов, присваиваемое строке, меньше размера массива, большинство компиляторов C++ будут присваивать символы NULL остающимся элементам строкового массива. Как и в случае с массивами других типов, если не указан размер массива, который инициализируется при объявлении, компилятор C++ распределит достаточно памяти для размещения указанных букв и символа NULL:

 

Пример 65.

char *s=”String5”; // выделяется 8 байтов для строки

char*ss; // описан указатель

ss=”String6”; //память не выделяется, поэтому программа может закончиться аварийно.

char *sss=new char[12]; //выделяем динамическую память

strcpy(sss,”String7”); //копируем строку в память.

 

Для ввода и вывода символьных данных в библиотеке языка C определены следующие функции:

int getchar(void) – осуществляет вод одного символа их входного потока, при этом она возвращает один байт информации (символ) в виде значения типа int. Это сделано для распознавания ситуации, когда при чтении будет достигнут конец файла.

int putchar (int c) – помещает в стандартный выходной поток символ c.

char* gets(char*s) – считывает строку s из стандартного потока до появления символа ‘\n’, сам символ ‘\n’ в строку не заносится.

int puts(const char* s)записывает строку в стандартный поток, добавляя в конец строки символ ‘\n’, в случае удачного завершения возвращает значение больше или равное 0 и отрицательное значение (EOF=-1) в случае ошибки.

 

Пример 66

1. char s[20];

cin>>s; //ввод строки из стандартного потока

cout<<s; //вывод строки в стандартный поток

Результат работы программы:

При вводе строки “123 456 789”, чтение байтов осуществляется до первого пробела, т.е. в строку s занесется только первое слово строки “123/0”, следовательно, выведется: 123.

 

2. char s[20];

gets(s); //ввод строки из стандартного потока

puts(s); //вывод строки в стандартный поток

Результат работы программы:

При вводе строки “123 456 789”, чтение байтов осуществляется до символа ‘\n’, т.е. в s занесется строка”123 456 789\n\0”, при выводе строки функция puts возвращает еще один символ ‘\n’, следовательно, будет выведена строка “123 456 789\n\n”.

3. char s[20];

scanf(“%s”,s);/*ввод строки из стандартного потока*/

printf(“%s”,s); /*вывод строки в стандартный поток*/

Результат работы программы:

При вводе строки “123 456 789”, чтение байтов осуществляется до первого пробела, т.е. в строку s занесется только первое слово строки “123/0”, следовательно, выведется: 123. Т.к. s – имя массива, т.е. адрес его первого элемента, операция & в функции scanf не используется.

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

Таблица 18

Функции работы со строками

 

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

#include <stdio.h>

#include <string.h>

#include <conio.h>

void main()

{

char s[250] , //исходная строка

w[25], //слово

mas[12][25]; //массив слов

puts(“\nвведите строку”);

gets(s);

int k=0,t=0,i,len,j;

len=strlen(s);

while(t<len)

{//формируем слово до пробела

for(j=0,i=t;s[i]!=’‘;i++,j++) w[j]=s[i];

w[j]=’/0’; //формируем конец строки

strcpy(mas[k],w); //копируем слово в массив

k++; //увеличиваем счетчик слов

t=i+1; /*переходим к следующему слову в исходной строке*/

}

strcpy(s,””); //очищаем исходную строку

for(t=0;t<k;t++)

if(mas[t][0]<’0’&&mas[t][0]>’9’) //если первый символ не цифра

{

strcat(s,mas[t]);//копируем в строку слово

strcat(s,” “);//копируем в строку пробел

}

puts(s);//выводим результат

getch();

}

Пример 68. Сформировать динамический массив строк. Удалить из него строку с заданным номером.

#include <iostream.h>

#include <string.h>

#include <conio.h>

void main()

{

int n;

cout<<«\nN=?»;cin>>n;

char s[100];

char**matr=new char*[n];

for(int i=0;i<n;i++)

{

cout<<«\nS=?»;

cin>>s;

matr[i]=new char[strlen(s)];

strcpy(matr[i],s);

}

for(i=0;i<n;i++)

{

cout<<matr[i];

cout<<«\n»;

}

int k;

cout<<«\nK=?»;

cin>>k;

if(k>=n){cout<<«There is not such string\n»; return;}

char **temp=new char*[n-1];

int j=0;

for(i=0;i<n;i++)

if(i!=k)

{

temp[j]=new char[strlen(matr[i])];

strcpy(temp[j],matr[i]);

j++;

}

n--;

for(i=0;i<n;i++)

{

cout<<temp[i];

cout<<«\n»;

}

getch();

}

освоили следующие основные концепции:

1. Символьная строка представляет собой массив символов, завершающийся 0 (символом NULL).

2. Вы создаете символьную строку, объявляя массив типаchar.

3. Ваша программа ответственна за размещение символа NULL за последним символом строки.

4. Если программа использует строковые константы, заключенные в

5. двойные кавычки, компилятор C++ автоматически добавляет символ NULL.

6. C++ позволяет вам инициализировать строки при объявлении, указывая требуемые символы внутри двойных кавычек.

7. Большинство компиляторов C++ в своих библиотеках этапа выполнения обеспечивают широкий набор функций для манипулирования строками.

4.8. Функции в C++

С увеличением объема программы становится невозможно удерживать в памяти все детали. Чтобы уменьшить сложность программы, ее разбивают на части. В C++ задача может быть разделена на более простые подзадачи с помощью функций. Разделение задачи на функции также позволяет избежать избыточности кода, т.к. функцию записывают один раз, а вызывают многократно. Программу, которая содержит функции, легче отлаживать.

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