Строки в си. Введение

Теги: Си строки. Char array.



Строки в си. Введение.

Это вводная статья по строкам в си. Более подробное описание и примеры будут, когда мы научимся работать с памятью и указателями. В компьютере все значения хранятся в виде чисел. И строки тоже, там нет никаких символов и букв. Срока представляет собой массив чисел. Каждое число соответствует определённому символу, который берётся из таблицы кодировки. При выводе на экран символ отображается определённым образом.
Для хранения строк используются массивы типа char. Ещё раз повторюсь – тип char – числовой, он хранит один байт данных. Но в соответствии с таблицей кодировки каждое из этих чисел связано с символом. И в обратную сторону – каждый символ определяется своим порядковым номером в таблице кодировки.
Например

#include <conio.h>
#include <stdio.h>
 
void main() {
    char c = 'A';
	int  i = 65;
	printf("display as char %c\n", c);
	printf("display as int %d\n", c);
	printf("display as char %c\n", i);
	printf("display as char %d\n", i);
	getch();
}

Мы создали две переменные, одна типа char, другая int. Литера 'A' имеет числовое значение 65. Это именно литера, а не строка, поэтому окружена одинарными кавычками. Мы можем вывести её на печать как букву

printf("display as char %c\n", c);

Тогда будет выведено
A
Если вывести её как число, то будет
65
Точно также можно поступить и с числом 65, которое хранится в переменной типа int.
Спецсимволы также имеют свой номер

#include <conio.h>
#include <stdio.h>
 
void main() {
    printf("%c", '\a');
	printf("%d", '\a');
	printf("%c", 7);
	getch();
}

Здесь будет сначала "выведен" звуковой сигнал, затем его числовое значение, затем опять звуковой сигнал.
Строка в си – это массив типа char, последний элемент которого хранит терминальный символ '\0'. Числовое значение этого символа 0, поэтому можно говорить, что массив оканчивается нулём.
Например

#include <conio.h>
#include <stdio.h>
 
void main() {
    char word[10];
	word[0] = 'A';
	word[1] = 'B';
	word[2] = 'C';
	word[3] = '\0';
	//word[3] = 0; эквивалентно
	printf("%s", word);
	getch();
}

Для вывода использовался ключ %s. При этом строка выводится до первого терминального символа, потому что функция printf не знает размер массива word.
Если в этом примере не поставить

word[3] = '\0';

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

#include <conio.h>
#include <stdio.h>
 
void main() {
    char word[10] = "ABC";
	char text[100] = {'H', 'E', 'L', 'L', 'O'};
	printf("%s\n", word);
	printf("%s", text);
	getch();
}

В данном случае всё корректно. Строка "ABC" заканчивается нулём, и ею мы инициализируем массив word. Строка text инициализируется побуквенно, все оставшиеся символы, как следует из главы про массивы, заполняются нулями.

Чтение строк

Для того, чтобы запросить у пользователя строку, необходимо создать буфер. Размер буфера должен быть выбран заранее, так, чтобы введённое слово в нём поместилось. При считывании строк есть опасность того, что пользователь введёт данных больше, чем позволяет буфер. Эти данные будут считаны и помещены в память, и затрут собой чужие значения. Таким образом можно провести атаку, записав нужные байты, в которых, к примеру, стоит переход на участок кода с вредоносной программой, или логгирование данных.

#include <conio.h>
#include <stdio.h>
 
void main() {
    char buffer[20];

	scanf("%19s", buffer);
	printf("%s", buffer);

	getch();
}

В данном случае количество введённых символов ограничено 19, а размер буфера на 1 больше, так как необходимо хранить терминальный символ. Напишем простую программу, которая запрашивает у пользователя строку и возвращает её длину.

#include <conio.h>
#include <stdio.h>
 
void main() {
    char buffer[128];
	unsigned len = 0;

	scanf("%127s", buffer);

	while (buffer[len] != '\0') {
		len++;
	}

	printf("length(%s) == %d", buffer, len);

	getch();
}

Так как числовое значение символа '\0' равно нулю, то можно записать

while (buffer[len] != 0) {
	len++;
}

Или, ещё короче

while (buffer[len]) {
	len++;
}

Теперь напишем программу, которая запрашивает у пользователя два слова и сравнивает их

#include <conio.h>
#include <stdio.h>
 
/*
Результатом сравнения будет число
0 если слова равны
1 если первое слово больше второго в лексикографическом порядке
-1 если второе слово больше
*/

void main() {
    char firstWord[128];	//Первое слово
	char secondWord[128];	//Второе слово
	unsigned i;				//Счётчик
	int cmpResult = 0;		//Результат сравнения

	scanf("%127s", firstWord);
	scanf("%127s", secondWord);

	for (i = 0; i < 128; i++) {
		if (firstWord[i] > secondWord[i]) {
			//Больше даже если второе слово уже закончилось, потому что
			//тогда оно заканчивается нулём
			cmpResult = 1;
			break;
		} else if (firstWord[i] < secondWord[i]) {
			cmpResult = -1;
			break;
		}
	}

	printf("%d", cmpResult);

	getch();
}

Так как каждая буква имеет числовое значение, то их можно сравнивать между собой как числа. Кроме того, обычно (но не всегда!) буквы в таблицах кодировок расположены по алфавиту. Поэтому сортировка по числовому значению также будет и сортировкой по алфавиту.

Q&A

Всё ещё не понятно? – пиши вопросы на ящик email
Многомерные массивы