Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Материалы для подготовки к экзамену по ОП.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
297.52 Кб
Скачать

Чтение строк

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

#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 если первое слово больше второго в лексикографическом порядке

2 если второе слово больше

*/

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();

}

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

Указатели

Это, пожалуй, самая сложная и самая важная тема во всём курсе. Без понимания указателей дальнейшее изучении си будет бессмысленным. Указатели – очень простая концепция, очень логичная, но требующая внимания к деталям.

Определение

Указатель – это переменная, которая хранит адрес области памяти. Указатель, как и переменная, имеет тип. Синтаксис определения указателей

<тип> *<имя>;

Например

float *a;

long long *b;

Два основных оператора для работы с указателями – это оператор & взятия адреса, и оператор * разыменования. Рассмотрим простой пример.

#include <conio.h>

#include <stdio.h>

void main() {

int A = 100;

int *p;

//Получаем адрес переменной A

p = &A;

//Выводим адрес переменной A

printf("%p\n", p);

//Выводим содержимое переменной A

printf("%d\n", *p);

//Меняем содержимое переменной A

*p = 200;

printf("%d\n", A);

printf("%d", *p);

getch();

}

Рассмотрим код внимательно, ещё раз

int A = 100;

Была объявлена переменная с именем A. Она располагается по какому-то адресу в памяти. По этому адресу хранится значение 100.

int *p;

Создали указатель типа int.

p = &A;

Теперь переменная p хранит адрес переменной A. Используя оператор * мы получаем доступ до содержимого переменной A.

Чтобы изменить содержимое, пишем

*p = 200;

После этого значение A также изменено, так как она указывает на ту же область памяти. Ничего сложного.

Теперь другой важный пример.

#include <conio.h>

#include <stdio.h>

void main() {

int A = 100;

int *a = &A;

double B = 2.3;

double *b = &B;

printf("%d\n", sizeof(A));

printf("%d\n", sizeof(a));

printf("%d\n", sizeof(B));

printf("%d\n", sizeof(b));

getch();

}

Будет выведено

4

4

8

4

Несмотря на то, что переменные имеют разный тип и размер, указатели на них имеют один размер. Действительно, если указатели хранят адреса, то они должны быть целочисленного типа. Так и есть, указатель сам по себе хранится в переменной типа size_t (а также ptrdiff_t), это тип, который ведёт себя как целочисленный, однако его размер зависит от разрядности системы. В большинстве случаев разницы между ними нет. Зачем тогда указателю нужен тип?