
- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор sizeof
- •Оператор «запятая»
- •Операторы [ ] u ()
- •Приоритеты в с
- •Выражения
- •Преобразование типов в выражениях
- •Принудительные преобразования
- •Пробелы и круглые скобки
- •Сокращенные операторы в с
- •Операторы управления программой
- •Истина и ложь в с
- •Операторы выбора
- •Вложенные if
- •Лесенка if-else-if
- •Оператор ?
- •Вложенные операторы switch
- •Вариации цикла for
- •Бесконечный цикл
- •Циклы for без тела
- •Метки и goto
- •Функции
- •Оператор return
- •Выход из функции
- •Возвращаемые значения
- •Значения, возвращаемые функцией main()
- •Правила видимости для функций
- •Аргументы функции
- •Передача по значению и передача по ссылке
- •Создание передачи по ссылке
- •Передача массивов в функции
- •Аргументы функции main()
- •Функции, возвращающие нецелые значения
- •Использование прототипов функции
- •Прототипы стандартных библиотечных функций
- •Создание прототипов функций, не имеющих параметров
- •Возврат указателей
- •Рекурсия
- •Сопоставление классического и современного объявления параметров
- •Указатели на функции
- •Особенности реализации
- •Параметризированные функции и функции общего назначения
- •Эффективность
- •Массивы
- •Одномерный массив
- •Создание указателя на массив
- •Передача одномерных массивов в функции
- •Двумерные массивы
- •Массивы строк
- •Многомерные массивы
- •Индексация с помощью указателей
- •Размещение массивов
- •Инициализация массива
- •Инициализация безразмерных массивов
- •Пример программы игры в крестики-нолики
- •Указатели
- •Указатели - это адреса
- •Переменные-указатели
- •Операторы для работы с указателями
- •Выражения с указателями
- •Присваивание указателей
- •Арифметические действия с указателями
- •Сравнение указателей
- •Динамическое выделение и указатели
- •Указатели на константы
- •Указатели на константы
- •Указатели на константы
- •Указатели и массивы
- •Указатели на символьные массивы
- •Массивы указателей
- •Указатели на указатели - многочисленное перенаправление
- •Инициализация указателей
- •Указатели на функции
- •Проблемы, связанные с указателями
- •Структуры, объединения и определяемые пользователем типы
- •Структуры
- •Доступ к членам структуры
- •Присваивание структур
- •Массивы структур
- •Программа инвентаризации
- •Передача структур в функции
- •Передача членов структур в функции
- •Передача всей структуры в функцию
- •Указатели на структуры
- •Объявление указателя на структуру
- •Использование указателей на структуру
- •Массивы и структуры в структурах
- •Битовые поля
- •Объединения
- •Перечисления
- •Использование sizeof для обеспечения переносимости
- •Ввод, вывод, потоки и файлы
- •Потоки и файлы
- •Текстовые потоки
- •Двоичные потоки
- •Консольный ввод/вывод
- •Чтение и запись символов
- •Чтение и запись строк: gets() и puts()
- •Форматированный консольный ввод/вывод
- •Печать символов
- •Вывод чисел
- •Вывод адресов
- •Спецификатор %n
- •Модификаторы формата
- •Спецификатор минимума ширины поля
- •Спецификатор точности
- •Выровненный вывод
- •Работа с другими типами данных
- •Модификаторы * u #
- •Спецификаторы формата
- •Ввод чисел
- •Ввод беззнаковых целых
- •Чтение отдельных символов с помощью scanf()
- •Чтение строк
- •Ввод адреса
- •Спецификатор %n
- •Использование множества сканирования
- •Пропуск нежелательных специальных символов
- •Обычные символы в управляющей строке
- •В scanf() следует передавать адреса
- •Модификаторы формата
- •Подавление ввода
- •Файловая система ansi с
- •Указатель на файл
- •Открытие файла
- •Запись символа
- •Чтение символа
- •Использование fopen(), getc(), putc() и fclose()
- •Использование feof()
- •Две расширенные функции: getw() и putw()
- •Работа со строками: fgets() и fputs()
- •Fseek() и произвольный доступ
- •Удаление файлов
- •Работа с консолью
- •Препроцессор и комментарии
- •Директивы условной компиляции
- •Использование defined
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Одномерный массив
Стандартный вид объявления одномерного массива следующий: тип имя_переменной [размер];
В С массивы должны определяться однозначно, чтобы компилятор мог выделить для них место в памяти. Здесь тип объявляет базовый тип массива и является типом каждого элемента массива. Параметр размер определяет, сколько элементов содержит массив. В одномерном массиве полный размер массива в байтах вычисляется следующим образом: общее число байт = sizeof (базовый тип) *число элементов
У всех массивов первый элемент имеет индекс 0. Поэтому, если написать char р [10]; то будет объявлен массив символов из 10 элементов, причем эти элементы адресуются индексом от 0 до 9. Следующая программа загружает целочисленный массив числами от 0 до 9 и выводит его: #include <stdio.h> int main(void) { int x[10]; /* резервирует место для 10 целочисленных элементов */ int t; for(t=0; t<10; ++t) x[t] = t; for(t=0; t<10; ++t) printf("%d ", x[t]); return 0; }
В С отсутствует проверка границ массивов. Можно выйти за один конец массива и записать значение в какую-либо переменную, не относящуюся к массиву, или даже в код программы. Работа по предоставлению проверки границ возлагается на программиста. Например, следует убедиться, что массив символов, куда осуществляется ввод, имеет достаточную длину для принятия самой длинной последовательности символов.
Одномерные массивы это на самом деле списки информации одного типа. Например, таблица. показывает, как массив а располагается в памяти, если он начинается с адреса 1000 и объявлен следующим образом: char а [7];
Таблица. Массив символов, включающий семь элементов и начинающийся по адресу 1000 |
||||||
a[0] |
a[1] |
a[2] |
a[3] |
a[4] |
a[5] |
a[6] |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
Создание указателя на массив
Можно создать указатель на первый элемент массива, указав имя массива без индекса. Пусть имеется int sample [10]; Можно создать указатель на первый элемент, используя имя sample. Следовательно, следующий фрагмент присваивает переменной р адрес первого элемента sample: int *р; int sample[10]; р = sample; Можно также получить адрес первого элемента массива с помощью оператора &. Например, sample и &sample[0] приводят к одинаковому результату. Тем не менее в профессиональных программах нет почти нигде &sample[0].
Передача одномерных массивов в функции
При передаче одномерных массивов в функции следует вызывать функцию с именем массива без индекса. В результате этого передается адрес первого элемента массива. В С невозможно передать весь массив как аргумент. Вместо этого автоматически передается указатель. Следующий пример передает адрес i в func1(); int main(void) { int i(10); func1(i); ... }
Если функция получает одномерный массив, то можно объявить формальный параметр как указатель, как массив с фиксированной длиной или как безразмерный массив. Например, для передачи i в функцию func1() можно объявить func1() одним из следующих способов: void fun1 (int *a) /* указатель */ { ... } или void fun1(int a[10]) /* массив с фиксированной длиной */ { ... } или void fun1(int a []) /* безразмерный массив */ { ... }
Все три способа объявления сообщают компилятору, что предполагается получение указателя на целое, В первом объявлении используется указатель. Во втором - стандартный способ объявления массива. В третьем - модифицированная версия объявления массива, указывающая на то, что предполагается получение массива типа int некоторой длины. Не имеет значения длина передаваемого массива, поскольку С не выполняет проверку выхода за границы массива. Фактически void fund1(int а[32]) { ... } также будет работать, поскольку компилятор создает код, указывающий func1() о получении указателя (на самом деле не создается 32-элементный массив).
Строки
Наиболее типичным использованием одномерного массива являются строки. Хотя С не определяет строкового типа, имеется поддержка строковых операций с помощью функций, имеющихся в любом языке. В С строка определяется как символьный массив произвольной длины, оканчивающийся нулевым символом. Нулевой символ определяется как '\0'. Поэтому необходимо объявлять символьные массивы на один символ больше, чем требуется для хранения самой длинной строки. Например, если необходимо объявить массив s, содержащий десятисимвольную строку, следует написать: char s [11]; В результате этого выделяется место в конце строки для нулевого символа.
Хотя С не имеет строкового типа данных, имеются строковые константы. Строковые константы -это список символов, заключенных в двойные кавычки. Ниже показаны две строковые константы: "hello there" "this is a test" He надо добавлять нулевой символ в конец строковой константы, поскольку компилятор С выполняет это автоматически.
С поддерживает множество функций для работы со строками. Наиболее типичными являются strcpy(), strcat(), strlen() и strcmp() со следующими прототипами: char *strcpy(char *s1, const char *s2); char *strcat(char *s1, const char *s2); size_t strlen(const char *s1); int strcmp(const char *s1, const char *s2);
Все функции используют заголовочный файл string.h. Функция strcpy() копирует строку, на которую указывает s2, в строку, на которую указывает s1. Функция возвращает s1. Функция strcat() выполняет конкатенацию строки, на которую указывает s2, и строки, на которую указывает s1. Она также возвращает s1. Функция strlen() возвращает длину строки, на которую указывает s1. (Тип данных size_t определяется, используя typedef как беззнаковое целое.) Функция strcmp() сравнивает s1 и s2. Она возвращает 0, если две строки эквивалентны, число большее 0 - если строка, на которую указывает s1, больше, чем строка, на которую указывает s2, и число меньшее 0 - если строка, на которую указывает s1, меньше, чем строка, на которую указывает s2. Все сравнения выполняются лексикографически (согласно порядку словаря). Следующая программа демонстрирует использование данных строковых функций: #include <string.h> #include <stdio.h> int main(void) { char s1[80], s2[80]; gets (s1); gets (s2); printf("lengths: %d %d\n", strlen(s1), strlen(s2)); if(!strcmp(s1, s2)) printf("The strings are equal\n"); strcat(s1, s2); printf("%s\n", s1); return 0; } Если при запуске программы ввести строки «hello» и «hello», в результате получится: length: 5 5 The strings are equal hellohello
Важно понять, что strcmp() возвращает ложь, если строки не равны. Поэтому можно использовать ! для инверсии состояния, как показано в данном примере.