Строки
Определение строк
В языке программирования Си нет специального типы данных для представления строк, а используются массивы символов. Например, определим строку:
#include <stdio.h>
int main( void )
{
char message[] = "Hello";
printf( "message: %s \n", message);
return 0;
}
Строки определяются в двойных кавычках. Но стоит отметить, что кроме символов, заключеных в двойные кавычки, каждая строка в качестве завершающего символа содержит символ \0. Поэтому в строке "Hello" на самом деле будет не 5 символов, а 6. Фактически можно было бы написать:
char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
Строки можно объявлять не только как массив символов, но и как указатель на тип char.
char *hello = "Hello World!"; // указатель на char - фактически строка
Интернирование строк
Для простого чтения строк оба определения равнозначны, но если нужно менять строки в процессе выполнения программы, то определения с помощью указателя не позволит этого сделать. Это связано с тем, что для работы со строками применяется интернирование строк. В этом случае строки в виде строковых литералов сохраняются в приложении в секции .rodata (read-only data), которая предназначена для данных только для чтения.
Если строка была объявлена как массив, то для изменения можно использовать синтаксис и массива, и указателя.
#include <stdio.h>
int main( void )
{
char text[] = "Hello";
text[1] = 'a';
*text = 'B';
*(text+2) = 'b';
printf("%s\n", text);
return 0;
}
Ввод и вывод строк
Для ввода и вывод строк можно также использовать функции printf и scanf, указав соответствующие спецификаторы в параметре форматной строки:
char s[10];
scanf("%s",s);
printf("%s",s);
Для посимвольного ввода строки можно использовать функцию getchar():
char s[100], c;
int i=0;
while( (c=getchar())!='\n' ){
s[i++]=c;
}
s[i]='\0';
Обратите внимание на скобки внутри while. Считываем строку до первого символа «перенос строки» и заносим всё в массив. После окончания ввода нужно обязательно поставить признак конца строки \0.
Напечатать строку можно также с помощью функции посимвольного вывода putchar()
while( s[i] ){
putchar(s[i++]);
}
Библиотека string.h
Для работы со строками существует стандартная библиотека string.h. В ней реализовано много функций. Рассмотрим самые используемые из них.
Функция strlen(const char *cs)
возвращает длину строки (количество символов в строке).
#include <stdio.h>
#include <string.h>
int main(void)
{
char st[10] = "hello";
printf("Sizeof = %llu\n", sizeof(st));
printf("Strlen = %llu\n", strlen(st));
return 0;
}
В данном коде sizeof = 10, а strlen = 5.
Для сравнения строк нельзя использовать логические операции ==, != так как они сравнивают указатели на начало соответствующих строк, а не сами строки. Для работы со строками есть специальная функция int strcmp(const char *cs, const char *ct)
, которая сравнивает в лексикографическом порядке строку cs со строкой ct. Если строка cs меньше строки ct, возвращается значение < 0
, если строка cs больше строки ct, возвращается значение > 0
, а в случае равенства строк возвращается значение 0
. Пример работы функции:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *EQ = "equal to";
char *LS = "less";
char *GT = "greater than";
char *a = "abcde";
char *b = "xyz";
char *c = "abcd";
char *d = "xyz";
int res;
printf("A = %s\nB = %s\nC = %s\nD = %s\n\n", a, b, c, d);
printf("A is %s B\n",(res = strcmp(a, b)) == 0 ? EQ : res < 0 ? LS : GT);
printf("A is %s C\n",(res = strcmp(a, c)) == 0 ? EQ : res < 0 ? LS : GT);
printf("A is %s D\n",(res = strcmp(a, d)) == 0 ? EQ : res < 0 ? LS : GT);
printf("B is %s C\n",(res = strcmp(b, c)) == 0 ? EQ : res < 0 ? LS : GT);
printf("B is %s D\n",(res = strcmp(b, d)) == 0 ? EQ : res < 0 ? LS : GT);
printf("C is %s D\n",(res = strcmp(c, d)) == 0 ? EQ : res < 0 ? LS : GT);
return 0;
}
Для копирования строк существует функция char* strcpy(char *dst, const char *src)
, которая копирует строку src (включая \0) в расположение, указанное в dst. Функция возвращает указатель на первый символ строки ds. Пример:
#include <stdio.h>
char *strcpy (char *dst, char *src)
{
char *ptr = dst;
while(*dst++=*src++);
return ptr;
}
int main(int argc, char **argv)
{
char str1[]={"Hello!"};
char str2[]={"World!"};
printf("%s\n",strcpy(str2,str1));
printf("%s\n",str2);
return 0;
}
Для объединения двух строк в одну служит функция char *strcat(char *destination_str, const char *source_str)
. При этом первая строка должна быть достаточно большая, чтобы вместить вторую строку:
#include <stdio.h>
#include <string.h>
int main(void)
{
char destination[30] = "Hello ";
char source[30] = "METANIT.COM";
strcat(destination, source);
printf("%s\n", destination);
return 0;
}
Функция char *strstr(const char* string, const char* substring)
ищет подстроку substring в строке string и возвращает указатель на символ первого вхождения подстроки, то есть по сути адрес подстроки. Если от адреса первого символа строки вычесть адрес первого вхождения подстроки, то мы получим индекс подстроки в строке:
#include <stdio.h>
#include <string.h>
int main(void)
{
char text[20] = "Hello METANIT.COM!";
char substring[14] = "METANIT.COM";
char *substring_ptr = strstr(text, substring);
if(substring_ptr)
{
long position = substring_ptr - text;
printf("Substring index: %ld\n", position); // Substring index: 6
}
else // если подстрока не найдена
{
printf("Substring not found\n");
}
return 0;
}
Самостоятельная работа
Задачи
Задача 1
Посчитать количество слов в тексте, слова разделены одним или несколькими пробелами. Попробуйте решить данную задачу с использованием функции getchar()
Задача 2
Реализовать функцию, которая преобразует переданную строку в массив байт, возвращает количество байт int StrToHex(const char *str,char* Hex)
.