Руководство по c с примечаниями

Руководство по языку программирования C++

Последнее обновление: 01.04.2023

  1. Глава 1. Введение в C++

    1. Язык программирования C++

    2. Первая программа на Windows. Компилятор g++

    3. Первая программа на Windows. Компилятор Clang

    4. Первая программа на Linux. Компилятор g++

    5. Первая программа на MacOS. Компилятор Clang

    6. Настройка параметров компиляции

    7. Локализация и кириллица в консоли

  2. Глава 2. Основы языка программирования C++

    1. Структура программы

    2. Переменные

    3. Типы данных

    4. Константы

    5. Ввод и вывод в консоли

    6. using. Подключение пространств имен и определение псевдонимов

    7. Арифметические операции

    8. Статическая типизация и преобразования типов

    9. Поразрядные операции

    10. Операции присваивания

    11. Условные выражения

    12. Конструкция if-else и тернарный оператор

    13. Конструкция switch

    14. Циклы

    15. Ссылки

    16. Массивы

    17. Многомерные массивы

    18. Массивы символов

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

  3. Глава 3. Указатели

    1. Что такое указатели

    2. Операции с указателями

    3. Арифметика указателей

    4. Константы и указатели

    5. Указатели и массивы

  4. Глава 4. Функции

    1. Определение и объявление функций

    2. Область видимости объектов

    3. Параметры функции

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

    5. Константные параметры

    6. Оператор return и возвращение результата

    7. Указатели в параметрах функции

    8. Массивы в параметрах функции

    9. Параметры функции main

    10. Возвращение указателей и ссылок

    11. Перегрузка функций

    12. Рекурсивные функции

    13. Рекурсия на примере быстрой сортировки

    14. Указатели на функции

    15. Указатели на функции как параметры

    16. Тип функции

    17. Указатель на функцию как возвращаемое значение

    18. Разделение программы на файлы

    19. Внешние объекты

  5. Глава 5. Динамическая память и smart-указатели

    1. Динамические объекты

    2. Динамические массивы

    3. unique_ptr<T>

    4. shared_ptr<T>

  6. Глава 6. Объектно-ориентированное программирование

    1. Определение классов

    2. Конструкторы и инициализация объектов

    3. Управление доступом. Инкапсуляция

    4. Объявление и определение функций класса

    5. Конструктор копирования

    6. Константные объекты и функции

    7. Ключевое слово this

    8. Дружественные функции и классы

    9. Статические члены класса

    10. Деструктор

    11. Структуры

    12. Перечисления

    13. Наследование

    14. Управление доступом в базовых и производных классах

    15. Скрытие функционала базового класса

    16. Множественное наследование

    17. Виртуальные функции и их переопределение

    18. Преобразование типов

    19. Динамическое преобразование

    20. Особенности динамического связывания

    21. Чистые виртуальные функции и абстрактные классы<

    22. Перегрузка операторов

    23. Операторы преобразования типов

    24. Оператор индексирования

    25. Переопределение оператора присваивания

    26. Пространства имен

    27. Вложенные классы

  7. Глава 7. Исключения

    1. Обработка исключений

    2. Вложенные try-catch

    3. Создание своих типов исключений

    4. Тип exception

    5. Типы исключений

  8. Глава 8. Шаблоны

    1. Шаблоны функций

    2. Шаблон класса

    3. Специализация шаблона класса

    4. Наследование и шаблоны классов

  9. Глава 9. Контейнеры

    1. Типы контейнеров

    2. Вектор

    3. Итераторы

    4. Операции с векторами

    5. Array

    6. List

    7. Forward_list

    8. Deque

    9. Стек std::stack

    10. Очередь std::queue

    11. Очередь приоритетов std::priority_queue

    12. Множества

    13. Словарь std::map

    14. Span

  10. Глава 10. Строки

    1. Определение строк

    2. Строки с поддержкой Unicode

    3. Преобразование типов и строки

    4. Сравнение строк

    5. Получение подстроки и проверка начала и конца строки

    6. Поиск подстроки

    7. Изменение строки

    8. Операции с символами

    9. Программа подсчета слов

    10. Тип std:string_view

  11. Глава 11. Семантика перемещения

    1. rvalue

    2. Конструктор перемещения

    3. Оператор присваивания с перемещением

    4. Роль noexcept при перемещении

  12. Глава 12. Объекты функций и лямбда-выражения

    1. Объекты функций

    2. Лямбда-выражения

    3. Захват внешних значений в лямбда-выражениях

    4. Шаблон std::function<>

  13. Глава 13. Алгоритмы и представления

    1. Минимальный и максимальный элементы

    2. Поиск элементов

    3. Копирование элементов

    4. Удаление элементов и идиома Remove-Erase Idiom

    5. Сортировка

    6. Представления. Фильтрация

    7. Проекция данных

    8. Пропуск элементов. drop_view и drop_while_view

    9. Извлечение диапазона элементов. take_view и take_while_view

    10. Цепочки представлений

  14. Глава 14. Ограничения шаблонов

    1. Оператор requires

    2. Концепты

    3. Выражение requires

    4. Ограничения типа для auto

  15. Глава 15. Потоки и система ввода-вывода

    1. Базовые типы для работы с потоками

    2. Файловые потоки. Открытие и закрытие

    3. Чтение и запись текстовых файлов

    4. Переопределение операторов ввода и вывода

  16. Глава 16. Стандартная библиотека C++

    1. Математические константы и операции

    2. Форматирование строк и функция format

    3. std::optional<T>

  17. Глава 17. Идиомы С++

    1. Управление ресурсами. Идиома RAII

    2. Идиома копирования и замены

    3. Идиома Move-and-Swap

  18. Глава 18. Среды разработки

    1. Первая программа в Visual Studio

    2. Первая программа в Qt Creator

  • Глава 1. Введение в С++
    • Язык программирования С++
    • Первая программа на Windows. Компилятор g++
    • Первая программа на Windows. Компилятор Clang
    • Первая программа на Linux. Компилятор g++
    • Первая программа на MacOS. Компилятор Clang
    • Настройка параметров компиляции
    • Локализация и кириллица в консоли
  • Глава 2. Основы языка программирования C++
    • Структура программы
    • Переменные
    • Типы данных
    • Константы
    • Ввод и вывод в консоли
    • using. Подключение пространств имен и определение псевдонимов
    • Арифметические операции
    • Статическая типизация и преобразования типов
    • Поразрядные операции
    • Операции присваивания
    • Условные выражения
    • Конструкция if-else и тернарный оператор
    • Конструкция switch-case
    • Циклы
    • Ссылки
    • Массивы
    • Многомерные массивы
    • Массивы символов
    • Введение в строки
  • Глава 3. Указатели
    • Что такое указатели
    • Операции с указателями
    • Арифметика указателей
    • Константы и указатели
    • Указатели и массивы
  • Глава 4. Функции
    • Определение и объявление функций
    • Область видимости объектов
    • Параметры функции
    • Передача аргументов по значению и по ссылке
    • Константные параметры
    • Оператор return и возвращение результата
    • Указатели в параметрах функции
    • Массивы в параметрах функции
    • Параметры функции main
    • Возвращение указателей и ссылок
    • Перегрузка функций
    • Рекурсивные функции
    • Рекурсия на примере быстрой сортировки
    • Указатели на функции
    • Указатели на функции как параметры
    • Тип функции
    • Указатель на функцию как возвращаемое значение
    • Разделение программы на файлы
    • Внешние объекты
  • Глава 5. Динамическая память и smart-указатели
    • Динамические объекты
    • Динамические массивы
    • unique_ptr<T>
    • shared_ptr<T>
  • Глава 6. Объектно-ориентированное программирование
    • Определение классов
    • Конструкторы и инициализация объектов
    • Управление доступом. Инкапсуляция
    • Объявление и определение функций класса
    • Конструктор копирования
    • Константные объекты и функции
    • Ключевое слово this
    • Дружественные функции и классы
    • Статические члены класса
    • Деструктор
    • Структуры
    • Перечисления
    • Наследование
    • Управление доступом в базовых и производных классах
    • Скрытие функционала базового класса
    • Множественное наследование
    • Виртуальные функции и их переопределение
    • Преобразование типов
    • Динамическое преобразование
    • Особенности динамического связывания
    • Чистые виртуальные функции и абстрактные классы
    • Перегрузка операторов
    • Операторы преобразования типов
    • Оператор индексирования
    • Переопределение оператора присваивания
    • Пространства имен
    • Вложенные классы
  • Глава 7. Исключения
    • Обработка исключений
    • Вложенные try-catch
    • Создание своих типов исключений
    • Тип exception
    • Типы исключений
  • Глава 8. Шаблоны
    • Шаблоны функций
    • Шаблон класса
    • Специализация шаблона класса
    • Наследование и шаблоны классов
  • Глава 9. Контейнеры
    • Типы контейнеров
    • Вектор
    • Итераторы
    • Операции с векторами
    • Array
    • List
    • Forward_list
    • Deque
    • Стек std::stack
    • Очередь std::queue
    • Очередь приоритетов std::priority_queue
    • Множества
    • Словарь std::map
    • Span
  • Глава 10. Строки
    • Определение строк
    • Строки с поддержкой Unicode
    • Преобразование типов и строки
    • Сравнение строк
    • Получение подстроки и проверка начала и конца строки
    • Поиск подстроки
    • Изменение строки
    • Операции с символами
    • Программа подсчета слов
    • Тип std:string_view
  • Глава 11. Семантика перемещения
    • rvalue
    • Конструктор перемещения
    • Оператор присваивания с перемещением
    • Роль noexcept при перемещении
  • Глава 12. Объекты функций и лямбда-выражения
    • Объекты функций
    • Лямбда-выражения
    • Захват внешних значений в лямбда-выражениях
    • Шаблон std::function<>
  • Глава 13. Алгоритмы и представления
    • Минимальный и максимальный элементы
    • Поиск элементов
    • Копирование элементов
    • Удаление элементов и идиома Remove-Erase Idiom
    • Сортировка
    • Представления. Фильтрация
    • Проекция данных
    • Пропуск элементов. drop_view и drop_while_view
    • Извлечение диапазона элементов. take_view и take_while_view
    • Цепочки представлений
  • Глава 14. Ограничения шаблонов
    • Оператор requires
    • Концепты
    • Выражение requires
    • Ограничения типа для auto
  • Глава 15. Потоки и система ввода-вывода
    • Базовые типы для работы с потоками
    • Файловые потоки. Открытие и закрытие
    • Чтение и запись текстовых файлов
    • Переопределение операторов ввода и вывода
  • Глава 16. Стандартная библиотека C++
    • Математические константы и операции
    • Форматирование строк и функция format
    • std::optional<T>
  • Глава 17. Идиомы C++
    • Управление ресурсами. Идиома RAII
    • Идиома копирования и замены
    • Идиома Move-and-Swap
  • Глава 18. Среды разработки
    • Первая программа в Visual Studio
    • Первая программа в Qt Creator

Помощь сайту

YooMoney:

410011174743222

Перевод на карту

Номер карты:

4048415020898850

Предисловие

Я несколько раз в своих комментариях ссылался на книгу Эндрю Таненбаума «Operating Systems Design and Implementation» на ее первое издание и на то, как в ней представлен язык Си. И эти комментарии всегда вызывали интерес. Я решил, что пришло время опубликовать перевод этого введения в язык Си. Оно по-прежнему актуально. Хотя наверняка найдутся и те, кто не слышал о языке программировании PL/1, а может даже и об операционной системе Minix.

Это описание интересно также и с исторической точки зрения и для понимания того, как далеко ушел язык Си с момента своего рождения и IT-отрасль в целом.

Хочу сразу оговориться, что мой второй язык французский:

image

Но это компенсируется 46-летним программистским стажем.
Итак, приступим, наступила очередь Эндрю Таненбаума.

Введение в язык Си (стр. 350 — 362)

Язык программирования Cи был создан Деннисом Ритчи из AT&T Bell Laboratories как язык программирования высокого уровня для разработки операционной системы UNIX. В настоящее время язык широко используется в различных областях. C особенно популярен у системных программистов, потому что позволяет писать программы просто и кратко.

Основной книгой, описывающая язык Cи, является книга Брайана Кернигана и Денниса Ритчи « Язык программирования Cи» (1978). Книги по языку Си писали Bolon (1986), Gehani (1984), Hancock and Krieger (1986), Harbison и Steele (1984) и многие другие.

В этом приложении мы попытаемся дать достаточно полное введение в Cи, так что те кто знаком с языками высокого уровня, такими как Pascal, PL/1 или Modula 2, смогут понять большую часть кода MINIX, приведенного в этой книге. Особенности Cи, которые не используются в MINIX, здесь не обсуждаются. Многочисленные тонкие моменты опущены. Акцент делается на чтении программ на Си, а не на написании кода.

А.1. Основы языка Си

Программа на Cи состоит из набора процедур (часто называемых функциями, даже если они не возвращают значений). Эти процедуры содержат объявления, операторы и другие элементы, которые вместе говорят компьютеру что надо делать. На рисунке A-1 показана небольшая процедура, в которой объявляются три целочисленные переменные и присваиваются им значения. Имя процедуры — main (главная). Процедура не имеет формальных параметров, на что указывает отсутствие каких-либо идентификаторов между скобками за именем процедуры. Тело процедуры заключено в фигурные скобки ( { } ). Этот пример показывает, что Cи имеет переменные, и что эти переменные должны быть объявлены до использования. Cи также имеет операторы, в этом примере это операторы присваивания. Все операторы должны заканчиваться точкой с запятой (в отличие от Паскаля, который использует двоеточия между операторами, а не после них).

Комментарии начинаются с символов « / *» и заканчивается символами «* /» и могут занимать несколько строк.

main ()      /* это комментарий */
{
     int i, j, k; 	         /* объявление 3 целочисленных переменных */
     i  =  10; 	        /* присвоить i значение 10 (десятичное число) */
     j  =  i + 015; 	/* присвоить j значение  i + 015 (восьмеричное число) */
     k = j * j + 0xFF;   /* установить k в j * j + 0xFF (шестнадцатеричное число) */
}
Рис. A-l. Пример процедуры в Си.

Процедура содержит три константы. Константа 10 в первом присваивании
это обычная десятичная константа. Константа 015 является восьмеричной константой
(равно 13 в десятичной системе счисления). Восьмеричные константы всегда начинаются с начального нуля. Константа 0xFF является шестнадцатеричной константой (равной 255 десятичной). Шестнадцатеричные константы всегда начинаются с 0x. Все три типа используются в Cи.

А.2. Основные типы данных

Cи имеет два основных типа данных (переменных): целое и символ, объявляемые как int и char, соответственно. Нет отдельной булевой переменной. В качестве булевой переменной используется переменная int. Если эта переменная содержит 0, то это означает ложь/false, а любое другое значение означает истина/true. Cи также имеет и типы с плавающей точкой, но MINIX не использует их.

К типу int можно применять «прилагательные» short, long или unsigned, которые определяют (зависящий от компилятора) диапазон значений. Большинство процессоров 8088 используют 16-битные целые числа для int и short int и 32-битные целые числа для long int. Целые числа без знака (unsigned int) на процессоре 8088 имеют диапазон от 0 до 65535, а не от -32768 до +32767, как это у обычных целых чисел (int). Символ занимает 8 бит.

Спецификатор register также допускается как для int, так и для char, и является подсказкой для компилятора, что объявленную переменную стоит поместить в регистр, чтобы программа работала быстрее.

Некоторые объявления показаны на рис. А — 2.

int i; 			         /* одно целое число */
short int z1, z2; 	        / *два коротких целых числа */
char c; 			/* один символ */
unsigned short int k; 	/* одно короткое целое без знака */
long flag_poll;	        /* 'int' может быть опущено */
register int r; 		/* переменная регистра */

Рис. А-2. Некоторые объявления.

Преобразование между типами разрешено. Например, оператор

flag_pole = i;

разрешен, даже если i имеет тип int, а flag_pole — long. Во многих случаях
необходимо или полезно принудительно проводить преобразования между типами данных. Для принудительного преобразования достаточно поставить целевой тип в скобках перед выражением для преобразования. Например:

р ( (long) i);

предписывает преобразовать целое число i в long перед передачей его в качестве параметра в процедуру p, которая ожидает именно параметр long.

При преобразовании между типами следует обратить внимание на знак.
При преобразовании символа в целое число некоторые компиляторы обрабатывают символы как знаковые, то есть от — 128 до +127, тогда как другие рассматривают их как
без знака, то есть от 0 до 255. В MINIX часто встречаются такие выражения, как

i = c & 0377;

которые преобразует с (символ) в целое число, а затем выполняет логическое И
(амперсанд) с восьмеричной константой 0377. В результате получается, что старшие 8 бит
устанавливаются в ноль, фактически заставляя рассматривать c как 8-битное число без знака, в диапазоне от 0 до 255.

А.3. Составные типы и указатели

В этом разделе мы рассмотрим четыре способа построения более сложных типов данных: массивы, структуры, объединения и указатели (arrays, structures, unions, and pointers). Массив — это коллекция/множество элементов одного типа. Все массивы в Cи начинаются с элемента 0.

Объявление

int a [10];

объявляет массив a с 10 целыми числами, которые будут хранится в элементах массива от [0] до a [9]. Второе, массивы могут быть трех и более измерений, но они не используются в MINIX.
Структура — это набор переменных, обычно разных типов. Структура в Cи похож на record в Паскале. Оператор

struct {int i; char c;} s;

объявляет s как структуру, содержащую два члена, целое число i и символ c.

Чтобы присвоить члену i структуры s значение 6, нужно записать следующее выражение:

s.i = 6;

где оператор точка указывает, что элемент i принадлежит структуре s.
Объединение — это также набор членов, аналогично структуре, за исключением того, что в любой момент в объединение может находится только один из них. Объявление

union {int i; char c;} u;

означает, что вы можете иметь целое число или символ, но никак не оба. Компилятор должен выделить достаточно места для объединения, чтобы в нем мог разместиться самый большой (с точки зрения занимаемой памяти) элемент объединения. Объединения используются только в двух местах в MINIX (для определения сообщения как объединения нескольких различных структур, и для определения дискового блока как объединения блока данных, блока i-узла, блока каталога и т. д.).

Указатели используются для хранения машинных адресов в Cи. Они используются очень и очень часто. Символ звездочка (*) используется для обозначения указателя в объявлениях. Объявление

int i, *pi, a [10], *b[10], **ppi;

объявляет целое число i, указатель на целое число pi, массив a из 10 элементов, массив b из 10 указателей на целые числа и указатель на указатель ppi на целое число.

Точные правила синтаксиса для сложных объявлений, объединяющих массивы, указатели и другие типы несколько сложны. К счастью, MINIX использует только простые объявления.

На рисунке A-3 показано объявление массива z структур struct table, каждая из которых имеет
три члена, целое число i, указатель cp на символ и символ с.

struct table {	/* каждая структура имеет тип таблицы */
      int i; 		/ *целое число */
      char *cp, c; 	/* указатель на символ и символ */
} z [20]; 		/* это массив из 20 структур */

Рис. А - 3. Массив структур.

Массивы структур распространены в MINIX. Далее, имя table можно объявить как структуру struct table, которую можно использовать в последующих объявлениях. Например,

register struct table *p;

объявляет p указателем на структуру struct table и предлагает сохранить ее
в register. Во время выполнения программы p может указывать, например, на z [4] или
на любой другой элемент в z, все 20 элементов которой являются структурами типа struct table.

Чтобы сделать p указателем на z [4], достаточно написать

p = &z[4];

где амперсанд в качестве унарного (монадического) оператора означает «взять адрес того, что за ним следует ». Скопировать в целочисленную переменную n значение члена i
структуры, на которую указывает указатель р, можно следующим образом:

n = p->i;

Обратите внимание, что стрелка используется для доступа к члену структуры через указатель. Если мы будем использовать переменную z, то тогда мы должны использовать оператор с точкой:

n = z [4] .i;

Разница в том, что z [4] является структурой, и оператор точки выбирает элементы
из составных типов (структуры, массивы) напрямую. С помощью указателей мы не выбираем участника напрямую. Указатель предписывает сначала выбрать структуру и только потом выбрать члена этой структуры.

Иногда удобно дать имя составному типу. Например:

typedef unsigned short int unshort;

определяет unshort как unsigned short (короткое целое число без знака). Теперь unshort может быть использован в программе как основной тип. Например,

unshort ul, *u2, u3[5];

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

А.4. Операторы

Процедуры в Cи содержат объявления и операторы. Мы уже видели объявления, так что теперь мы будем рассматривать операторы. Назначение условного оператора и операторов цикла по существу такие же, как и в других языках. Рисунок А – 4 показывает несколько примеров из них. Единственное, на что стоит обратить внимание, это то, что фигурные скобки используются для группировки операторов, а оператор while имеет две формы, вторая из которых похожа на оператор repeat Паскаля.

Cи также имеет оператор for, но он не похож на оператор for в любом другом языке. Оператор for имеет следующий вид:

for (<инициализация>; <условие>; <выражение>) оператор;

Тоже самое можно выразить через опертор while:

<инициализация>
while(<условие>) {
	<оператор>;
	<выражение>
} 

В качестве примера рассмотрим следующий оператор:

for (i=0; i <n; i = i+l) a[i]=0;

Этот оператор устанавливает первые n элементов массива a равными нулю. Выполнение оператора начинается с установки i в ноль (это делается вне цикла). Затем оператор повторяется до тех пор, пока i < n, выполняя при этом присваивание и увеличение i. Конечно, вместо оператора присвоения значения текущему элементу массива нуля может быть составной оператор (блок), заключенный в фигурные скобки.

if (x < 0) k = 3;        /* простое оператор if */

if (x > y) {	              /* составной оператор if */
     i = 2;
     k = j + l,
}

if (x + 2 <y) {          /* оператор if-else */
      j  = 2;
      k = j - 1;
} else {
      m = 0;
}

while (n > 0) {	      /* оператор while */
     k = k + k;
     n = n - l;
}

do {	         / * другой вид оператора while */
      k = k + k;
       n = n - 1;
} while (n >  0);

Рис. A-4. Примеры операторов if и while в Cи.

Си имеет также оператор аналогичный case-оператору в языке Pascal. Это switch-оператор. Пример представлен на рисунке А-5. В зависимости от значения выражения, указанного в switch, выбирается тот или иной оператор cаse.

Если выражение не соответствует ни одному из операторов case, то выбирается оператор по умолчанию (default).

Если выражение не связано ни с одним оператором case и оператор default отсутствует, то выполнение продолжается со следующего оператора после оператора switch.

Следует отметить, что для выхода из блока case следует использовать оператор break. Если оператор break отсутствует, то будет выполняться следующий блок case.

switch (k) {
      case 10:
            i = 6;
            break;  /* не выполнять case 20, т.е. завершить выполнение опертора switch */
      case 20:
             i = 2;
             k = 4;
             break;	/ * не выполнять default* /
      default:
            j = 5;
}

Рис. A-5. Пример оператора switch

Оператор break также действует внутри циклов for и while. При этом надо помнить, что если оператор break находится внутри серии вложенных циклов, выход осуществляется только на один уровень вверх.

Связанным оператором является оператор continue, который не выходит из цикла,
но вызывает завершение текущей итерации и начало следующей итерации
немедленно. По сути, это возврат к вершине цикла.

Cи имеет процедуры, которые могут вызываться с параметрами или без параметров.
Согласно Кернигану и Ричи (стр. 121), не разрешено передавать массивы,
структуры или процедуры в качестве параметров, хотя передача указателей на все это
допускается. Есть ли книга или нет ее (так и всплывет в памяти:- «Если жизнь на Марсе, нет ли жизни на Марсе»), многие компиляторы языка Си допускают структуры в качестве параметров.
Имя массива, если оно написано без индекса, означает указатель на массив, что упрощает передачу указателя массива. Таким образом, если a является именем массива любого типа, его можно передать в процедуру g, написав

g(а);

Это правило действует только для массивов, на структуры это правило не распространяется.
Процедуры могут возвращать значения, выполняя оператор return. Этот оператор может содержать выражение, результат выполнения которого будет возвращено в качестве значения процедуры, но вызвавшая процедура может смело игнорировать возвращаемое значение. Если процедура возвращает значение, то тип значение записывается перед именем процедуры, как показано на рис. A-6. Аналогично параметрам, процедуры не могут возвращать массивы, структуры или процедуры, но могут вернуть указатели на них. Это правило разработано для более эффективной реализации — все параметры и результаты всегда соответствуют одному машинному слову (в котором хранится адрес). Компиляторы, которые допускают использование структур в качестве параметров, обычно также допускают их использование в качестве возвращаемых значений.

int sum (i, j)        /* эта процедура возвращает целое число */
int i, j ; 	          /*объявление формальных параметров */
{
      return (i + j);       /* добавить параметры и вернуть сумму */
}

Рис. А-6. Пример простой процедуры, которая возвращает значение.

C не имеет встроенных операторов ввода / вывода. Ввод/вывод реализуется путем вызова библиотечных функций, наиболее распространенные из которых проиллюстрированы ниже:

printf («x=% d y = %o z = %x n», x, y, z);

Первый параметр — это строка символов между кавычками (на самом деле это массив символов).

Любой символ, который не является процентом, просто печатается как есть.

Когда встречается процент, печатается следующий параметр в виде, определяемом буквой, следующей за процентом:

d — вывести в виде десятичного целого числа
o — печатать как восьмеричное целое
u — печатать как беззнаковое десятичное целое
x — печатать как шестнадцатеричное целое
s — печатать как строку символов
c — печатать как один символ

Также допускаются буквы D, 0 и X для десятичной, восьмеричной и шестнадцатеричной печати длинных чисел.

А.5. Выражения

Выражения создаются путем объединения операндов и операторов.

Арифметические операторы, такие как + и -, и реляционные операторы, такие как <
и > похожи на своих аналогов в других языках. Оператор %
используется по модулю. Стоит отметить, что оператор равенства это ==, а оператор неравенства это! =. Чтобы проверить равны ли a и b, можно написать так:

if (a == b) <оператор>;

Си также позволяет объединять оператор присваивания с другими операторами, поэтому

a +=  4;

эквивалентно записи

а = а + 4;

Другие операторы также могут быть объединены таким образом.

Си имеет операторы для манипулирования битами слова. Разрешены как сдвиги, так и побитовые логические операции. Операторы сдвига влево и вправо являются <<
и >> соответственно. Побитовые логические операторы &, | и ^, которые являются логическим И (AND), включающим ИЛИ (OR) и исключающим ИЛИ (XOP) соответственно. Если i имеет значение 035 (восьмеричное), тогда выражение i & 06 имеет значение 04 (восьмеричное). Еще один пример, если i = 7, то

j = (i << 3) | 014;

и получим 074 для j.
Другой важной группой операторов являются унарные операторы, каждый из которых принимает только один операнд. Как унарный оператор, амперсанд & получает адрес переменной.

Если p является указателем на целое число, а i является целым числом, оператор

p = &i;

вычисляет адрес i и сохраняет его в переменной p.
Противоположным взятию адреса является оператор, который принимает указатель в качестве входных данных и вычисляет значение, находящееся по этому адресу. Если мы только что присвоили адрес i указателю p, тогда *p имеет то же значение, что и i.

Другими словами, в качестве унарного оператора за звездочкой следует указатель (или
выражение, дающее указатель), и возвращает значение элемента, на который указывает. Если i имеет значение 6, то оператор

j = *р;

присвоит j число 6.
Оператор! (восклицательный знак – оператор отрицания) возвращает 0, если его операнд отличен от нуля, и 1, если его оператор равен 0.

Он в основном используется в операторах if, например

if (!x) k=0;

проверяет значение х. Если x равен нулю (false), то k присваивается значение 0. В действительности, оператор! отменяет условие, следующее за ним, так же, как оператор not в Паскаль.

Оператор ~ является побитовым оператором дополнения. Каждый 0 в своем операнде
становится 1, а каждый 1 становится 0.

Оператор sizeof сообщает размер его операнда в байтах. Применительно к
массиву из 20 целых чисел a на компьютере с 2-байтовыми целыми числами, например sizeof a будет иметь значение 40.

Последняя группа операторов — это операторы увеличения и уменьшения.

Оператор

р++;

означает увеличение р. На сколько увеличится p, зависит от его типа.
Целые числа или символы увеличиваются на 1, но указатели увеличиваются на
размер объекта, на который указывает Таким образом, если а является массивом структур, а р указатель на одну из этих структур, и мы пишем

p = &a[3];

чтобы заставить p указать на одну из структур в массиве, то после увеличения p
будет указывать на a[4] независимо от того, насколько велики структуры. Оператор

p--;

аналогичен оператору p++, за исключением того, что он уменьшает, а не увеличивает значение операнда.

В операторе

n = k++;

где обе переменные являются целыми числами, исходное значение k присваивается n и
только после этого происходит увеличение k. В операторе

n = ++ k;

сначала увеличивается k, затем его новое значение сохраняется в n.

Таким образом, ++ (или —) оператор может быть записан до или после его операнда, что приводит к получению различных значений.

Последний оператор – это? (знак вопроса), который выбирает одну из двух альтернатив
разделеных двоеточием. Например, оператор,

i = (x < y ? 6 : k + 1);

сравнивает х с у. Если x меньше y, тогда i получает значение 6; в противном случае переменная i получает значение k + 1. Скобки не обязательны.

А.6. Структура программы

Программа на С состоит из одного или нескольких файлов, содержащих процедуры и объявления.
Эти файлы могут быть скомпилированы по отдельности в объектные файлы, которые затем линкуются друг с другом (с помощью компоновщика) для формирования исполняемой программы.
В отличие от Паскаля, объявления процедур не могут быть вложенными, поэтому все они записываются на «верхнем уровне» в файле программы.

Допускается объявлять переменные вне процедур, например, в начале файла перед первым объявлением процедуры. Эти переменные являются глобальными, и могут использоваться в любой процедуре во всей программе, если только ключевое слово static не предшествует объявлению. В этом случае эти переменные нельзя использовать в другом файле. Те же правила применяются к процедурам. Переменные, объявленные внутри процедуры, являются локальными для процедуры.
Процедура может обращаться к целочисленной переменной v, объявленной в другом файле (при условии, что переменная не является статической), объявляя ее у себя внешней:

extern int v;

Каждая глобальная переменная должна быть объявленным ровно один раз без атрибута extern, чтобы выделить память под нее.

Переменные могут быть инициализированы при объявлении:

int size = 100;

Массивы и структуры также могут быть инициализированы. Глобальные переменные, которые не инициализированы явно, получают значение по умолчанию, равное нулю.

А.7. Препроцессор Cи

Прежде чем исходный файл будет передан компилятору Cи, он автоматически обрабатывается
программой под названием препроцессор. Именно выход препроцессора, а не
оригинальная программа, подается на вход компилятора. Препроцессор выполняет
три основных преобразования в файле перед передачей его компилятору:

1. Включение файлов.
2. Определение и замена макросов.
3. Условная компиляция.

Все директивы препроцессора начинаются со знака числа (#) в 1-ом столбце.
Когда директива вида

#include  "prog.h"

встречается препроцессором, он включает файл prog.h, строка за строкой, в
программу, которая будет передана компилятору. Когда директива #include написана как

#include <prog.h>

то включаемый файл ищется в каталоге /usr/include вместо рабочего каталога. В Cи распространена практика группировать объявления, используемые несколькими файлами, в заголовочном файле (обычно с суффиксом .h), и включать их там, где они необходимы.
Препроцессор также позволяет определения макросов. Например,

#define BLOCK_SIZE 1024

определяет макрос BLOCK_SIZE и присваивает ему значение 1024. С этого момента
каждое вхождение строки из 10 символов «BLOCK_SIZE» в файле будет
заменяться 4-символьной строкой «1024» до того, как компилятор увидит файл с программой. По соглашению имена макросов пишутся в верхнем регистре. Макросы могут иметь параметры, но на практике немногие это делают.

Третья особенность препроцессора — условная компиляция. В MINIX есть несколько
мест, где код написан специально для процессора 8088, и этот код не должен включаться при компиляции для другого процессора. Эти разделы выглядят как так:

#ifdef i8088
      <объявления только для 8088>
#endif

Если символ i8088 определен, то операторы между двумя директивами препроцессора #ifdef i8088 и #endif включаются в выходные данные препроцессора; в противном случае они пропускаются. Вызывая компилятор с командой

cc -c -Di8088 prog.c

или включив в программу заявление

#define i8088

мы определяем символ i8088, поэтому весь зависимый код для 8088 быть включен. По мере развития MINIX он может приобрести специальный код для 68000s и других процессоров, которые будут обрабатываться также.

В качестве примера того, как работает препроцессор, рассмотрим программу рис. A-7 (a). Она включает в себя один файл prog.h, содержимое которого выглядит следующим образом:

int x;
#define MAXAELEMENTS 100

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

cc  -E  -Di8088 prog.c

После того, как файл прошел через препроцессор, вывод будет таким, как показано на Рис. A-7 (b).

Именно этот вывод, а не исходный файл, дается как вход в Cи компилятор.

#include prog.h 			        int x;
main ()						main ();
{						{
      int a[MAX_ELEMENTS]; 			   int a [100];
      х = 4;					   х = 4;
      a[x] = 6; 				   а[х] = 6;
#ifdef i8088 					   printf("8088. a[x]:% dn", a[x]);
      printf ("8088. a[x]:% dn", a[x]);
#endif						}

#ifdef m68000
      printf ("68000. x=%dn", x);
#endif
}
            (а) 				     (b)

Рис. А-7. (a) Содержание файла prog.c. (b) Выход препроцессора.

Обратите внимание, что препроцессор выполнил свою работу и удалил все строки, начинающиеся со знаком #. Если компилятор был бы вызван так

cc -c  -Dm68000 prog.c

то была бы включена другая печать. Если бы он был вызван вот так:

cc -c prog.c

то ни одна печать не была бы включена. (Читатель может поразмышлять о том, что случилось бы, если бы компилятор вызывался с обоими флагами -Dflags.)

А.8. Идиомы

В этом разделе мы рассмотрим несколько конструкций, которые характерны для Cи, но не распространены в других языках программирования. Для начала рассмотрим петлю:

while (n--) *p++  =  *q++;

Переменные p и q обычно являются символьными указателями, а n является счетчиком. Цикл копирует n-символьную строку из места, на которое указывает q, в место, на которое указывает р. На каждой итерации цикла счетчик уменьшается, пока он не доходит до 0, и каждый из указателей увеличивается, поэтому они последовательно указывают на ячейки памяти с более высоким номером.

Еще одна распространенная конструкция:

for (i = 0; i < N; i++) a[i] = 0;

которая устанавливает первые N элементов а в 0. Альтернативный способ написания этого цикла выглядит так:

for (p = &a[0]; p < &a[N]; p++) *p = 0;

В этой формулировке целочисленный указатель p инициализируется так, чтобы указывать на нулевой элемент массива. Цикл продолжается до тех пор, пока p не достиг адреса N-ого элемента массива. Конструкция указателя гораздо эффективнее, чем конструкция массива, и поэтому обычно используют ее.

Операторы присвоения могут появляться в неожиданных местах. Например,

if (a = f (x))  < оператор >;

сначала вызывает функцию f, затем присваивает результат вызова функции a и
наконец, проверяет, является ли оно истинным (ненулевым) или ложным (нулевым). Если а не равно нулю, то условие выполнено. Оператор

if (a = b) < оператор >;

также сначало значение переменной b переменной a, а затем проверяет a, не является ли значение ненулевым. И этот оператор полностью отличается от

if (a == b)  < оператор >;

который сравнивает две переменные и выполняет оператор, если они равны.

Послесловие

Вот и все. Вы не поверите, какое я получил огромное удовольствие, готовя этот текст. Как много я вспомнил полезного из того же языка Си. Надеюсь, вы тоже с удовольствием окунетесь в прекрасный мир языка Си.

What is C:

  • In 1972, a great computer scientist Dennis Ritchie created a new programming language called C at Bell laboratories.
  • It was created from ALGOL, BCL, and B programming language.
  • It contains all the features of these languages and many more additional concepts that make it unique from other programming languages.
  • It is a powerful programming language that is strongly associated with the UNIX operating system and most of the UNIX operating systems are coded in C Language.
  • Initially, it was limited to the UNIX operating system, but as it started spreading around the world, it became commercial, and many compilers were released for cross-platform systems.
  • Today C runs under a variety of operating systems and hardware platforms.
  • As it started evolving many versions of the language were released.
  • At times, it became difficult for the developers to keep up with the latest version as the systems were running under the older versions.
  • To assure that C language will remain standard, American National Standards Institute (ANSI) defined a commercial standard for C language in 1989.
  • Later, it was approved by the International Standards Organization (ISO) in 1990. The C programming language is also called ANSI C.

Applications of C:

  • It is widely used for developing desktop applications and for developing browsers and their extensions.
  • Google’s Chromium is built using a C programming language.
  • It is widely used in embedded systems.
  • It is used to develop databases. MySQL is the most popular database software which is built using C.
  • It is used in developing an operating system such as Apple’s OS X, Microsoft’s Windows, and Symbian are developed using the C language.
  • It is used for developing desktop as well as mobile phone’s operating system.
  • It is used for compiler production.
  • It is widely used in IoT applications.

Features of C:

  • C is a structured programming language in which the program is divided into various modules.
  • C is a Procedural Oriented Programming Language.
  • C is a middle level language.
  • Each module can be written separately and together it forms a single C program. This structure makes it easy for testing, maintaining, and debugging processes.
  • C contains 32 keywords, various data types, and a set of powerful built-in functions that make programming very efficient.
  • C program contains various functions that are part of a library. Programmer can add their own features and functions to the library.
  • These functions are accessible and used anytime in the program. This feature makes it simple while working with complex programming.
  • It is a popular choice for system level apps.

Working of C:

  • C is a compiled language.
  • A compiler is a special tool that compiles the program and converts it into an object file that is machine-readable.
  • After the compilation process, the linker will combine different object files and creates a single executable file to run the program.
  • The following diagram shows the execution of a ‘C’ program:

Nowadays, various compilers are available online. The functionality will never differ and most of the compilers will provide the features required to execute both ‘C’ and ‘C++’ programs. Below is the name of such compilers:

  • Clang compiler
  • MinGW compiler (Minimalist GNU for Windows)
  • Portable C compiler
  • Turbo C

Program 1:
Below is the program in C to print Hello World:
 

C

#include <stdio.h>

void main()

{

    printf("Hello World");

    getch();

}

Output

Explanation:

  • Preprocessor directive 
    • #include is a preprocessor directive in C.
    • #include , stdio is the library where the function printf() is defined.
    • It is used for generating output. Before using this function, first include the required file, also known as a header file (.h).
  • Main function: The main function is a part of every C program. It can be represented in various form such as: 
    • main()
    • int main()
    • void main()
    • main(void)
    • void main(void)
    • int main(void)
  • The empty parentheses indicate that this function does not take any argument, value, or parameter.
  • The keyword void means the function does not return any value, in this case, the last statement is always getch().

Program 2:
Below is the C program printing “Hello World”:
 

C

#include <stdio.h>

int main()

{

    printf("Hello World");

    return 0;

}

Explanation:

  • In the above example, the keyword int means the function will return an integer value. In this case, the last statement should always return 0.
  • In the source code, after the main function has been declared, specify the opening and closing parentheses. Curly brackets { }, indicate the starting and end of a program.
  • These brackets must be always put after the main function.
  • All the program code is written inside these brackets, such as declarative and executable parts.
  • The printf function generates the output and “Hello World” gets displayed on the console.
  • The semicolon ; determines the end of the statement. In C, each statement must end with a semicolon.

Steps to run C program in CodeBlocks:
 

  • Create a new project as shown below: 
     

  • In the pop-up, firstly select the file, then choose the “C/C++ Source” and click “Go” as shown below: 
     

  • Continue by clicking on, “next”. 
     

  • To create the new file, select a “C” file then click on the “Next” button to continue. 
     

  • Set the file path by clicking the “…” button, the explorer window permits the creation of the C file. 
     

  • Select the path of your new C file then its name which has a .c extension and save it. 
     

  • Finally, to confirm the C file creation click “Finish”. 
     

  • Enter the code, save it and compile it by clicking on the “Build & Run “button.
     

Comments and its types in C program:

Comment: A comment is an explanation or description of the source code of the program. It helps a developer explain the logic of the code and improves program readability. At run-time, a comment is ignored by the compiler.

Types of Comments: 

  1. Single line comment: Single-line Comments which uses a double slash // dedicated to comment single lines
  2. Multi-line comment: A comment that starts with a slash asterisk /* and finishes with an asterisk slash */ and it can place it anywhere in your code, on the same line or several lines.

Program 1:

Below is the C program illustrating the use of single-line comment:

C

#include <stdio.h>

int main(void)

{

    printf("Geeks for Geeks");

    return 0;

}

Program 2:

Below is the C program illustrating the use of multi-line comment:

C

#include <stdio.h>

int main()

{

    int x = 42;

    printf("%d", x);

    return 0;

}

Need for comments:

  1. A good programmer who writes codes understood by a human is better than a programmer who generates codes understood only by the machine.
  2. So, it is highly recommended to insert comments into the code because it is good programming practice.
  3. Comments do not affect a program because the compiler ignores them.
  4. Comments help the developer understand the logic/algorithm of the code if revisits it after a long time.

Character Set:

  • Like every other language, ‘C’ also has its own character set.
  • A program is a set of instructions that, when executed, generate an output.
  • The data that is processed by a program consists of various characters and symbols.
  • The output generated is also a combination of characters and symbols.

A compiler always ignores the use of characters, but it is widely used for formatting the data. Following is the character set in ‘C’ programming. A character set in C is divided into the following types:
 

A compiler always ignores the use of characters, but it is widely used for formatting the data. Following is the character set in ‘C’ programming:

  • Letters: All the lowercase and uppercase characters from A to Z.
  • Numbers: All the digits from 0 to 9.
  • White spaces: Such as Blank space, Newline, Carriage return, and Horizontal tab.
  • Special Characters

Token:

  • Token is the smallest unit in a ‘C’ program.
  • It is each and every word and punctuation that you come across in the C program.
  • The compiler breaks a program into the smallest possible units (tokens) and proceeds to the various stages of the compilation.
  • A token is divided into six different types, viz, Keywords, Operators, Strings, Constants, Special Characters, and Identifiers.
     

Keywords and Identifiers:

In ‘C’ every word can be either a keyword or an identifier.

  • Keywords have fixed meanings, and the meaning cannot be changed. They act as a building block of a ‘C’ program. There are a total of 32 keywords in ‘C’. Keywords are written in lowercase letters.
  • An identifier is nothing but a name assigned to an element in a program.
    • Example: name of a variable, function, etc.
    • Identifiers are the user-defined names consisting of the ‘C’ standard character set.
    • As the name says, identifiers are used to identify a particular element in a program.
    • Each identifier must have a unique name.
    • Following rules must be followed for identifiers:
      • The first character must always be an alphabet or an underscore.
      • It should be formed using only letters, numbers, or underscore.
      • A keyword cannot be used as an identifier.
      • It should not contain any white space character.
      • The name must be meaningful.
         

Summary:

  • A token is the smallest unit in a program.
  • A keyword is reserved words by language.
  • There is a total of 32 keywords.
  • An identifier is used to identify elements of a program.

Variables:

  • A variable is an identifier that is used to store some value.
  • Constants can never change at the time of execution.
  • Variables can change during the execution of a program and update the value stored inside it.
  • A single variable can be used at multiple locations in a program.
  • A variable name must be meaningful.
  • It should represent the purpose of the variable.
  • Example: Height, age, are the meaningful variables that represent the purpose it is being used for.
    • Height variable can be used to store a height value.
    • The age variable can be used to store the age of a person.
  • A variable must be declared first before it is used somewhere inside the program.
  • A variable name is formed using characters, digits, and an underscore.
     

Following are the rules that must be followed while creating a variable:

  1. A variable name should consist of only characters, digits, and an underscore.
  2. A variable name should not begin with a number.
  3. A variable name should not consist of white space.
  4. A variable name should not consist of a keyword.
  5. ‘C’ is a case-sensitive language that means a variable named ‘age’ and ‘AGE’ are different.
     

Data types: ‘C’ provides various data types to make it easy for a programmer to select a suitable data type as per the requirements of an application. Following are the three data types:

  • Primitive data types
  • Derived data types
  • User-defined data types
     

The following are five primary fundamental data types:

  • int for integer data
  • char for character data
  • float for floating-point numbers
  • double for double-precision floating-point numbers
  • void

Derived Data types:

  • Array, functions, pointers, structures are derived data types.
  • C language provides more extended versions of the above-mentioned primary data types.
  • Each data type differs from one another in size and range.
  • The following table displays the size and range of each data type:

Datatypes

Size

Range

char or signed char  1 -128 to 127
unsigned char 1 0 to 255
int or signed int 2 -32768 to 32767
unsigned int 2 0 to 65535
short int or Unsigned short int 2 0 to 255
signed short int 2 -128 to 127
long int or Signed long int 4 -2147483648 to 2147483647
unsigned long int 4 0 to 4294967295
float 4 3.4E-38 to 3.4E+38

Conditional Statement:

  • Conditional Statements in C programming are used to make decisions based on the conditions.
  • It executes sequentially when there is no condition around the statements.
  • If put some conditions for a block of statements, the execution flow may change based on the result evaluated by the condition. This process is called decision-making in ‘C.’
  • In ‘C’ programming conditional statements are possible with the help of the following two constructs:
    • If statement
    • If-else statement
  • It is also called branching as a program decides which statement to execute based on the result of the evaluated condition.

Types of Conditional Statement:

  • If statement
  • Relational Operators
  • The If-Else statement
  • Conditional Expressions
  • Nested If-else Statements
  • Nested Else-if statements
     

If statement:

  • It is one of the powerful conditional statements.
  • If statement is responsible for modifying the flow of execution of a program.
  • It is always used with a condition.
  • The condition is evaluated first before executing any statement inside the body of if.

Syntax:
             if(condition)
             {
                 instruction;
            }

  • The condition evaluates to either true or false.
  • True is always a non-zero value, and false is a value that contains zero.
  • Instructions can be a single instruction or a code block enclosed by curly braces {}.

Below is the C program illustrates the use of if statement:

C

#include <stdio.h>

void if_demo()

{

    int num1 = 1;

    int num2 = 2;

    if (num1 < num2) {

        printf("num1 is smaller "

               "than num2");

    }

}

int main()

{

    if_demo();

    return 0;

}

Output:

num1 is smaller than num2

Explanation:

  • In the above program, two variables are initialized with num1, num2 with values of 1, 2 respectively.
  • Then, used the if statement with a test-expression to check which number is the smallest and which number is the largest.
  • Relational expression has been used in if constructed. Since the value of num1 is smaller than num2, the condition will evaluate to true.
  • Thus it will print the statement inside the block of If.
  • After that, the control will go outside of the block and the program will be terminated with a successful result.

Relational Operators: C has six relational operators that can be used to formulate a Boolean expression for making a decision and testing conditions, which returns true or false, below are some of them:

  • < less than
  • <= less than or equal to
  • > greater than
  • >= greater than or equal to
  • == equal to
  • != not equal to

Below is the C program illustrating the use of relational operator:

C

#include <stdio.h>

void relationalOperator()

{

    int x = 41;

    x = x + 1;

    if (x == 42) {

        printf("You succeed!");

    }

}

int main()

{

    relationalOperator();

    return 0;

}

If-Else statement: It is an extended version of If. Below is the flowchart representing the if-else statement:

Syntax:
           if (test – expression)
          {
              True block of statement;
         }
       else
       { 
            False block of statements;
      } Statements;

  • In this type of statement, if the value of test-expression is true, then the true block of statements will be executed.
  • If the value of test-expression is false, then the false block of statements will be executed.
  • In any case, after the execution, the control will be automatically transferred to the statements appearing outside the block of If.

Below is the C program demonstrating the if-else statement:

C

#include <stdio.h>

void ifElseStatement()

{

    int num = 19;

    if (num < 10) {

        printf("The value is less"

               " than 10");

    }

    else {

        printf("The value is greater"

               " than 10");

    }

}

int main()

{

    ifElseStatement();

    return 0;

}

Output:

The value is greater than 10

Conditional Expressions: There is another way to express an if-else statement is by introducing the ?: operator. In a conditional expression the ?: operator has only one statement associated with the if and the else.

Below is the C program demonstrating the conditional statement: 

C

#include <stdio.h>

void conditionalStatement()

{

    int y;

    int x = 2;

    y = (x >= 6) ? 6 : x;

    printf("y =%d ", y);

}

int main()

{

    conditionalStatement();

    return 0;

}

Nested If-else Statements:

  • When a series of decisions is required, nested if-else is used.
  • Nesting means using one if-else construct within another one.

Below is the C program demonstrating the use of nested if-else:

C

#include <stdio.h>

void nestedIfElse()

{

    int num = 1;

    if (num < 10) {

        if (num == 1) {

            printf("The value is"

                   ":%dn",

                   num);

        }

        else {

            printf("The value is "

                   "greater than 1");

        }

    }

    else {

        printf("The value is "

               "greater than 10");

    }

}

int main()

{

    nestedIfElse();

    return 0;

}

  • Nested else-if is used when multi path decisions are required.

Below is the C program illustrating the use of nested if-else for multipath decision:

C

#include <stdio.h>

void multiPath()

{

    int marks = 83;

    if (marks > 75) {

        printf("First class");

    }

    else if (marks > 65) {

        printf("Second class");

    }

    else if (marks > 55) {

        printf("Third class");

    }

    else {

        printf("Fourth class");

    }

}

int main()

{

    multiPath();

    return 0;

}

Loops:

  • A Loop executes the sequence of statements many times until the stated condition becomes false.
  • A loop consists of two parts, a body of a loop and a control statement.
  • The control statement is a combination of some conditions that direct the body of the loop to execute until the specified condition becomes false.
  • The purpose of the loop is to repeat the same code a number of times.
  • There are mainly 3 types of loops, they are as follows:
    • While loop
    • Do-While loop
    • For loop

Switch Statement:

  • The switch statement in C tests the value of a variable and compares it with multiple cases.
  • Once the case match is found, a block of statements associated with that particular case is executed.
  • Each case in a block of a switch has a different name/number which is referred to as an identifier.
  • The value provided by the user is compared with all the cases inside the switch block until the match is found.

String:

  • A String in C is nothing but a collection of characters in a linear sequence.
  • ‘C’ always treats a string a single data even though it contains white space.
  • A single character is defined using a single quote representation.
  • A string is represented using double quote marks.

Storage Class:

  • A storage class represents the visibility and location of a variable.
  • It tells from what part of code we can access a variable.
  • A storage class in C is used to describe the following things:
    • The variable scope.
    • The location where the variable will be stored.
    • The initialized value of a variable.
    • A lifetime of a variable.
    • Who can access a variable?
  • Thus, a storage class is used to represent the information about a variable.

NOTE: A variable is not only associated with a data type, its value but also a storage class.

File Management: A File can be used to store a large volume of persistent data.
Like many other languages C provides the following file management functions:

  • Creation of a file
  • Opening a file
  • Reading a file
  • Writing to a file
  • Closing a file

The process to create a file:

  • Whenever work with a file, the first step is to create a file.
  • A file is nothing but space in a memory where data is stored.
  • To create a file in a ‘C’ program following syntax is used:

FILE *fp;

fp = fopen (“file_name”, “mode”);

  • In the above syntax, the file is a data structure that is defined in the standard library.
  • The fopen is a standard function that is used to open a file.
  • If the file is not present on the system, then it is created and then opened.
  • If a file is already present on the system, then it is directly opened using this function.
  • fp is a file pointer that points to the type file.
  • Whenever open or create a file, specify the operations going to do with the file.
  • A file in ‘C’ programming can be created or opened for reading/writing purposes.
  • A mode is used to specify whether you want to open a file for any of the below-given purposes.

Following are the different types of modes in ‘C’ programming that can be used while working with a file:

File Mode Description:

  • r: Open a file for reading. If a file is in reading mode, then no data is deleted if a file is already present on a system.
  • w: Open a file for writing. If a file is in writing mode, then a new file is created if a file doesn’t exist at all. If a file is already present on a system, then all the data inside the file is truncated, and it is opened for writing purposes.
  • a: Open a file in append mode. If a file is in append mode, then the file is opened. The content within the file doesn’t change.
  • r+: Open for reading and writing from the beginning.
  • w+: Open for reading and writing, overwriting a file.
  • a+: Open for reading and writing, appending to file.

In the given syntax, the filename and the mode are specified as strings hence they must always be enclosed within double-quotes.

Below is the C code snippet showing the use of file mode:

C

#include <stdio.h>

int main()

{

    FILE* fp;

    fp = fopen("data.txt", "w");

}

Output:

Below is the C code snippet showing the path where the user wants to create the file:

C

#include <stdio.h>

int main()

{

    FILE* fp;

    fp = fopen("D:// data.txt", "w");

}

Output:

Close a file:

  • One should always close a file whenever the operations on file are over.
  • It means the contents and links to the file are terminated.
  • This prevents accidental damage to the file.
  • ‘C’ provides the fclose function to perform file closing operation.
  • The syntax of fclose is as follows:

Syntax: fclose (file_pointer);
Example:  FILE *fp;
               fp  = fopen (“data.txt”, “r”);
               fclose (fp);

  • The fclose function takes a file pointer as an argument.
  • The file associated with the file pointer is then closed with the help of fclose function.
  • It returns 0 if the close was successful and EOF (end of file), if there is an error, has occurred while file closing.

Writing to a File:

  • In C, when writing to a file, newline characters ‘n’ must be explicitly added.
  • The stdio library offers the necessary functions to write to a file:
    • fputc(char, file_pointer): It writes a character to the file pointed to by file_pointer.
    • fputs(str, file_pointer): It writes a string to the file pointed to by file_pointer.
    • fprintf(file_pointer, str, variable_lists): It prints a string to the file pointed to by file_pointer. The string can optionally include format specifiers and a list of variables variable_lists.

Below is the C program illustrating the use of fputc():

C

#include <stdio.h>

void fputc_func()

{

    int i;

    FILE* fptr;

    char fn[50];

    char str[] = "Hi my name is madhun";

    fptr = fopen("fputc_test.txt", "w");

    for (i = 0; str[i] != 'n'; i++) {

        fputc(str[i], fptr);

    }

    fclose(fptr);

}

int main()

{

    fputc_func();

    return 0;

}

Output:

0x7fffb39a39fc
0x7fffb39a39fc

Output:

Function:

  • Function in C programming is a reusable block of code that makes a program easier to understand, test and can be easily modified without changing the calling program.
  • Functions divide the code and modularize the program for better and effective results.
  • In short, a larger program is divided into various subprograms which are called functions.

Pointers:

  • The Pointer in C is a variable that stores the address of another variable.
  • A pointer can also be used to refer to another pointer function.
  • A pointer can be incremented/decremented, i.e., to point to the next/ previous memory location.
  • The purpose of the pointer is to save memory space and achieve faster execution time.

Use of Pointers: If declare a variable v of type int, v will actually store a value.
                            

              Declaration: int v = 0; 
                                  Where v is equal to zero now.

  • However, each variable, apart from value, also has its address (or, simply put, where it is located in the memory).
  • The address can be retrieved by putting an ampersand (&) before the variable name.
  • If print the address of a variable on the screen, it will look like a totally random number (moreover, it can be different from run to run).

Declaring a Pointer:

  • Like variables, pointers in C programming have to be declared before they can be used in the program.
  • Pointers can be named anything as long as they obey C’s naming rules.
  • A pointer declaration has the following form:

          Declaration: data_type * pointer_variable_name;

Initialize a pointer:

  • After declaring a pointer, initialize it like standard variables with a variable address.
  • If pointers in C programming are not uninitialized and used in the program, the results are unpredictable and potentially disastrous.
  • To get the address of a variable, use the ampersand (&)operator, placed before the name of a variable whose address is needed.
  • Pointer initialization is done with the following syntax:

Syntax:  pointer = &variable; 

Below is the C program illustrating the implementation of pointer
Program 1:

C

#include <stdio.h>

void main()

{

    int a = 10;

    int* p = &a;

    printf("%pn", &a);

    printf("%pn", p);

}

Output:

0x7fff3aa3027c
0x7fff3aa3027c

Program 2:
 

C

#include <stdio.h>

void main()

{

    int a = 10;

    int* p = &a;

    int** q = &p;

    printf("%dn", **q);

}

Advantages of Pointers:

  • Pointers are useful for accessing memory locations.
  • Pointers provide an efficient way for accessing the elements of an array structure.
  • Pointers are used for dynamic memory allocation as well as deallocation.
  • Pointers are used to form complex data structures such as linked list, graph, tree, etc.

Disadvantages of Pointers:

  • Pointers are a little complex to understand.
  • Pointers can lead to various errors such as segmentation faults or can access a memory location that is not required at all.
  • If an incorrect value is provided to a pointer, it may cause memory corruption.
  • Pointers are also responsible for memory leakage.
  • Pointers are comparatively slower than that of the variables.
  • Programmers find it very difficult to work with the pointers; therefore it is the programmer’s responsibility to manipulate a pointer carefully.

Bitwise Operators:

  • Bitwise Operators are used for manipulating data at the bit level, also called bit-level programming.
  • Bitwise operates on one or more bit patterns or binary numerals at the level of their individual bits.
  • They are used in numerical computations to make the calculation process faster.

Bitwise AND:

  • This is one of the most commonly used logical bitwise operators.
  • It is represented by a single ampersand sign (&).
  • Two integer expressions are written on each side of the (&) operator.
  • The result of the bitwise AND operation is 1 if both the bits have the value as 1; otherwise, the result is always 0.

Bitwise OR:

  • It is represented by a single vertical bar sign (|).
  • Two integer expressions are written on each side of the (|) operator.
  • The result of the bitwise OR operation is 1 if at least one of the expressions has the value as 1; otherwise, the result is always 0.

Bitwise Exclusive OR:

  • It is represented by a symbol (^).
  • Two integer expressions are written on each side of the (^) operator.
  • The result of the bitwise Exclusive-OR operation is 1 if only one of the expression has the value of 1. Otherwise, the result is always 0.

Bitwise Shift Operators:

  • The bitwise shift operators are used to move/shift the bit patterns either to the left or right side. Left and right are two shift operators provided by ‘C’ which are represented as follows:
    • Operand << n (Left Shift)
    • Operand >> n (Right Shift)

Bitwise Compliment Operator:

  • The Bitwise compliment is also called one’s compliment operator since it always takes only one value or an operand.
  • It is a unary operator.
  • When performing complement on any bits, all the 1’s become 0’s and vice versa.
  • If an integer expression contains 0000 1111 then after performing bitwise complement operation the value will become 1111 0000.
  • Bitwise compliment operator is denoted by symbol tilde (~).

Below is the C program illustrating bitwise operator:

C

#include <stdio.h>

void bitwiseOperator()

{

    unsigned int x = 48;

    unsigned int y = 13;

    int z = 0;

    z = x & y;

    printf("Bitwise AND Operator "

           "- x & y = %dn",

           z);

    z = x | y;

    printf("Bitwise OR Operator "

           "- x | y = %dn",

           z);

    z = x ^ y;

    printf("Bitwise XOR Operator- "

           "x^y= %dn",

           z);

    z = ~x;

    printf("Bitwise One's Compliment "

           "Operator - ~x = %dn",

           z);

    z = x << 2;

    printf("Bitwise Left Shift Operator"

           " x << 2= %dn",

           z);

    z = x >> 2;

    printf("Bitwise Right Shift Operator "

           "x >> 2= %dn",

           z);

}

int main()

{

    bitwiseOperator();

    return 0;

}

Output:

Bitwise AND Operator - x & y = 0
Bitwise OR Operator - x | y = 61
Bitwise XOR Operator- x^y= 61
Bitwise One's Compliment Operator - ~x = -49
Bitwise Left Shift Operator x << 2= 192
Bitwise Right Shift Operator x >> 2= 12

Work of Memory Management:

  • When declaring a variable using a basic data type, the C compiler automatically allocates memory space for the variable in a pool of memory called the stack.
  • For example, a float variable takes typically 4 bytes (according to the platform) when it is declared.
  • It can verify this information using the sizeof operator.

Dynamic Memory Allocation:

  • Dynamic Memory Allocation is the manual allocation and freeing of memory according to your programming needs.
  • Dynamic memory is managed and served with pointers that point to the newly allocated memory space in an area which is called the heap.
  • Now it can create and destroy an array of elements dynamically at runtime without any problems.
  • To sum up, automatic memory management uses the stack, and the C Dynamic Memory Allocation uses the heap.

malloc():

  • The C malloc() function stands for memory allocation.
  • It is a function that is used to allocate a block of memory dynamically.
  • It reserves memory space of specified size and returns the null pointer pointing to the memory location.
  • The pointer returned is usually of type void.
  • It means that we can assign the C malloc() function to any pointer.

Syntax of malloc():
 ptr = (cast_type *) malloc (byte_size);

free():

  • The memory for variables is automatically deallocated at compile time.
  • In dynamic memory allocation, deallocate memory explicitly.
  • If not done, it may encounter out of memory error.
  • The free() function is called to release/deallocate memory in C.
  • By freeing memory in your program, it make more available for use later.

calloc():

  • The C callao() function stands for contiguous allocation.
  • This function is used to allocate multiple blocks of memory.
  • It is a dynamic memory allocation function that is used to allocate the memory to complex data structures such as arrays and structures.
  • Malloc() function is used to allocate a single block of memory space while the calloc() in C is used to allocate multiple blocks of memory space.
  • Each block allocated by the calloc() function is of the same size.

Syntax of calloc():         
 ptr = (cast_type *) calloc (n, size);

realloc():

  • Using the C realloc() function, add more memory size to already allocated memory.
  • It expands the current block while leaving the original content as it is.
  • The realloc() in C stands for reallocation of memory.
  • realloc() can also be used to reduce the size of the previously allocated memory.

Syntax of realloc():
 ptr = realloc (ptr, newsize);

Dynamic Arrays:

  • A Dynamic array in C allows the number of elements to grow as needed.
  • C Dynamic array are widely used in Computer science algorithms.

Below is the C program creating and resizing Dynamic array:

C

#include <stdio.h>

void dynamicArray()

{

    int* arr_dynamic = NULL;

    int elements = 2, i;

    arr_dynamic = calloc(

        elements,

        sizeof(int));

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

        arr_dynamic[i] = i;

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

        printf("arr_dynamic[%d]=%dn",

               i, arr_dynamic[i]);

    elements = 4;

    arr_dynamic = realloc(

        arr_dynamic,

        elements * sizeof(int));

    printf("After reallocn");

    for (i = 2; i < elements; i++)

        arr_dynamic[i] = i;

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

        printf("arr_dynamic[%d]=%dn",

               i, arr_dynamic[i]);

    free(arr_dynamic);

}

int main()

{

    dynamicArray();

    return 0;

}

Explanation:

  • It can be dynamically managed the memory by creating memory blocks as needed in the heap.
  • In C Dynamic Memory Allocation, memory is allocated at a run time.
  • Dynamic memory allocation permits the manipulation of strings and arrays whose size is flexible and can be changed anytime in the program.
  • It is required when one has no idea how much memory a particular structure is going to occupy.
  • Malloc() in C is a dynamic memory allocation function that stands for memory allocation that blocks of memory with the specific size initialized to a garbage value
  • Calloc() in C is a contiguous memory allocation function that allocates multiple memory blocks at a time initialized to 0
  • Realloc() in C is used to reallocate memory according to the specified size.
  • Free() function is used to clear the dynamically allocated memory.

TypeCasting: Typecasting is converting one data type into another one. It is also called data conversion or type conversion. It is one of the important concepts introduced in ‘C’ programming.

‘C’ programming provides two types of type casting operations:

  • Implicit type casting
  • Explicit type casting

Implicit type casting:

  • Implicit type casting means the conversion of data types without losing its original meaning.
  • This type of typecasting is essential when the data type is changing without changing the significance of the values stored inside the variable.
  • Implicit type conversion happens automatically when a value is copied to its compatible data type.
  • During conversion, strict rules for type conversion are applied.
  • If the operands are of two different data types, then an operand having lower data type is automatically converted into a higher data type.

Below is the C program illustrating implicit type casting:

C

#include <stdio.h>

void implicitTypeCasting()

{

    short a = 10;

    int b;

    b = a;

    printf("%dn", a);

    printf("%dn", b);

}

int main()

{

    implicitTypeCasting();

    return 0;

}

Explicit type casting:

  • An implicit type conversion, the data type is converted automatically.
  • There are some scenarios in which the programmer may have to force type conversion.
  • Suppose a variable div that stores the division of two operands which are declared as an int data type.
  • In this case, after the division performed on variables var1 and var2 the result stored in the variable “result” will be in an integer format.
  • Whenever this happens, the value stored in the variable “result” loses its meaning because it does not consider the fraction part which is normally obtained in the division of two numbers.

int result, var1=10, var2=3;

result=var1/var2;

  • To force the type conversion in such situations, we use explicit typecasting.
  • It requires a type casting operator.

Below is the C program demonstrating the implementation of explicit type-casting:

C

#include <stdio.h>

void explicitTypeCasting()

{

    float a = 1.2;

    int b = (int)a + 1;

    printf("Value of a is %fn", a);

    printf("Value of b is %dn", b);

}

int main()

{

    explicitTypeCasting();

    return 0;

}

Output:

Value of a is 1.200000
Value of b is 2

Explanation:

  • Typecasting is also called type conversion
  • It means converting one data type into another.
  • Converting a smaller data type into a larger one is also called as a type promotion.
  • ‘C’ provides an implicit and explicit way of type conversion.
  • Implicit type conversion operates automatically when the compatible data type is found.
  • Explicit type conversion requires a type casting operator.

Last Updated :
16 Mar, 2023

Like Article

Save Article

Язык C – Обзор

C – это язык высокого уровня общего назначения, который первоначально был разработан Деннисом М. Ричи для разработки операционной системы UNIX в Bell Labs. Первоначально C был впервые реализован на компьютере DEC PDP-11 в 1972 году.

В 1978 году Брайан Керниган и Деннис Ритчи выпустили первое общедоступное описание C, теперь известное как стандарт K & R.

Операционная система UNIX, компилятор C и, по существу, все прикладные программы UNIX были написаны на C. Теперь C стал широко используемым профессиональным языком по разным причинам –

  • Легко обучаема
  • Структурированный язык
  • Производит эффективные программы
  • Это может обращаться с действиями низкого уровня
  • Он может быть скомпилирован на различных компьютерных платформах

Факты о С

  • C был изобретен для написания операционной системы под названием UNIX.

  • C является преемником языка B, который был представлен в начале 1970-х годов.

  • Язык был официально оформлен в 1988 году Американским национальным институтом стандартов (ANSI).

  • ОС UNIX была полностью написана на C.

  • На сегодняшний день C является наиболее широко используемым и популярным языком системного программирования.

  • Большая часть современного программного обеспечения была реализована с использованием C.

  • Самые популярные на сегодняшний день ОС Linux и RDBMS MySQL написаны на языке C.

C был изобретен для написания операционной системы под названием UNIX.

C является преемником языка B, который был представлен в начале 1970-х годов.

Язык был официально оформлен в 1988 году Американским национальным институтом стандартов (ANSI).

ОС UNIX была полностью написана на C.

На сегодняшний день C является наиболее широко используемым и популярным языком системного программирования.

Большая часть современного программного обеспечения была реализована с использованием C.

Самые популярные на сегодняшний день ОС Linux и RDBMS MySQL написаны на языке C.

Зачем использовать C?

Изначально C использовался для разработки систем, особенно программ, составляющих операционную систему. C был принят как язык разработки системы, потому что он производит код, который работает почти так же быстро, как код, написанный на языке ассемблера. Некоторые примеры использования C могут быть:

  • Операционные системы
  • Компиляторы языка
  • Монтажники
  • Текстовые редакторы
  • Спулеры печати
  • Сетевые драйверы
  • Современные программы
  • Базы данных
  • Переводчики
  • коммунальные услуги

C Программы

Программа переменного тока может варьироваться от 3 до миллионов строк, и ее следует записать в один или несколько текстовых файлов с расширением «.c» ; например, hello.c . Вы можете использовать «vi» , «vim» или любой другой текстовый редактор, чтобы записать вашу C-программу в файл.

В этом руководстве предполагается, что вы знаете, как редактировать текстовый файл и как писать исходный код в программном файле.

C – Настройка среды

Настройка локальной среды

Если вы хотите настроить свою среду для языка программирования C, вам понадобятся следующие два программных инструмента, доступных на вашем компьютере: (а) текстовый редактор и (б) компилятор C.

Текстовый редактор

Это будет использоваться для ввода вашей программы. Примеры нескольких редакторов: Блокнот Windows, Команда редактирования ОС, Бриф, Эпсилон, EMACS и vim или vi.

Название и версия текстовых редакторов могут различаться в разных операционных системах. Например, Блокнот будет использоваться в Windows, а vim или vi могут использоваться как в Windows, так и в Linux или UNIX.

Файлы, которые вы создаете в редакторе, называются исходными файлами и содержат исходные коды программы. Исходные файлы для программ на C обычно называются с расширением ” .c “.

Перед началом программирования убедитесь, что у вас есть один текстовый редактор, и у вас достаточно опыта, чтобы написать компьютерную программу, сохранить ее в файле, скомпилировать и, наконец, выполнить.

Компилятор C

Исходный код, написанный в исходном файле, является удобочитаемым исходным кодом для вашей программы. Он должен быть «скомпилирован» на машинном языке, чтобы ваш процессор мог фактически выполнить программу согласно приведенным инструкциям.

Компилятор компилирует исходные коды в конечные исполняемые программы. Наиболее часто используемым и бесплатным доступным компилятором является компилятор GNU C / C ++, в противном случае вы можете иметь компиляторы из HP или Solaris, если у вас есть соответствующие операционные системы.

В следующем разделе объясняется, как установить компилятор GNU C / C ++ в различных ОС. Мы продолжаем упоминать C / C ++ вместе, потому что компилятор GNU gcc работает как для языков программирования C, так и для C ++.

Установка в UNIX / Linux

Если вы используете Linux или UNIX , проверьте, установлен ли GCC в вашей системе, введя следующую команду из командной строки:

$ gcc -v

Если на вашем компьютере установлен компилятор GNU, он должен напечатать сообщение следующим образом:

Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

Если GCC не установлен, вам придется установить его самостоятельно, используя подробные инструкции, доступные по адресу https://gcc.gnu.org/install/.

Это руководство было написано на основе Linux, и все приведенные примеры были скомпилированы на основе Cent OS системы Linux.

Установка в Mac OS

Если вы используете Mac OS X, самый простой способ получить GCC – это загрузить среду разработки Xcode с веб-сайта Apple и следовать простым инструкциям по установке. После настройки Xcode вы сможете использовать компилятор GNU для C / C ++.

Xcode в настоящее время доступен по адресу developer.apple.com/technologies/tools/ .

Установка на Windows

Чтобы установить GCC в Windows, вам необходимо установить MinGW. Чтобы установить MinGW, перейдите на домашнюю страницу MinGW www.mingw.org и перейдите по ссылке на страницу загрузки MinGW. Загрузите последнюю версию программы установки MinGW, которая должна называться MinGW- <версия> .exe.

При установке Min GW, как минимум, вы должны установить gcc-core, gcc-g ++, binutils и среду выполнения MinGW, но вы можете установить больше.

Добавьте подкаталог bin вашей установки MinGW в переменную среды PATH , чтобы вы могли указывать эти инструменты в командной строке по их простым именам.

После завершения установки вы сможете запустить gcc, g ++, ar, ranlib, dlltool и несколько других инструментов GNU из командной строки Windows.

C – Структура программы

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

Пример Hello World

Программа AC в основном состоит из следующих частей –

  • Команды препроцессора
  • функции
  • переменные
  • Заявления и выражения
  • Комментарии

Давайте посмотрим на простой код, который будет печатать слова «Hello World» –

Live Demo

#include <stdio.h>

int main() {
   /* my first program in C */
   printf("Hello, World! n");
   
   return 0;
}

Давайте посмотрим на различные части вышеуказанной программы –

  • Первая строка программы #include <stdio.h> – это команда препроцессора, которая указывает компилятору C включить файл stdio.h перед переходом к фактической компиляции.

  • Следующая строка int main () – это основная функция, с которой начинается выполнение программы.

  • Следующая строка /*…*/ будет игнорироваться компилятором, и она была добавлена ​​для добавления дополнительных комментариев в программу. Поэтому такие строки называются комментариями в программе.

  • Следующая строка printf (…) – это еще одна функция, доступная в C, которая вызывает сообщение “Hello, World!” быть отображенным на экране.

  • Следующая строка возвращает 0; завершает функцию main () и возвращает значение 0.

Первая строка программы #include <stdio.h> – это команда препроцессора, которая указывает компилятору C включить файл stdio.h перед переходом к фактической компиляции.

Следующая строка int main () – это основная функция, с которой начинается выполнение программы.

Следующая строка /*…*/ будет игнорироваться компилятором, и она была добавлена ​​для добавления дополнительных комментариев в программу. Поэтому такие строки называются комментариями в программе.

Следующая строка printf (…) – это еще одна функция, доступная в C, которая вызывает сообщение “Hello, World!” быть отображенным на экране.

Следующая строка возвращает 0; завершает функцию main () и возвращает значение 0.

Скомпилируйте и выполните программу C

Давайте посмотрим, как сохранить исходный код в файле и как скомпилировать и запустить его. Ниже приведены простые шаги –

  • Откройте текстовый редактор и добавьте вышеупомянутый код.

  • Сохраните файл как hello.c

  • Откройте командную строку и перейдите в каталог, где вы сохранили файл.

  • Введите gcc hello.c и нажмите enter, чтобы скомпилировать ваш код.

  • Если в вашем коде нет ошибок, командная строка переместит вас на следующую строку и сгенерирует исполняемый файл .out .

  • Теперь введите a.out для выполнения вашей программы.

  • Вы увидите вывод «Hello World», напечатанный на экране.

Откройте текстовый редактор и добавьте вышеупомянутый код.

Сохраните файл как hello.c

Откройте командную строку и перейдите в каталог, где вы сохранили файл.

Введите gcc hello.c и нажмите enter, чтобы скомпилировать ваш код.

Если в вашем коде нет ошибок, командная строка переместит вас на следующую строку и сгенерирует исполняемый файл .out .

Теперь введите a.out для выполнения вашей программы.

Вы увидите вывод «Hello World», напечатанный на экране.

$ gcc hello.c
$ ./a.out
Hello, World!

Убедитесь, что компилятор gcc находится в вашем пути и вы запускаете его в каталоге, содержащем исходный файл hello.c.

C – Базовый синтаксис

Вы видели базовую структуру C-программы, поэтому вам будет легко понять другие основные строительные блоки языка C-программирования.

Жетоны в С

Программа AC состоит из различных токенов, и токен является ключевым словом, идентификатором, константой, строковым литералом или символом. Например, следующий оператор C состоит из пяти токенов –

printf("Hello, World! n");

Отдельные токены –

printf
(
"Hello, World! n"
)
;

Точка с запятой

В программе на Си точка с запятой – это терминатор оператора. То есть каждое отдельное утверждение должно заканчиваться точкой с запятой. Это указывает на конец одного логического объекта.

Ниже приведены два разных утверждения –

printf("Hello, World! n");
return 0;

Комментарии

Комментарии подобны тексту помощи в вашей C-программе и игнорируются компилятором. Они начинаются с / * и заканчиваются символами * /, как показано ниже –

/* my first program in C */

Вы не можете иметь комментарии в комментариях, и они не встречаются в строке или символьных литералах.

Идентификаторы

Идентификатор AC – это имя, используемое для идентификации переменной, функции или любого другого определенного пользователем элемента. Идентификатор начинается с буквы от A до Z, от a до z или подчеркивания ‘_’, за которым следуют ноль или более букв, подчеркиваний и цифр (от 0 до 9).

C не допускает использование знаков препинания, таких как @, $ и% в идентификаторах. C – чувствительный к регистру язык программирования. Таким образом, рабочая сила и рабочая сила – два разных идентификатора в C. Вот несколько примеров допустимых идентификаторов:

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

Ключевые слова

В следующем списке показаны зарезервированные слова в C. Эти зарезервированные слова не могут использоваться в качестве констант или переменных или любых других имен идентификаторов.

авто еще долго переключатель
перерыв перечисление регистр ЬурейеЕ
дело внешний вернуть союз
голец поплавок короткая неподписанный
Const за подписанный недействительным
Продолжить идти к размер летучий
дефолт если статический в то время как
делать ИНТ структура _Packed
двойной

Пробел в C

Строка, содержащая только пробел, возможно, с комментарием, называется пустой строкой, и компилятор C полностью игнорирует ее.

Пробел – это термин, используемый в C для описания пробелов, вкладок, символов новой строки и комментариев. Пробелы отделяют одну часть оператора от другой и позволяют компилятору определить, где заканчивается один элемент в выражении, например int, и начинается следующий элемент. Поэтому в следующем утверждении –

int age;

должен быть хотя бы один пробельный символ (обычно пробел) между int и age, чтобы компилятор мог их различать. С другой стороны, в следующем утверждении –

fruit = apples + oranges;   // get the total fruit

между фруктами и = или между = и яблоками не нужно вводить пробельные символы, хотя вы можете включить некоторые из них, если хотите улучшить читаемость.

C – Типы данных

Типы данных в c относятся к обширной системе, используемой для объявления переменных или функций различных типов. Тип переменной определяет, сколько места она занимает в хранилище и как интерпретируется сохраненный битовый шаблон.

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

Sr.No. Типы и описание
1

Основные типы

Они являются арифметическими типами и далее подразделяются на: (а) целочисленные типы и (б) типы с плавающей точкой.

2

Перечисляемые типы

Они снова являются арифметическими типами и используются для определения переменных, которые могут назначать только определенные дискретные целочисленные значения по всей программе.

3

Тип пустоты

Спецификатор типа void указывает, что значение недоступно.

4

Производные типы

Они включают (a) типы указателей, (b) типы массивов, (c) типы структур, (d) типы объединений и (e) типы функций.

Основные типы

Они являются арифметическими типами и далее подразделяются на: (а) целочисленные типы и (б) типы с плавающей точкой.

Перечисляемые типы

Они снова являются арифметическими типами и используются для определения переменных, которые могут назначать только определенные дискретные целочисленные значения по всей программе.

Тип пустоты

Спецификатор типа void указывает, что значение недоступно.

Производные типы

Они включают (a) типы указателей, (b) типы массивов, (c) типы структур, (d) типы объединений и (e) типы функций.

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

Целочисленные типы

В следующей таблице приведены сведения о стандартных целочисленных типах с их размерами хранения и диапазонами значений.

Тип Размер хранилища Диапазон значений
голец 1 байт От -128 до 127 или от 0 до 255
без знака 1 байт От 0 до 255
подписанный символ 1 байт От -128 до 127
ИНТ 2 или 4 байта От -32 768 до 32 767 или от -2 147 483 648 до 2 147 483 647
без знака int 2 или 4 байта От 0 до 65 535 или от 0 до 4 294 967 295
короткая 2 байта От -32 768 до 32 767
неподписанный короткий 2 байта От 0 до 65 535
долго 4 байта От -2 147 483 648 до 2 147 483 647
без знака долго 4 байта От 0 до 4 294 967 295

Чтобы получить точный размер типа или переменной на конкретной платформе, вы можете использовать оператор sizeof . Выражение sizeof (тип) возвращает размер хранилища объекта или типа в байтах. Ниже приведен пример получения размера типа int на любой машине:

Live Demo

#include <stdio.h>
#include <limits.h>

int main() {
   printf("Storage size for int : %d n", sizeof(int));
   
   return 0;
}

Когда вы компилируете и запускаете вышеупомянутую программу, она дает следующий результат в Linux:

Storage size for int : 4

Типы с плавающей точкой

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

Тип Размер хранилища Диапазон значений точность
поплавок 4 байта 1,2E-38 до 3,4E + 38 6 десятичных знаков
двойной 8 байт 2,3E-308 до 1,7E + 308 15 десятичных знаков
длинный двойной 10 байт От 3.4E-4932 до 1.1E + 4932 19 десятичных знаков

Заголовочный файл float.h определяет макросы, которые позволяют вам использовать эти значения и другие подробности о двоичном представлении действительных чисел в ваших программах. В следующем примере печатается место для хранения, занятое типом с плавающей запятой, и его значениями диапазона.

Live Demo

#include <stdio.h>
#include <float.h>

int main() {
   printf("Storage size for float : %d n", sizeof(float));
   printf("Minimum float positive value: %En", FLT_MIN );
   printf("Maximum float positive value: %En", FLT_MAX );
   printf("Precision value: %dn", FLT_DIG );
   
   return 0;
}

Когда вы компилируете и запускаете вышеупомянутую программу, она дает следующий результат в Linux:

Storage size for float : 4
Minimum float positive value: 1.175494E-38
Maximum float positive value: 3.402823E+38
Precision value: 6

Тип пустоты

Тип void указывает, что значение недоступно. Он используется в трех видах ситуаций –

Sr.No. Типы и описание
1

Функция возвращается как void

В C есть различные функции, которые не возвращают никакого значения, или вы можете сказать, что они возвращают void. Функция без возвращаемого значения имеет тип возврата как void. Например, void exit (int status);

2

Аргументы функции как void

В C есть различные функции, которые не принимают никаких параметров. Функция без параметра может принять пустоту. Например, int rand (void);

3

Указатели на аннулирование

Указатель типа void * представляет адрес объекта, но не его тип. Например, функция выделения памяти void * malloc (size_t size); возвращает указатель на void, который может быть приведен к любому типу данных.

Функция возвращается как void

В C есть различные функции, которые не возвращают никакого значения, или вы можете сказать, что они возвращают void. Функция без возвращаемого значения имеет тип возврата как void. Например, void exit (int status);

Аргументы функции как void

В C есть различные функции, которые не принимают никаких параметров. Функция без параметра может принять пустоту. Например, int rand (void);

Указатели на аннулирование

Указатель типа void * представляет адрес объекта, но не его тип. Например, функция выделения памяти void * malloc (size_t size); возвращает указатель на void, который может быть приведен к любому типу данных.

C – переменные

Переменная – это не что иное, как имя, данное области памяти, которой могут манипулировать наши программы. Каждая переменная в C имеет определенный тип, который определяет размер и расположение памяти переменной; диапазон значений, которые могут быть сохранены в этой памяти; и набор операций, которые могут быть применены к переменной.

Имя переменной может состоять из букв, цифр и символа подчеркивания. Он должен начинаться либо с буквы, либо с подчеркивания. Прописные и строчные буквы различны, потому что C чувствителен к регистру. Основываясь на базовых типах, описанных в предыдущей главе, будут следующие базовые типы переменных:

Sr.No. Тип и описание
1

голец

Обычно один октет (один байт). Это целочисленный тип.

2

ИНТ

Наиболее натуральный размер целого числа для машины.

3

поплавок

Значение с плавающей запятой одинарной точности.

4

двойной

Значение с плавающей запятой двойной точности.

5

недействительным

Представляет отсутствие типа.

голец

Обычно один октет (один байт). Это целочисленный тип.

ИНТ

Наиболее натуральный размер целого числа для машины.

поплавок

Значение с плавающей запятой одинарной точности.

двойной

Значение с плавающей запятой двойной точности.

недействительным

Представляет отсутствие типа.

Язык программирования C также позволяет определять различные другие типы переменных, которые мы рассмотрим в следующих главах, таких как Перечисление, Указатель, Массив, Структура, Объединение и т. Д. В этой главе мы изучим только основные типы переменных.

Определение переменной в C

Определение переменной сообщает компилятору, где и сколько памяти нужно создать для переменной. Определение переменной определяет тип данных и содержит список из одной или нескольких переменных этого типа следующим образом:

type variable_list;

Здесь тип должен быть допустимым типом данных C, включая char, w_char, int, float, double, bool или любой определенный пользователем объект; и variable_list может состоять из одного или нескольких имен идентификаторов, разделенных запятыми. Некоторые действительные объявления показаны здесь –

int    i, j, k;
char   c, ch;
float  f, salary;
double d;

Линия int i, j, k; объявляет и определяет переменные i, j и k; который инструктирует компилятор создавать переменные с именами i, j и k типа int.

Переменные могут быть инициализированы (им присвоено начальное значение) в их объявлении. Инициализатор состоит из знака равенства, за которым следует постоянное выражение:

type variable_name = value;

Вот некоторые примеры:

extern int d = 3, f = 5;    // declaration of d and f. 
int d = 3, f = 5;           // definition and initializing d and f. 
byte z = 22;                // definition and initializes z. 
char x = 'x';               // the variable x has the value 'x'.

Для определения без инициализатора: переменные со статической продолжительностью хранения неявно инициализируются с помощью NULL (все байты имеют значение 0); начальное значение всех остальных переменных не определено.

Объявление переменных в C

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

Объявление переменной полезно, когда вы используете несколько файлов и определяете свою переменную в одном из файлов, которые будут доступны во время компоновки программы. Вы будете использовать ключевое слово extern для объявления переменной в любом месте. Хотя вы можете объявлять переменную несколько раз в вашей C-программе, она может быть определена только один раз в файле, функции или блоке кода.

пример

Попробуйте следующий пример, где переменные были объявлены сверху, но они были определены и инициализированы внутри основной функции –

Live Demo

#include <stdio.h>

// Variable declaration:
extern int a, b;
extern int c;
extern float f;

int main () {

   /* variable definition: */
   int a, b;
   int c;
   float f;
 
   /* actual initialization */
   a = 10;
   b = 20;
  
   c = a + b;
   printf("value of c : %d n", c);

   f = 70.0/3.0;
   printf("value of f : %f n", f);
 
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

value of c : 30
value of f : 23.333334

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

// function declaration
int func();

int main() {

   // function call
   int i = func();
}

// function definition
int func() {
   return 0;
}

L-значения и R-значения в C

Есть два вида выражений в C –

  • lvalue – выражения, которые ссылаются на ячейку памяти, называются «lvalue» выражениями. Lvalue может отображаться как левая или правая сторона задания.

  • rvalue – термин rvalue относится к значению данных, которое хранится по некоторому адресу в памяти. Значение r – это выражение, которому не может быть присвоено значение, что означает, что значение r может появляться в правой части, но не в левой части назначения.

lvalue – выражения, которые ссылаются на ячейку памяти, называются «lvalue» выражениями. Lvalue может отображаться как левая или правая сторона задания.

rvalue – термин rvalue относится к значению данных, которое хранится по некоторому адресу в памяти. Значение r – это выражение, которому не может быть присвоено значение, что означает, что значение r может появляться в правой части, но не в левой части назначения.

Переменные являются l-значениями, поэтому они могут отображаться в левой части назначения. Числовые литералы являются r-значениями, поэтому они не могут быть назначены и не могут отображаться слева. Взгляните на следующие действительные и недействительные утверждения –

int g = 20; // valid statement

10 = 20; // invalid statement; would generate compile-time error

C – константы и литералы

Константы относятся к фиксированным значениям, которые программа не может изменить во время своего выполнения. Эти фиксированные значения также называются литералами .

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

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

Целочисленные литералы

Целочисленный литерал может быть десятичной, восьмеричной или шестнадцатеричной константой. Префикс указывает основание или основание: 0x или 0X для шестнадцатеричного, 0 для восьмеричного и ничего для десятичного.

Целочисленный литерал также может иметь суффикс, который представляет собой комбинацию U и L для беззнакового и длинного соответственно. Суффикс может быть в верхнем или нижнем регистре и может быть в любом порядке.

Вот несколько примеров целочисленных литералов –

212         /* Legal */
215u        /* Legal */
0xFeeL      /* Legal */
078         /* Illegal: 8 is not an octal digit */
032UU       /* Illegal: cannot repeat a suffix */

Ниже приведены другие примеры различных типов целочисленных литералов –

85         /* decimal */
0213       /* octal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */

Литералы с плавающей точкой

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

Представляя десятичную форму, вы должны включить десятичную точку, показатель степени или оба; и при представлении экспоненциальной формы вы должны включать целую часть, дробную часть или оба. Подписанный показатель вводится через e или E.

Вот несколько примеров литералов с плавающей точкой –

3.14159       /* Legal */
314159E-5L    /* Legal */
510E          /* Illegal: incomplete exponent */
210f          /* Illegal: no decimal or exponent */
.e55          /* Illegal: missing integer or fraction */

Константы персонажа

Символьные литералы заключены в одинарные кавычки, например, ‘x’ может храниться в простой переменной типа char .

Символьный литерал может быть простым символом (например, «x»), escape-последовательностью (например, « t») или универсальным символом (например, « u02C0»).

В С есть определенные символы, представляющие особое значение, когда им предшествует обратная косая черта, например, новая строка ( n) или табуляция ( t).

Здесь у вас есть список таких кодов escape-последовательностей –

Последовательность побега Имея в виду
\ персонаж
» ‘ персонаж
» ” персонаж
? ? персонаж
а Оповещение или звонок
б возврат на одну позицию
е Форма подачи
п Новая линия
р Возврат каретки
т Горизонтальная вкладка
v Вертикальная вкладка
ооо Восьмеричное число от одной до трех цифр
ххх , , Шестнадцатеричное число из одной или нескольких цифр

Ниже приведен пример, показывающий несколько символов escape-последовательности:

Live Demo

#include <stdio.h>

int main() {
   printf("HellotWorldnn");

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Hello World

Строковые литералы

Строковые литералы или константы заключаются в двойные кавычки “”. Строка содержит символы, похожие на символьные литералы: простые символы, escape-последовательности и универсальные символы.

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

Вот несколько примеров строковых литералов. Все три формы являются одинаковыми строками.

"hello, dear"

"hello, 

dear"

"hello, " "d" "ear"

Определение констант

Есть два простых способа определения констант в C:

  • Использование #define препроцессора.

  • Используя ключевое слово const .

Использование #define препроцессора.

Используя ключевое слово const .

Препроцессор #define

Ниже приведена форма для использования препроцессора #define для определения константы –

#define identifier value

Следующий пример объясняет это подробно –

Live Demo

#include <stdio.h>

#define LENGTH 10   
#define WIDTH  5
#define NEWLINE 'n'

int main() {
   int area;  
  
   area = LENGTH * WIDTH;
   printf("value of area : %d", area);
   printf("%c", NEWLINE);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

value of area : 50

Ключевое слово const

Вы можете использовать префикс const для объявления констант определенного типа следующим образом:

const type variable = value;

Следующий пример объясняет это подробно –

Live Demo

#include <stdio.h>

int main() {
   const int  LENGTH = 10;
   const int  WIDTH = 5;
   const char NEWLINE = 'n';
   int area;  
   
   area = LENGTH * WIDTH;
   printf("value of area : %d", area);
   printf("%c", NEWLINE);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

value of area : 50

Обратите внимание, что это хорошая практика программирования для определения констант в заглавных буквах.

C – Классы хранения

Класс хранения определяет область действия (видимость) и время жизни переменных и / или функций в программе на Си. Они предшествуют типу, который они изменяют. У нас есть четыре разных класса хранения в программе на C –

  • авто
  • регистр
  • статический
  • внешний

Авто Класс Хранения

Класс автоматического хранения является классом хранения по умолчанию для всех локальных переменных.

{
   int mount;
   auto int month;
}

В приведенном выше примере определены две переменные в одном классе хранения. ‘auto’ может использоваться только внутри функций, то есть локальных переменных.

Класс хранения регистра

Класс хранения регистров используется для определения локальных переменных, которые должны храниться в регистре, а не в ОЗУ. Это означает, что переменная имеет максимальный размер, равный размеру регистра (обычно одно слово), и к ней не может быть применен унарный оператор ‘&’ (так как она не имеет места в памяти).

{
   register int  miles;
}

Регистр следует использовать только для переменных, которые требуют быстрого доступа, таких как счетчики. Следует также отметить, что определение «регистр» не означает, что переменная будет храниться в регистре. Это означает, что он МОЖЕТ храниться в реестре в зависимости от аппаратного обеспечения и ограничений реализации.

Статический класс хранения

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

Статический модификатор также может применяться к глобальным переменным. Когда это сделано, область действия этой переменной будет ограничена файлом, в котором она объявлена.

В программировании на C, когда static используется в глобальной переменной, он вызывает совместное использование только одной копии этого члена всеми объектами этого класса.

Live Demo

#include <stdio.h>
 
/* function declaration */
void func(void);
 
static int count = 5; /* global variable */
 
main() {

   while(count--) {
      func();
   }
	
   return 0;
}

/* function definition */
void func( void ) {

   static int i = 5; /* local static variable */
   i++;

   printf("i is %d and count is %dn", i, count);
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0

Внешний класс хранения

Класс внешнего хранилища используется для предоставления ссылки на глобальную переменную, которая видна ВСЕМ программным файлам. Когда вы используете ‘extern’, переменная не может быть инициализирована, однако, она указывает имя переменной на место хранения, которое было ранее определено.

Если у вас есть несколько файлов, и вы определяете глобальную переменную или функцию, которые также будут использоваться в других файлах, тогда extern будет использоваться в другом файле для предоставления ссылки на определенную переменную или функцию. Просто для понимания, extern используется для объявления глобальной переменной или функции в другом файле.

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

Первый файл: main.c

#include <stdio.h>
 
int count ;
extern void write_extern();
 
main() {
   count = 5;
   write_extern();
}

Второй файл: support.c

#include <stdio.h>
 
extern int count;
 
void write_extern(void) {
   printf("count is %dn", count);
}

Здесь extern используется для объявления счетчика во втором файле, где, как и его определение в первом файле, main.c. Теперь скомпилируйте эти два файла следующим образом:

$gcc main.c support.c

Это произведет исполняемую программу a.out . Когда эта программа выполняется, она дает следующий результат –

count is 5

C – Операторы

Оператор – это символ, который указывает компилятору выполнять определенные математические или логические функции. Язык C богат встроенными операторами и предоставляет следующие типы операторов:

  • Арифметические Операторы
  • Операторы отношений
  • Логические Операторы
  • Битовые операторы
  • Операторы присваивания
  • Разные Операторы

В этой главе мы рассмотрим, как работает каждый оператор.

Арифметические Операторы

В следующей таблице показаны все арифметические операторы, поддерживаемые языком Си. Предположим, что переменная A содержит 10, а переменная B содержит 20, тогда –

Показать примеры

оператор Описание пример
+ Добавляет два операнда. А + В = 30
Вычитает второй операнд из первого. A – B = -10
* Умножает оба операнда. A * B = 200
/ Делит числитель на числитель. B / A = 2
% Оператор модуля и остаток от целочисленного деления. B% A = 0
++ Оператор приращения увеличивает целочисленное значение на единицу. А ++ = 11
Оператор уменьшения уменьшает целочисленное значение на единицу. A– = 9

Операторы отношений

В следующей таблице показаны все реляционные операторы, поддерживаемые C. Предположим, переменная A содержит 10, а переменная B содержит 20, тогда –

Показать примеры

оператор Описание пример
== Проверяет, равны ли значения двух операндов или нет. Если да, то условие становится истинным. (A == B) не соответствует действительности.
знак равно Проверяет, равны ли значения двух операндов или нет. Если значения не равны, то условие становится истинным. (A! = B) верно.
> Проверяет, больше ли значение левого операнда, чем значение правого операнда. Если да, то условие становится истинным. (A> B) не соответствует действительности.
< Проверяет, меньше ли значение левого операнда, чем значение правого операнда. Если да, то условие становится истинным. (A <B) верно.
> = Проверяет, больше ли значение левого операнда или равно значению правого операнда. Если да, то условие становится истинным. (A> = B) не соответствует действительности.
<= Проверяет, меньше ли значение левого операнда или равно значению правого операнда. Если да, то условие становится истинным. (A <= B) верно.

Логические Операторы

В следующей таблице приведены все логические операторы, поддерживаемые языком Си. Предположим, что переменная A содержит 1, а переменная B содержит 0, тогда –

Показать примеры

оператор Описание пример
&& Называется логический оператор И. Если оба операнда отличны от нуля, условие становится истинным. (A && B) неверно.
|| Вызывается логическим оператором ИЛИ. Если любой из двух операндов отличен от нуля, условие становится истинным. (A || B) верно.
! Вызывается логическим оператором НЕ. Он используется для изменения логического состояния своего операнда. Если условие истинно, то оператор Логический НЕ сделает его ложным. ! (A && B) верно.

Битовые операторы

Побитовый оператор работает с битами и выполняет побитовую операцию. Таблицы истинности для &, | и ^ следующие:

п Q P & Q р | Q р ^ д
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Предположим, что A = 60 и B = 13 в двоичном формате, они будут выглядеть следующим образом:

A = 0011 1100

B = 0000 1101

—————–

A & B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~ A = 1100 0011

В следующей таблице перечислены побитовые операторы, поддерживаемые C. Предположим, переменная «A» содержит 60, а переменная «B» содержит 13, затем –

Показать примеры

оператор Описание пример
& Двоичный оператор AND немного копирует результат, если он существует в обоих операндах. (A & B) = 12, т.е. 0000 1100
| Оператор двоичного ИЛИ копирует немного, если он существует в любом из операндов. (A | B) = 61, т. Е. 0011 1101
^ Двоичный оператор XOR копирует бит, если он установлен в одном операнде, но не в обоих. (A ^ B) = 49, т.е. 0011 0001
~ Оператор дополнения Binary One является унарным и имеет эффект «переворачивания» битов. (~ A) = ~ (60), т. Е. -0111101
<< Двоичный оператор левого сдвига. Значение левого операнда перемещается влево на количество битов, указанное правым операндом. A << 2 = 240, т. Е. 1111 0000
>> Оператор двоичного правого сдвига. Значение левого операнда перемещается вправо на количество битов, указанное правым операндом. A >> 2 = 15, т.е. 0000 1111

Операторы присваивания

В следующей таблице перечислены операторы присваивания, поддерживаемые языком C –

Показать примеры

оператор Описание пример
знак равно Простой оператор присваивания. Назначает значения от правых операндов к левому операнду C = A + B назначит значение A + B для C
+ = Добавить И оператор присваивания. Он добавляет правый операнд к левому операнду и присваивает результат левому операнду. C + = A эквивалентно C = C + A
знак равно Вычитание И оператор присваивания. Он вычитает правый операнд из левого операнда и присваивает результат левому операнду. C – = A эквивалентно C = C – A
знак равно Оператор умножения И присваивания. Он умножает правый операнд на левый операнд и присваивает результат левому операнду. C * = A эквивалентно C = C * A
знак равно Оператор деления И присваивания. Он делит левый операнд на правый операнд и присваивает результат левому операнду. C / = A эквивалентно C = C / A
знак равно Модуль И оператор присваивания. Он принимает модуль с использованием двух операндов и присваивает результат левому операнду. C% = A эквивалентно C = C% A
<< = Левый сдвиг И оператор присваивания. C << = 2 совпадает с C = C << 2
>> = Сдвиг вправо И оператор присваивания. C >> = 2 – это то же самое, что C = C >> 2
знак равно Побитовое И оператор присваивания. C & = 2 совпадает с C = C & 2
^ = Побитовое исключающее ИЛИ и оператор присваивания. C ^ = 2 совпадает с C = C ^ 2
| = Побитовое ИЛИ и оператор присваивания. C | = 2 – это то же самое, что C = C | 2

Разные операторы ↦ sizeof & ternary

Помимо операторов, описанных выше, есть несколько других важных операторов, включая sizeof и ? : поддерживается языком Си.

Показать примеры

оператор Описание пример
размер() Возвращает размер переменной. sizeof (a), где a является целым числом, вернет 4.
& Возвращает адрес переменной. & А; возвращает фактический адрес переменной.
* Указатель на переменную. * А;
? : Условное выражение. Если условие верно? тогда значение X: иначе значение Y

Приоритет операторов в C

Приоритет оператора определяет группировку терминов в выражении и определяет способ вычисления выражения. Некоторые операторы имеют более высокий приоритет, чем другие; например, оператор умножения имеет более высокий приоритет, чем оператор сложения.

Например, х = 7 + 3 * 2; здесь x назначено 13, а не 20, потому что оператор * имеет более высокий приоритет, чем +, поэтому он сначала умножается на 3 * 2, а затем прибавляется к 7.

Здесь операторы с самым высоким приоритетом отображаются вверху таблицы, а операторы с самым низким – внизу. Внутри выражения операторы с более высоким приоритетом будут оцениваться первыми.

Показать примеры

категория оператор Ассоциативность
постфикс () [] ->. ++ – – Слева направо
Одинарный + -! ~ ++ – – (тип) * & sizeof Справа налево
Multiplicative * /% Слева направо
присадка + – Слева направо
сдвиг << >> Слева направо
реляционный <<=>> = Слева направо
равенство ==! = Слева направо
Побитовое И & Слева направо
Побитовый XOR ^ Слева направо
Побитовое ИЛИ | Слева направо
Логическое И && Слева направо
Логическое ИЛИ || Слева направо
условный ?: Справа налево
присваивание = + = – = * = / =% = >> = << = & = ^ = | = Справа налево
запятая , Слева направо

C – Принятие решений

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

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

Принятие решений заявления в C

Язык программирования C принимает любые ненулевые и ненулевые значения как истинные , и если это ноль или ноль , то это предполагается как ложное значение.

Язык программирования C предоставляет следующие типы операторов принятия решений.

Sr.No. Заявление и описание
1 если заявление

Оператор if состоит из логического выражения, за которым следует одно или несколько операторов.

2 если … еще заявление

За оператором if может следовать необязательный оператор else , который выполняется, когда логическое выражение имеет значение false.

3 вложенные операторы if

Вы можете использовать один оператор if или else if внутри другого оператора if или else if .

4 заявление о переключении

Оператор switch позволяет проверять переменную на соответствие списку значений.

5 вложенные операторы switch

Вы можете использовать один оператор switch внутри другого оператора (ов) switch .

Оператор if состоит из логического выражения, за которым следует одно или несколько операторов.

За оператором if может следовать необязательный оператор else , который выполняется, когда логическое выражение имеет значение false.

Вы можете использовать один оператор if или else if внутри другого оператора if или else if .

Оператор switch позволяет проверять переменную на соответствие списку значений.

Вы можете использовать один оператор switch внутри другого оператора (ов) switch .

? : Оператор

Мы накрыли условного оператора? : в предыдущей главе, которая может быть использована для замены операторов if … else . Он имеет следующую общую форму –

Exp1 ? Exp2 : Exp3;

Где Exp1, Exp2 и Exp3 являются выражениями. Обратите внимание на использование и размещение толстой кишки.

Значение? выражение определяется так –

  • Exp1 оценивается. Если это правда, то Exp2 оценивается и становится значением целого? выражение.

  • Если Exp1 имеет значение false, то Exp3 оценивается, и его значение становится значением выражения.

Exp1 оценивается. Если это правда, то Exp2 оценивается и становится значением целого? выражение.

Если Exp1 имеет значение false, то Exp3 оценивается, и его значение становится значением выражения.

C – Петли

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

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

Оператор цикла позволяет нам выполнять оператор или группу операторов несколько раз. Ниже приведена общая форма оператора цикла в большинстве языков программирования –

Петлевая архитектура

Язык программирования C предоставляет следующие типы циклов для обработки требований циклов.

Sr.No. Тип и описание петли
1 в то время как цикл

Повторяет оператор или группу операторов, пока данное условие выполняется. Он проверяет условие перед выполнением тела цикла.

2 для цикла

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

3 делать … пока цикл

Это больше похоже на оператор while, за исключением того, что он проверяет условие в конце тела цикла.

4 вложенные циклы

Вы можете использовать один или несколько циклов внутри любого другого цикла while, for или do.. while.

Повторяет оператор или группу операторов, пока данное условие выполняется. Он проверяет условие перед выполнением тела цикла.

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

Это больше похоже на оператор while, за исключением того, что он проверяет условие в конце тела цикла.

Вы можете использовать один или несколько циклов внутри любого другого цикла while, for или do.. while.

Заявления о контроле цикла

Операторы управления циклом изменяют выполнение от его нормальной последовательности. Когда выполнение покидает область действия, все автоматические объекты, созданные в этой области, уничтожаются.

C поддерживает следующие операторы управления.

Sr.No. Контрольное заявление и описание
1 заявление о нарушении

Завершает оператор цикла или переключателя и передает выполнение в оператор, следующий сразу за циклом или переключателем.

2 продолжить заявление

Заставляет петлю пропускать оставшуюся часть своего тела и немедленно проверять свое состояние перед повторением.

3 Перейти к заявлению

Передает управление помеченному выражению.

Завершает оператор цикла или переключателя и передает выполнение в оператор, следующий сразу за циклом или переключателем.

Заставляет петлю пропускать оставшуюся часть своего тела и немедленно проверять свое состояние перед повторением.

Передает управление помеченному выражению.

Бесконечный цикл

Цикл становится бесконечным, если условие никогда не становится ложным. Цикл for традиционно используется для этой цели. Поскольку ни одно из трех выражений, образующих цикл for, не требуется, вы можете создать бесконечный цикл, оставив условное выражение пустым.

#include <stdio.h>
 
int main () {

   for( ; ; ) {
      printf("This loop will run forever.n");
   }

   return 0;
}

Когда условное выражение отсутствует, оно считается истинным. У вас может быть выражение инициализации и приращения, но программисты на Си чаще используют конструкцию for (;;) для обозначения бесконечного цикла.

ПРИМЕЧАНИЕ. – Вы можете завершить бесконечный цикл, нажав клавиши Ctrl + C.

C – Функции

Функция – это группа операторов, которые вместе выполняют задачу. Каждая программа на С имеет как минимум одну функцию – main () , и все самые тривиальные программы могут определять дополнительные функции.

Вы можете разделить ваш код на отдельные функции. Как вы делите свой код между различными функциями, зависит от вас, но логически разделение таково, что каждая функция выполняет определенную задачу.

Объявление функции сообщает компилятору об имени функции, типе возврата и параметрах. Определение функции обеспечивает фактическое тело функции.

Стандартная библиотека C предоставляет множество встроенных функций, которые может вызывать ваша программа. Например, strcat () для объединения двух строк, memcpy () для копирования одной области памяти в другую и многие другие функции.

Функцию также можно назвать методом, подпрограммой, процедурой и т. Д.

Определение функции

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

return_type function_name( parameter list ) {
   body of the function
}

Определение функции в C-программировании состоит из заголовка функции и тела функции . Вот все части функции –

  • Тип возврата – функция может возвращать значение. Return_type – это тип данных значения, которое возвращает функция. Некоторые функции выполняют нужные операции без возврата значения. В этом случае return_type является ключевым словом void .

  • Имя функции – это фактическое имя функции. Имя функции и список параметров вместе составляют сигнатуру функции.

  • Параметры – параметр похож на заполнитель. Когда вызывается функция, вы передаете значение параметру. Это значение называется фактическим параметром или аргументом. Список параметров относится к типу, порядку и количеству параметров функции. Параметры являются необязательными; то есть функция может не содержать параметров.

  • Тело функцииТело функции содержит набор операторов, которые определяют, что делает функция.

Тип возврата – функция может возвращать значение. Return_type – это тип данных значения, которое возвращает функция. Некоторые функции выполняют нужные операции без возврата значения. В этом случае return_type является ключевым словом void .

Имя функции – это фактическое имя функции. Имя функции и список параметров вместе составляют сигнатуру функции.

Параметры – параметр похож на заполнитель. Когда вызывается функция, вы передаете значение параметру. Это значение называется фактическим параметром или аргументом. Список параметров относится к типу, порядку и количеству параметров функции. Параметры являются необязательными; то есть функция может не содержать параметров.

Тело функцииТело функции содержит набор операторов, которые определяют, что делает функция.

пример

Ниже приведен исходный код функции max () . Эта функция принимает два параметра num1 и num2 и возвращает максимальное значение между двумя –

/* function returning the max between two numbers */
int max(int num1, int num2) {

   /* local variable declaration */
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

Объявления функций

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

Объявление функции состоит из следующих частей:

return_type function_name( parameter list );

Для определенной выше функции max () объявление функции выглядит следующим образом:

int max(int num1, int num2);

Имена параметров не важны в объявлении функции, требуется только их тип, поэтому следующее также является допустимым объявлением:

int max(int, int);

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

Вызов функции

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

Когда программа вызывает функцию, управление программой передается вызываемой функции. Вызываемая функция выполняет определенную задачу, и когда выполняется ее оператор return или когда достигается закрывающая фигурная скобка, завершающая функцию, она возвращает управление программой обратно в основную программу.

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

Live Demo

#include <stdio.h>
 
/* function declaration */
int max(int num1, int num2);
 
int main () {

   /* local variable definition */
   int a = 100;
   int b = 200;
   int ret;
 
   /* calling a function to get max value */
   ret = max(a, b);
 
   printf( "Max value is : %dn", ret );
 
   return 0;
}
 
/* function returning the max between two numbers */
int max(int num1, int num2) {

   /* local variable declaration */
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

Мы сохранили max () вместе с main () и скомпилировали исходный код. Запустив финальный исполняемый файл, он даст следующий результат:

Max value is : 200

Аргументы функции

Если функция должна использовать аргументы, она должна объявлять переменные, которые принимают значения аргументов. Эти переменные называются формальными параметрами функции.

Формальные параметры ведут себя как другие локальные переменные внутри функции и создаются при входе в функцию и уничтожаются при выходе.

При вызове функции есть два способа передачи аргументов в функцию:

Sr.No. Тип звонка и описание
1 Звонок по значению

Этот метод копирует фактическое значение аргумента в формальный параметр функции. В этом случае изменения, внесенные в параметр внутри функции, не влияют на аргумент.

2 Звоните по ссылке

Этот метод копирует адрес аргумента в формальный параметр. Внутри функции адрес используется для доступа к фактическому аргументу, используемому в вызове. Это означает, что изменения, внесенные в параметр, влияют на аргумент.

Этот метод копирует фактическое значение аргумента в формальный параметр функции. В этом случае изменения, внесенные в параметр внутри функции, не влияют на аргумент.

Этот метод копирует адрес аргумента в формальный параметр. Внутри функции адрес используется для доступа к фактическому аргументу, используемому в вызове. Это означает, что изменения, внесенные в параметр, влияют на аргумент.

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

C – Правила области

Область действия в любом программировании – это область программы, в которой может существовать определенная переменная, и за пределами этой переменной к ней нельзя получить доступ. Есть три места, где переменные могут быть объявлены на языке программирования C –

  • Внутри функции или блока, который называется локальными переменными.

  • Снаружи всех функций, которые называются глобальными переменными.

  • В определении параметров функции, которые называются формальными параметрами.

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

Снаружи всех функций, которые называются глобальными переменными.

В определении параметров функции, которые называются формальными параметрами.

Давайте разберемся, что такое локальные и глобальные переменные, а также формальные параметры.

Локальные переменные

Переменные, которые объявлены внутри функции или блока, называются локальными переменными. Они могут использоваться только операторами, которые находятся внутри этой функции или блока кода. Локальные переменные не известны функциям вне их собственных. В следующем примере показано, как используются локальные переменные. Здесь все переменные a, b и c являются локальными для функции main ().

Live Demo

 #include <stdio.h>
 
 int main () {

   / * объявление локальной переменной * /
   int a, b;
   int c;
 
   / * фактическая инициализация * /
   а = 10;
   б = 20;
   с = а + б;
 
   printf («значение a =% d, b =% d и c =% d  n», a, b, c);
 
   вернуть 0;
 }

Глобальные переменные

Глобальные переменные определяются вне функции, обычно в верхней части программы. Глобальные переменные хранят свои значения в течение всего жизненного цикла вашей программы, и к ним можно получить доступ в любой из функций, определенных для программы.

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

Live Demo

#include <stdio.h>
 
/* global variable declaration */
int g;
 
int main () {

  /* local variable declaration */
  int a, b;
 
  /* actual initialization */
  a = 10;
  b = 20;
  g = a + b;
 
  printf ("value of a = %d, b = %d and g = %dn", a, b, g);
 
  return 0;
}

Программа может иметь одинаковые имена для локальных и глобальных переменных, но предпочтение будет отдаваться значению локальной переменной внутри функции. Вот пример –

Live Demo

#include <stdio.h>
 
/* global variable declaration */
int g = 20;
 
int main () {

  /* local variable declaration */
  int g = 10;
 
  printf ("value of g = %dn",  g);
 
  return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

value of g = 10

Формальные параметры

Формальные параметры обрабатываются как локальные переменные внутри функции и имеют приоритет над глобальными переменными. Ниже приведен пример –

Live Demo

#include <stdio.h>
 
/* global variable declaration */
int a = 20;
 
int main () {

  /* local variable declaration in main function */
  int a = 10;
  int b = 20;
  int c = 0;

  printf ("value of a in main() = %dn",  a);
  c = sum( a, b);
  printf ("value of c in main() = %dn",  c);

  return 0;
}

/* function to add two integers */
int sum(int a, int b) {

   printf ("value of a in sum() = %dn",  a);
   printf ("value of b in sum() = %dn",  b);

   return a + b;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

value of a in main() = 10
value of a in sum() = 10
value of b in sum() = 20
value of c in main() = 30

Инициализация локальных и глобальных переменных

Когда определена локальная переменная, она не инициализируется системой, вы должны инициализировать ее самостоятельно. Глобальные переменные автоматически инициализируются системой, когда вы определяете их следующим образом:

Тип данных Начальное значение по умолчанию
ИНТ 0
голец ‘ 0’
поплавок 0
двойной 0
указатель НОЛЬ

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

C – Массивы

Массивы – это структура данных, в которой можно хранить последовательную коллекцию элементов одного и того же типа. Массив используется для хранения коллекции данных, но часто более полезно думать о массиве как о коллекции переменных одного типа.

Вместо того, чтобы объявлять отдельные переменные, такие как number0, number1, … и number99, вы объявляете одну переменную массива, такую ​​как числа, и используете числа [0], числа [1] и …, числа [99] для представления отдельные переменные. Определенный элемент в массиве доступен по индексу.

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

Массивы в Си

Объявление массивов

Чтобы объявить массив в C, программист определяет тип элементов и количество элементов, требуемых массивом, следующим образом:

type arrayName [ arraySize ];

Это называется одномерным массивом. ArraySize должен быть целочисленной константой, большей нуля, и тип может быть любым допустимым типом данных C. Например, чтобы объявить массив из 10 элементов с именем balance типа double, используйте этот оператор –

double balance[10];

Здесь баланс – это переменная, которой достаточно для хранения до 10 двойных чисел.

Инициализация массивов

Вы можете инициализировать массив в C один за другим или использовать один оператор следующим образом:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

Число значений в фигурных скобках {} не может быть больше, чем количество элементов, которые мы объявляем для массива в квадратных скобках [].

Если вы опустите размер массива, будет создан массив, достаточно большой, чтобы вместить инициализацию. Поэтому, если вы напишите –

double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

Вы создадите точно такой же массив, как и в предыдущем примере. Ниже приведен пример назначения одного элемента массива:

balance[4] = 50.0;

Приведенный выше оператор присваивает 5- й элемент в массиве со значением 50,0. Все массивы имеют 0 в качестве индекса своего первого элемента, который также называется базовым индексом, а последний индекс массива будет иметь общий размер массива минус 1. Ниже показано графическое представление массива, который мы обсуждали выше –

Презентация массива

Доступ к элементам массива

Доступ к элементу осуществляется путем индексации имени массива. Это делается путем помещения индекса элемента в квадратные скобки после имени массива. Например –

double salary = balance[9];

Приведенный выше оператор возьмет 10- й элемент из массива и присвоит значение переменной salary. В следующем примере показано, как использовать все три вышеупомянутых понятия, а именно. объявление, присваивание и доступ к массивам –

Live Demo

#include <stdio.h>
 
int main () {

   int n[ 10 ]; /* n is an array of 10 integers */
   int i,j;
 
   /* initialize elements of array n to 0 */         
   for ( i = 0; i < 10; i++ ) {
      n[ i ] = i + 100; /* set element at location i to i + 100 */
   }
   
   /* output each array element's value */
   for (j = 0; j < 10; j++ ) {
      printf("Element[%d] = %dn", j, n[j] );
   }
 
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

Массивы в деталях

Массивы важны для C и должны уделять гораздо больше внимания. Следующие важные понятия, связанные с массивом, должны быть понятны программисту C –

Sr.No. Концепция и описание
1 Многомерные массивы

C поддерживает многомерные массивы. Простейшей формой многомерного массива является двумерный массив.

2 Передача массивов в функции

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

3 Возврат массива из функции

C позволяет функции возвращать массив.

4 Указатель на массив

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

C поддерживает многомерные массивы. Простейшей формой многомерного массива является двумерный массив.

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

C позволяет функции возвращать массив.

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

C – указатели

Указатели на C легки и интересны для изучения. Некоторые задачи программирования на Си легче выполняются с помощью указателей, а другие задачи, такие как динамическое распределение памяти, не могут быть выполнены без использования указателей. Поэтому становится необходимым изучать указатели, чтобы стать идеальным программистом Си. Давайте начнем изучать их в простых и легких шагах.

Как вы знаете, каждая переменная является ячейкой памяти, и каждая ячейка памяти имеет свой адрес, к которому можно обратиться, используя оператор амперсанда (&), который обозначает адрес в памяти. Рассмотрим следующий пример, который печатает адрес определенных переменных:

Live Demo

#include <stdio.h>

int main () {

   int  var1;
   char var2[10];

   printf("Address of var1 variable: %xn", &var1  );
   printf("Address of var2 variable: %xn", &var2  );

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Address of var1 variable: bff5a400
Address of var2 variable: bff5a3f6

Что такое указатели?

Указатель – это переменная, значением которой является адрес другой переменной, т. Е. Прямой адрес ячейки памяти. Как и любая переменная или константа, вы должны объявить указатель, прежде чем использовать его для хранения любого адреса переменной. Общая форма объявления переменной указателя –

type *var-name;

Здесь тип – это базовый тип указателя; это должен быть допустимый тип данных C, а var-name – это имя переменной-указателя. Звездочка *, используемая для объявления указателя, такая же, как звездочка, используемая для умножения. Однако в этом утверждении звездочка используется для обозначения переменной в качестве указателя. Взгляните на некоторые из допустимых объявлений указателей –

int    *ip;    /* pointer to an integer */
double *dp;    /* pointer to a double */
float  *fp;    /* pointer to a float */
char   *ch     /* pointer to a character */

Фактический тип данных значения всех указателей, будь то целое число, число с плавающей запятой, символ или другое, является одним и тем же, длинное шестнадцатеричное число, представляющее адрес памяти. Единственное различие между указателями разных типов данных – это тип данных переменной или константы, на которую указывает указатель.

Как использовать указатели?

Есть несколько важных операций, которые мы будем делать с помощью указателей очень часто. (а) мы определяем переменную указателя, (б) назначаем адрес переменной указателю и (в) наконец получаем доступ к значению по адресу, доступному в переменной указателя. Это делается с помощью унарного оператора *, который возвращает значение переменной, расположенной по адресу, указанному ее операндом. В следующем примере используются эти операции –

Live Demo

#include <stdio.h>

int main () {

   int  var = 20;   /* actual variable declaration */
   int  *ip;        /* pointer variable declaration */

   ip = &var;  /* store address of var in pointer variable*/

   printf("Address of var variable: %xn", &var  );

   /* address stored in pointer variable */
   printf("Address stored in ip variable: %xn", ip );

   /* access the value using the pointer */
   printf("Value of *ip variable: %dn", *ip );

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20

NULL указатели

Хорошей практикой всегда является присвоение значения NULL переменной-указателю, если у вас нет точного адреса для назначения. Это делается во время объявления переменной. Указатель, которому присвоен NULL, называется нулевым указателем.

Указатель NULL – это константа со значением ноль, определенная в нескольких стандартных библиотеках. Рассмотрим следующую программу –

Live Demo

#include <stdio.h>

int main () {

   int  *ptr = NULL;

   printf("The value of ptr is : %xn", ptr  );
 
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

The value of ptr is 0

В большинстве операционных систем программам не разрешен доступ к памяти по адресу 0, поскольку эта память зарезервирована операционной системой. Однако адрес памяти 0 имеет особое значение; он сигнализирует о том, что указатель не предназначен для указания на доступную ячейку памяти. Но по соглашению, если указатель содержит нулевое (нулевое) значение, предполагается, что он ничего не указывает.

Чтобы проверить нулевой указатель, вы можете использовать оператор if следующим образом:

if(ptr)     /* succeeds if p is not null */
if(!ptr)    /* succeeds if p is null */

Указатели в деталях

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

Sr.No. Концепция и описание
1 Арифметика указателей

В указателях можно использовать четыре арифметических оператора: ++, -, +, –

2 Массив указателей

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

3 Указатель на указатель

C позволяет вам иметь указатель на указатель и так далее.

4 Передача указателей на функции в C

Передача аргумента по ссылке или по адресу позволяет вызывающему функции изменять переданный аргумент в вызывающей функции.

5 Возврат указателя из функций в C

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

В указателях можно использовать четыре арифметических оператора: ++, -, +, –

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

C позволяет вам иметь указатель на указатель и так далее.

Передача аргумента по ссылке или по адресу позволяет вызывающему функции изменять переданный аргумент в вызывающей функции.

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

C – Струны

Строки на самом деле являются одномерным массивом символов, оканчивающихся нулевым символом ‘ 0’. Таким образом, строка с нулевым символом в конце содержит символы, которые составляют строку, за которой следует ноль .

Следующее объявление и инициализация создают строку, состоящую из слова «Hello». Чтобы держать нулевой символ в конце массива, размер массива символов, содержащего строку, на один больше, чем количество символов в слове «Hello».

char greeting[6] = {'H', 'e', 'l', 'l', 'o', ''};

Если вы следуете правилу инициализации массива, вы можете написать приведенное выше утверждение следующим образом:

char greeting[] = "Hello";

Ниже приводится представление в памяти определенной выше строки в C / C ++ –

Строковая презентация в C / C ++

На самом деле, вы не помещаете нулевой символ в конец строковой константы. Компилятор C автоматически помещает ‘ 0’ в конец строки, когда инициализирует массив. Давайте попробуем напечатать вышеупомянутую строку –

Live Demo

#include <stdio.h>

int main () {

   char greeting[6] = {'H', 'e', 'l', 'l', 'o', ''};
   printf("Greeting message: %sn", greeting );
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Greeting message: Hello

C поддерживает широкий спектр функций, которые обрабатывают строки с нулевым символом в конце –

Sr.No. Функция и цель
1

strcpy (s1, s2);

Копирует строку s2 в строку s1.

2

strcat (s1, s2);

Объединяет строку s2 в конец строки s1.

3

StrLen (S1);

Возвращает длину строки s1.

4

strcmp (s1, s2);

Возвращает 0, если s1 и s2 одинаковы; меньше 0, если s1 <s2; больше 0, если s1> s2.

5

strchr (s1, ch);

Возвращает указатель на первое вхождение символа ch в строке s1.

6

strstr (s1, s2);

Возвращает указатель на первое вхождение строки s2 в строку s1.

strcpy (s1, s2);

Копирует строку s2 в строку s1.

strcat (s1, s2);

Объединяет строку s2 в конец строки s1.

StrLen (S1);

Возвращает длину строки s1.

strcmp (s1, s2);

Возвращает 0, если s1 и s2 одинаковы; меньше 0, если s1 <s2; больше 0, если s1> s2.

strchr (s1, ch);

Возвращает указатель на первое вхождение символа ch в строке s1.

strstr (s1, s2);

Возвращает указатель на первое вхождение строки s2 в строку s1.

В следующем примере используются некоторые из вышеупомянутых функций –

Live Demo

#include <stdio.h>
#include <string.h>

int main () {

   char str1[12] = "Hello";
   char str2[12] = "World";
   char str3[12];
   int  len ;

   /* copy str1 into str3 */
   strcpy(str3, str1);
   printf("strcpy( str3, str1) :  %sn", str3 );

   /* concatenates str1 and str2 */
   strcat( str1, str2);
   printf("strcat( str1, str2):   %sn", str1 );

   /* total lenghth of str1 after concatenation */
   len = strlen(str1);
   printf("strlen(str1) :  %dn", len );

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

strcpy( str3, str1) :  Hello
strcat( str1, str2):   HelloWorld
strlen(str1) :  10

C – Структуры

Массивы позволяют определить тип переменных, которые могут содержать несколько элементов данных одного вида. Аналогичным образом структура – это еще один определяемый пользователем тип данных, доступный в C, который позволяет объединять элементы данных разных типов.

Структуры используются для представления записи. Предположим, вы хотите отслеживать свои книги в библиотеке. Вы можете отслеживать следующие атрибуты о каждой книге –

  • заглавие
  • автор
  • Предмет
  • ID книги

Определение структуры

Чтобы определить структуру, вы должны использовать инструкцию struct . Оператор struct определяет новый тип данных с более чем одним членом. Формат оператора структуры следующий:

struct [structure tag] {

   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];  

Тег структуры является необязательным, и каждое определение члена является обычным определением переменной, например int i; или плавать f; или любое другое допустимое определение переменной. В конце определения структуры перед последней точкой с запятой вы можете указать одну или несколько переменных структуры, но это не обязательно. Вот как вы бы объявили структуру Книги –

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;  

Доступ к членам структуры

Чтобы получить доступ к любому члену структуры, мы используем оператор доступа к члену (.) . Оператор доступа к элементу кодируется как точка между именем структурной переменной и элементом структуры, к которому мы хотим получить доступ. Вы бы использовали ключевое слово struct для определения переменных типа структуры. В следующем примере показано, как использовать структуру в программе.

Live Demo

#include <stdio.h>
#include <string.h>
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* print Book1 info */
   printf( "Book 1 title : %sn", Book1.title);
   printf( "Book 1 author : %sn", Book1.author);
   printf( "Book 1 subject : %sn", Book1.subject);
   printf( "Book 1 book_id : %dn", Book1.book_id);

   /* print Book2 info */
   printf( "Book 2 title : %sn", Book2.title);
   printf( "Book 2 author : %sn", Book2.author);
   printf( "Book 2 subject : %sn", Book2.subject);
   printf( "Book 2 book_id : %dn", Book2.book_id);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

Структуры как аргументы функций

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

Live Demo

#include <stdio.h>
#include <string.h>
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* function declaration */
void printBook( struct Books book );

int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* print Book1 info */
   printBook( Book1 );

   /* Print Book2 info */
   printBook( Book2 );

   return 0;
}

void printBook( struct Books book ) {

   printf( "Book title : %sn", book.title);
   printf( "Book author : %sn", book.author);
   printf( "Book subject : %sn", book.subject);
   printf( "Book book_id : %dn", book.book_id);
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

Указатели на структуры

Вы можете определять указатели на структуры так же, как вы определяете указатель на любую другую переменную –

struct Books *struct_pointer;

Теперь вы можете сохранить адрес структурной переменной в указанной выше переменной-указателе. Чтобы найти адрес структурной переменной, поместите ‘&’; оператор перед именем структуры следующим образом –

struct_pointer = &Book1;

Чтобы получить доступ к членам структуры, используя указатель на эту структуру, вы должны использовать оператор → следующим образом:

struct_pointer->title;

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

Live Demo

#include <stdio.h>
#include <string.h>
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* function declaration */
void printBook( struct Books *book );
int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* print Book1 info by passing address of Book1 */
   printBook( &Book1 );

   /* print Book2 info by passing address of Book2 */
   printBook( &Book2 );

   return 0;
}

void printBook( struct Books *book ) {

   printf( "Book title : %sn", book->title);
   printf( "Book author : %sn", book->author);
   printf( "Book subject : %sn", book->subject);
   printf( "Book book_id : %dn", book->book_id);
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

Битовые поля

Битовые поля позволяют упаковывать данные в структуру. Это особенно полезно, когда память или хранилище данных стоят дорого. Типичные примеры включают –

  • Упаковка нескольких объектов в машинное слово. например, 1-битные флаги могут быть сжаты.

  • Чтение внешних форматов файлов – могут быть прочитаны нестандартные форматы файлов, например, 9-разрядные целые числа.

Упаковка нескольких объектов в машинное слово. например, 1-битные флаги могут быть сжаты.

Чтение внешних форматов файлов – могут быть прочитаны нестандартные форматы файлов, например, 9-разрядные целые числа.

C позволяет нам сделать это в определении структуры, поместив: bit length после переменной. Например –

struct packed_struct {
   unsigned int f1:1;
   unsigned int f2:1;
   unsigned int f3:1;
   unsigned int f4:1;
   unsigned int type:4;
   unsigned int my_int:9;
} pack;

Здесь pack_struct содержит 6 членов: четыре 1-битных флага f1..f3, 4-битный тип и 9-битный my_int.

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

C – Союзы

Объединение – это специальный тип данных, доступный в C, который позволяет хранить разные типы данных в одной и той же ячейке памяти. Вы можете определить объединение со многими членами, но только один член может содержать значение в любой момент времени. Союзы предоставляют эффективный способ использования одной и той же области памяти для многоцелевого использования.

Определение союза

Чтобы определить объединение, вы должны использовать оператор объединения так же, как при определении структуры. Оператор union определяет новый тип данных с более чем одним членом для вашей программы. Формат заявления объединения следующий:

union [union tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];  

Тег объединения является необязательным, и каждое определение члена является обычным определением переменной, например int i; или плавать f; или любое другое допустимое определение переменной. В конце определения объединения перед последней точкой с запятой вы можете указать одну или несколько переменных объединения, но это необязательно. Вот как вы можете определить тип объединения с именем Data, имеющий три члена i, f и str.

union Data {
   int i;
   float f;
   char str[20];
} data;  

Теперь переменная типа Data может хранить целое число, число с плавающей точкой или строку символов. Это означает, что одна переменная, т. Е. Одна и та же ячейка памяти, может использоваться для хранения нескольких типов данных. Вы можете использовать любые встроенные или определенные пользователем типы данных внутри объединения в зависимости от ваших требований.

Память, занятая профсоюзом, будет достаточно большой, чтобы вместить самого крупного члена профсоюза. Например, в приведенном выше примере тип данных будет занимать 20 байт пространства памяти, поскольку это максимальное пространство, которое может занимать строка символов. В следующем примере показан общий объем памяти, занимаемый вышеуказанным объединением –

Live Demo

#include <stdio.h>
#include <string.h>
 
union Data {
   int i;
   float f;
   char str[20];
};
 
int main( ) {

   union Data data;        

   printf( "Memory size occupied by data : %dn", sizeof(data));

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Memory size occupied by data : 20

Доступ к членам Союза

Чтобы получить доступ к любому члену профсоюза, мы используем оператор доступа члена (.) . Оператор доступа к члену кодируется как точка между именем переменной объединения и членом объединения, к которому мы хотим получить доступ. Вы бы использовали ключевое слово union для определения переменных типа union. В следующем примере показано, как использовать объединения в программе –

Live Demo

#include <stdio.h>
#include <string.h>
 
union Data {
   int i;
   float f;
   char str[20];
};
 
int main( ) {

   union Data data;        

   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");

   printf( "data.i : %dn", data.i);
   printf( "data.f : %fn", data.f);
   printf( "data.str : %sn", data.str);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

Здесь мы можем видеть, что значения членов i и f объединения были повреждены, потому что последнее значение, присвоенное переменной, заняло место в памяти, и это является причиной того, что значение члена str печатается очень хорошо.

Теперь давайте снова посмотрим на тот же пример, где мы будем использовать одну переменную за раз, что является основной целью создания объединений –

Live Demo

#include <stdio.h>
#include <string.h>
 
union Data {
   int i;
   float f;
   char str[20];
};
 
int main( ) {

   union Data data;        

   data.i = 10;
   printf( "data.i : %dn", data.i);
   
   data.f = 220.5;
   printf( "data.f : %fn", data.f);
   
   strcpy( data.str, "C Programming");
   printf( "data.str : %sn", data.str);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

data.i : 10
data.f : 220.500000
data.str : C Programming

Здесь все участники печатаются очень хорошо, потому что один член используется за один раз.

C – битовые поля

Предположим, что ваша C-программа содержит несколько переменных TRUE / FALSE, сгруппированных в структуру, называемую status, следующим образом:

struct {
   unsigned int widthValidated;
   unsigned int heightValidated;
} status;

Эта структура требует 8 байт памяти, но в действительности мы собираемся хранить 0 или 1 в каждой из переменных. Язык программирования C предлагает лучший способ использовать пространство памяти в таких ситуациях.

Если вы используете такие переменные внутри структуры, вы можете определить ширину переменной, которая сообщает компилятору C, что вы собираетесь использовать только это количество байтов. Например, приведенная выше структура может быть переписана следующим образом:

struct {
   unsigned int widthValidated : 1;
   unsigned int heightValidated : 1;
} status;

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

Если вы будете использовать до 32 переменных, каждая из которых имеет ширину 1 бит, то в структуре состояния также будет использоваться 4 байта. Однако, как только у вас будет 33 переменные, он выделит следующий слот памяти и начнет использовать 8 байтов. Давайте проверим следующий пример, чтобы понять концепцию –

Live Demo

#include <stdio.h>
#include <string.h>

/* define simple structure */
struct {
   unsigned int widthValidated;
   unsigned int heightValidated;
} status1;

/* define a structure with bit fields */
struct {
   unsigned int widthValidated : 1;
   unsigned int heightValidated : 1;
} status2;
 
int main( ) {
   printf( "Memory size occupied by status1 : %dn", sizeof(status1));
   printf( "Memory size occupied by status2 : %dn", sizeof(status2));
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Memory size occupied by status1 : 8
Memory size occupied by status2 : 4

Объявление битового поля

Объявление битового поля имеет следующую форму внутри структуры:

struct {
   type [member_name] : width ;
};

В следующей таблице описаны переменные элементы битового поля –

Sr.No. Элемент и описание
1

тип

Целочисленный тип, который определяет, как интерпретируется значение битового поля. Тип может быть int, подписанный int или беззнаковый int.

2

имя участника

Название битового поля.

3

ширина

Количество битов в битовом поле. Ширина должна быть меньше или равна битовой ширине указанного типа.

тип

Целочисленный тип, который определяет, как интерпретируется значение битового поля. Тип может быть int, подписанный int или беззнаковый int.

имя участника

Название битового поля.

ширина

Количество битов в битовом поле. Ширина должна быть меньше или равна битовой ширине указанного типа.

Переменные, определенные с предопределенной шириной, называются битовыми полями . Битовое поле может содержать более одного бита; например, если вам нужна переменная для хранения значения от 0 до 7, вы можете определить битовое поле шириной 3 бита следующим образом:

struct {
   unsigned int age : 3;
} Age;

Приведенное выше определение структуры указывает компилятору C, что переменная age будет использовать только 3 бита для хранения значения. Если вы попытаетесь использовать более 3 бит, то это не позволит вам сделать это. Давайте попробуем следующий пример –

Live Demo

#include <stdio.h>
#include <string.h>

struct {
   unsigned int age : 3;
} Age;

int main( ) {

   Age.age = 4;
   printf( "Sizeof( Age ) : %dn", sizeof(Age) );
   printf( "Age.age : %dn", Age.age );

   Age.age = 7;
   printf( "Age.age : %dn", Age.age );

   Age.age = 8;
   printf( "Age.age : %dn", Age.age );

   return 0;
}

Когда приведенный выше код компилируется, он компилируется с предупреждением, а при выполнении выдает следующий результат:

Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0

C – typedef

Язык программирования C предоставляет ключевое слово typedef , которое можно использовать для присвоения типу нового имени. Ниже приведен пример определения термина BYTE для однобайтовых чисел:

typedef unsigned char BYTE;

После этого определения типа идентификатор BYTE может использоваться, например, как сокращение для типа unsigned char. ,

BYTE  b1, b2;

По соглашению, в этих определениях используются заглавные буквы, чтобы напомнить пользователю, что имя типа действительно является символическим сокращением, но вы можете использовать строчные буквы следующим образом:

typedef unsigned char byte;

Вы также можете использовать typedef, чтобы дать имя вашим пользовательским типам данных. Например, вы можете использовать typedef со структурой для определения нового типа данных, а затем использовать этот тип данных для непосредственного определения структурных переменных следующим образом:

Live Demo

#include <stdio.h>
#include <string.h>
 
typedef struct Books {
   char title[50];
   char author[50];
   char subject[100];
   int book_id;
} Book;
 
int main( ) {

   Book book;
 
   strcpy( book.title, "C Programming");
   strcpy( book.author, "Nuha Ali"); 
   strcpy( book.subject, "C Programming Tutorial");
   book.book_id = 6495407;
 
   printf( "Book title : %sn", book.title);
   printf( "Book author : %sn", book.author);
   printf( "Book subject : %sn", book.subject);
   printf( "Book book_id : %dn", book.book_id);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Book  title : C Programming
Book  author : Nuha Ali
Book  subject : C Programming Tutorial
Book  book_id : 6495407

typedef против #define

#define – это C-директива, которая также используется для определения псевдонимов для различных типов данных, аналогичных typedef, но со следующими отличиями:

  • typedef ограничен предоставлением символических имен только для типов, где как #define может использоваться для определения псевдонима для значений, q. вы можете определить 1 как ONE и т. д.

  • Интерпретация typedef выполняется компилятором, тогда как операторы #define обрабатываются препроцессором.

typedef ограничен предоставлением символических имен только для типов, где как #define может использоваться для определения псевдонима для значений, q. вы можете определить 1 как ONE и т. д.

Интерпретация typedef выполняется компилятором, тогда как операторы #define обрабатываются препроцессором.

В следующем примере показано, как использовать #define в программе –

Live Demo

#include <stdio.h>
 
#define TRUE  1
#define FALSE 0
 
int main( ) {
   printf( "Value of TRUE : %dn", TRUE);
   printf( "Value of FALSE : %dn", FALSE);

   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Value of TRUE : 1
Value of FALSE : 0

C – вход и выход

Когда мы говорим « Ввод» , это означает ввод некоторых данных в программу. Входные данные могут быть предоставлены в форме файла или из командной строки. Программирование на С предоставляет набор встроенных функций для считывания заданного ввода и подачи его в программу согласно требованию.

Когда мы говорим « Вывод» , это означает отображение некоторых данных на экране, принтере или в любом файле. С-программирование предоставляет набор встроенных функций для вывода данных на экран компьютера, а также для сохранения их в текстовых или двоичных файлах.

Стандартные файлы

C программирование рассматривает все устройства как файлы. Таким образом, такие устройства, как дисплей, адресуются так же, как и файлы, и следующие три файла автоматически открываются при запуске программы для обеспечения доступа к клавиатуре и экрану.

Стандартный файл Файловый указатель устройство
Стандартный ввод STDIN клавиатура
Стандартный вывод стандартный вывод экран
Стандартная ошибка STDERR Ваш экран

Файловые указатели являются средством доступа к файлу для чтения и записи. В этом разделе объясняется, как считывать значения с экрана и как печатать результат на экране.

Функции getchar () и putchar ()

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

Функция int putchar (int c) помещает переданный символ на экран и возвращает тот же символ. Эта функция помещает только один символ за раз. Вы можете использовать этот метод в цикле, если вы хотите отобразить более одного символа на экране. Проверьте следующий пример –

#include <stdio.h>
int main( ) {

   int c;

   printf( "Enter a value :");
   c = getchar( );

   printf( "nYou entered: ");
   putchar( c );

   return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он ждет, когда вы введете какой-то текст. Когда вы вводите текст и нажимаете ввод, программа продолжает работу и читает только один символ и отображает его следующим образом:

$./a.out
Enter a value : this is test
You entered: t

Функции gets () и put ()

Функция char * gets (char * s) считывает строку из stdin в буфер, на который указывает s, до завершающей строки или EOF (End of File).

Функция int put (const char * s) записывает завершающие символы новой строки ‘s’ и ‘a’ в стандартный вывод .

#include <stdio.h>
int main( ) {

   char str[100];

   printf( "Enter a value :");
   gets( str );

   printf( "nYou entered: ");
   puts( str );

   return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он ждет, когда вы введете какой-то текст. Когда вы вводите текст и нажимаете ввод, программа продолжает и читает всю строку до конца и отображает ее следующим образом:

$./a.out
Enter a value : this is test
You entered: this is test

Функции scanf () и printf ()

Функция int scanf (const char * format, …) считывает ввод из стандартного потока ввода stdin и сканирует этот ввод в соответствии с предоставленным форматом .

Функция int printf (const char * format, …) записывает вывод в стандартный поток вывода stdout и производит вывод в соответствии с предоставленным форматом.

Формат может быть простой константной строкой, но вы можете указать% s,% d,% c,% f и т. Д. Для печати или чтения строк, целых чисел, символов или с плавающей точкой соответственно. Есть много других доступных вариантов форматирования, которые можно использовать в зависимости от требований. Давайте теперь перейдем к простому примеру, чтобы лучше понять концепции –

#include <stdio.h>
int main( ) {

   char str[100];
   int i;

   printf( "Enter a value :");
   scanf("%s %d", str, &i);

   printf( "nYou entered: %s %d ", str, i);

   return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он ждет, когда вы введете какой-то текст. Когда вы вводите текст и нажимаете ввод, программа переходит и читает ввод и отображает его следующим образом:

$./a.out
Enter a value : seven 7
You entered: seven 7

Здесь следует отметить, что scanf () ожидает ввод в том же формате, что вы указали% s и% d, что означает, что вы должны предоставить допустимые вводы, такие как «строковое целое число». Если вы укажете «string string» или «integer integer», то это будет считаться неправильным вводом. Во-вторых, при чтении строки scanf () прекращает чтение, как только встречает пробел, поэтому «это тест» – три строки для scanf ().

C – File I / O

В последней главе описаны стандартные устройства ввода и вывода, которые обрабатываются языком программирования C. В этой главе рассказывается, как программисты на C могут создавать, открывать, закрывать текстовые или двоичные файлы для хранения своих данных.

Файл представляет собой последовательность байтов, независимо от того, является ли он текстовым файлом или двоичным файлом. Язык программирования C обеспечивает доступ к функциям высокого уровня, а также к вызовам низкого уровня (уровня ОС) для обработки файлов на ваших устройствах хранения. Эта глава проведет вас через важные призывы к управлению файлами.

Открытие файлов

Вы можете использовать функцию fopen (), чтобы создать новый файл или открыть существующий файл. Этот вызов инициализирует объект типа FILE , который содержит всю информацию, необходимую для управления потоком. Прототип этого вызова функции выглядит следующим образом:

FILE *fopen( const char * filename, const char * mode );

Здесь filename является строковым литералом, который вы будете использовать для именования вашего файла, а режим доступа может иметь одно из следующих значений:

Sr.No. Режим и описание
1

р

Открывает существующий текстовый файл для чтения.

2

вес

Открывает текстовый файл для записи. Если он не существует, то создается новый файл. Здесь ваша программа начнет запись содержимого с начала файла.

3

Открывает текстовый файл для записи в режиме добавления. Если он не существует, то создается новый файл. Здесь ваша программа начнет добавлять содержимое в существующий файл содержимого.

4

г +

Открывает текстовый файл для чтения и записи.

5

ш +

Открывает текстовый файл для чтения и записи. Сначала он обрезает файл до нулевой длины, если он существует, в противном случае создает файл, если он не существует.

6

а +

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

р

Открывает существующий текстовый файл для чтения.

вес

Открывает текстовый файл для записи. Если он не существует, то создается новый файл. Здесь ваша программа начнет запись содержимого с начала файла.

Открывает текстовый файл для записи в режиме добавления. Если он не существует, то создается новый файл. Здесь ваша программа начнет добавлять содержимое в существующий файл содержимого.

г +

Открывает текстовый файл для чтения и записи.

ш +

Открывает текстовый файл для чтения и записи. Сначала он обрезает файл до нулевой длины, если он существует, в противном случае создает файл, если он не существует.

а +

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

Если вы собираетесь обрабатывать двоичные файлы, вы будете использовать следующие режимы доступа вместо вышеупомянутых:

"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"

Закрытие файла

Чтобы закрыть файл, используйте функцию fclose (). Прототип этой функции –

int fclose( FILE *fp );

Функция fclose (-) возвращает ноль в случае успеха или EOF, если при закрытии файла произошла ошибка. Эта функция фактически сбрасывает любые данные, все еще ожидающие в буфере, в файл, закрывает файл и освобождает любую память, используемую для файла. EOF является константой, определенной в заголовочном файле stdio.h .

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

Написание файла

Ниже приводится простейшая функция для записи отдельных символов в поток.

int fputc( int c, FILE *fp );

Функция fputc () записывает символьное значение аргумента c в выходной поток, на который ссылается fp. Он возвращает письменный символ, написанный при успехе, в противном случае EOF, если есть ошибка. Вы можете использовать следующие функции для записи строки с нулевым символом в конце –

int fputs( const char *s, FILE *fp );

Функция fputs () записывает строку s в выходной поток, на который ссылается fp. Он возвращает неотрицательное значение в случае успеха, в противном случае EOF возвращается в случае любой ошибки. Вы также можете использовать функцию int fprintf (FILE * fp, const char * format, …) для записи строки в файл. Попробуйте следующий пример.

Убедитесь, что у вас есть каталог / tmp . Если это не так, то прежде чем продолжить, вы должны создать этот каталог на вашем компьютере.

#include <stdio.h>

main() {
   FILE *fp;

   fp = fopen("/tmp/test.txt", "w+");
   fprintf(fp, "This is testing for fprintf...n");
   fputs("This is testing for fputs...n", fp);
   fclose(fp);
}

Когда приведенный выше код компилируется и выполняется, он создает новый файл test.txt в каталоге / tmp и записывает две строки, используя две разные функции. Давайте прочитаем этот файл в следующем разделе.

Чтение файла

Ниже приведена простейшая функция для чтения одного символа из файла –

int fgetc( FILE * fp );

Функция fgetc () читает символ из входного файла, на который ссылается fp. Возвращаемым значением является прочитанный символ, или в случае любой ошибки он возвращает EOF . Следующая функция позволяет читать строку из потока –

char *fgets( char *buf, int n, FILE *fp );

Функция fgets () читает до n-1 символов из входного потока, на который ссылается fp. Он копирует прочитанную строку в буфер buf , добавляя нулевой символ для завершения строки.

Если эта функция встречает символ новой строки ‘ n’ или конец файла EOF до того, как они прочитают максимальное количество символов, то она возвращает только символы, считанные до этой точки, включая символ новой строки. Вы также можете использовать функцию int fscanf (FILE * fp, const char * format, …) для чтения строк из файла, но она прекращает чтение после обнаружения первого пробела.

#include <stdio.h>

main() {

   FILE *fp;
   char buff[255];

   fp = fopen("/tmp/test.txt", "r");
   fscanf(fp, "%s", buff);
   printf("1 : %sn", buff );

   fgets(buff, 255, (FILE*)fp);
   printf("2: %sn", buff );
   
   fgets(buff, 255, (FILE*)fp);
   printf("3: %sn", buff );
   fclose(fp);

}

Когда приведенный выше код компилируется и выполняется, он читает файл, созданный в предыдущем разделе, и выдает следующий результат:

1 : This
2: is testing for fprintf...

3: This is testing for fputs...

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

Двоичные функции ввода / вывода

Есть две функции, которые можно использовать для двоичного ввода и вывода –

size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
              
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);

Обе эти функции должны использоваться для чтения или записи блоков памяти – обычно массивов или структур.

C – препроцессоры

Препроцессор C не является частью компилятора, но является отдельным этапом в процессе компиляции. Проще говоря, препроцессор C – это всего лишь инструмент подстановки текста, который инструктирует компилятору выполнить необходимую предварительную обработку перед фактической компиляцией. Мы будем называть препроцессор C как CPP.

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

Sr.No. Директива и описание
1

#define

Заменяет макрос препроцессора.

2

#включают

Вставляет определенный заголовок из другого файла.

3

#undef

Определяет макрос препроцессора.

4

#ifdef

Возвращает true, если этот макрос определен.

5

#ifndef

Возвращает true, если этот макрос не определен.

6

#если

Проверяет, верно ли условие времени компиляции.

7

#else

Альтернатива для #if.

8

#elif

#else и #if в одном утверждении.

9

#endif

Завершает препроцессор условно.

10

#ошибка

Распечатывает сообщение об ошибке на stderr.

11

#pragma

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

#define

Заменяет макрос препроцессора.

#включают

Вставляет определенный заголовок из другого файла.

#undef

Определяет макрос препроцессора.

#ifdef

Возвращает true, если этот макрос определен.

#ifndef

Возвращает true, если этот макрос не определен.

#если

Проверяет, верно ли условие времени компиляции.

#else

Альтернатива для #if.

#elif

#else и #if в одном утверждении.

#endif

Завершает препроцессор условно.

#ошибка

Распечатывает сообщение об ошибке на stderr.

#pragma

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

Примеры препроцессоров

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

#define MAX_ARRAY_LENGTH 20

Эта директива указывает CPP заменять экземпляры MAX_ARRAY_LENGTH на 20. Используйте #define для констант для повышения читабельности.

#include <stdio.h>
#include "myheader.h"

Эти директивы сообщают CPP, что нужно получить stdio.h из системных библиотек и добавить текст в текущий исходный файл. Следующая строка говорит CPP, чтобы получить myheader.h из локального каталога и добавить содержимое в текущий исходный файл.

#undef  FILE_SIZE
#define FILE_SIZE 42

Он говорит CPP, чтобы отменить определение существующего FILE_SIZE и определить его как 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

Это говорит CPP, чтобы определить СООБЩЕНИЕ, только если СООБЩЕНИЕ еще не определено.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

Он говорит CPP обрабатывать приложенные операторы, если определен DEBUG. Это полезно, если вы передаете флаг -DDEBUG компилятору gcc во время компиляции. Это определит DEBUG, так что вы можете включать и выключать отладку на лету во время компиляции.

Предопределенные макросы

ANSI C определяет количество макросов. Хотя каждый из них доступен для использования в программировании, предопределенные макросы не должны изменяться напрямую.

Sr.No. Макрос и описание
1

__ДАТА__

Текущая дата в виде символьного литерала в формате “МММ ДД ГГГГ”.

2

__ВРЕМЯ__

Текущее время как символьный литерал в формате «ЧЧ: ММ: СС».

3

__ФАЙЛ__

Это содержит текущее имя файла в виде строкового литерала.

4

__ЛИНИЯ__

Он содержит номер текущей строки в виде десятичной константы.

5

__STDC__

Определяется как 1, когда компилятор соответствует стандарту ANSI.

__ДАТА__

Текущая дата в виде символьного литерала в формате “МММ ДД ГГГГ”.

__ВРЕМЯ__

Текущее время как символьный литерал в формате «ЧЧ: ММ: СС».

__ФАЙЛ__

Это содержит текущее имя файла в виде строкового литерала.

__ЛИНИЯ__

Он содержит номер текущей строки в виде десятичной константы.

__STDC__

Определяется как 1, когда компилятор соответствует стандарту ANSI.

Давайте попробуем следующий пример –

Live Demo

#include <stdio.h>

int main() {

   printf("File :%sn", __FILE__ );
   printf("Date :%sn", __DATE__ );
   printf("Time :%sn", __TIME__ );
   printf("Line :%dn", __LINE__ );
   printf("ANSI :%dn", __STDC__ );

}

Когда приведенный выше код в файле test.c компилируется и выполняется, он дает следующий результат –

File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1

Операторы препроцессора

Препроцессор C предлагает следующие операторы для создания макросов:

Оператор продолжения макроса ()

Макрос обычно ограничен одной строкой. Оператор продолжения макроса () используется для продолжения макроса, который слишком длинный для одной строки. Например –

#define  message_for(a, b)  
   printf(#a " and " #b ": We love you!n")

Оператор Stringize (#)

Оператор stringize или number-sign (‘#’), когда используется в определении макроса, преобразует параметр макроса в строковую константу. Этот оператор может использоваться только в макросе с указанным аргументом или списком параметров. Например –

Live Demo

#include <stdio.h>

#define  message_for(a, b)  
   printf(#a " and " #b ": We love you!n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Carole and Debra: We love you!

Оператор вставки токена (##)

Оператор вставки токена (##) в определении макроса объединяет два аргумента. Он позволяет объединить два отдельных токена в определении макроса в один токен. Например –

Live Demo

#include <stdio.h>

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   tokenpaster(34);
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

token34 = 40

Это произошло так, потому что этот пример приводит к следующему фактическому выводу препроцессора –

printf ("token34 = %d", token34);

В этом примере показано объединение токена ## n в token34, и здесь мы использовали как stringize, так и вставку токена .

Определенный () оператор

Определяемый препроцессором оператор используется в константных выражениях, чтобы определить, определен ли идентификатор с помощью #define. Если указанный идентификатор определен, значение равно true (не ноль). Если символ не определен, значение равно false (ноль). Определенный оператор указан следующим образом:

Live Demo

#include <stdio.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   printf("Here is the message: %sn", MESSAGE);  
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Here is the message: You wish!

Параметризованные макросы

Одной из мощных функций CPP является возможность имитировать функции с помощью параметризованных макросов. Например, у нас может быть некоторый код для возведения в квадрат числа следующим образом:

int square(int x) {
   return x * x;
}

Мы можем переписать код выше с помощью макроса следующим образом:

#define square(x) ((x) * (x))

Макросы с аргументами должны быть определены с использованием директивы #define, прежде чем их можно будет использовать. Список аргументов заключен в круглые скобки и должен следовать сразу за именем макроса. Пробелы между именем макроса и открытыми скобками не допускаются. Например –

Live Demo

#include <stdio.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   printf("Max between 20 and 10 is %dn", MAX(10, 20));  
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Max between 20 and 10 is 20

C – Заголовочные файлы

Заголовочный файл – это файл с расширением .h, который содержит объявления функций C и определения макросов для совместного использования несколькими исходными файлами. Существует два типа заголовочных файлов: файлы, которые пишет программист, и файлы, поставляемые с вашим компилятором.

Вы просите использовать файл заголовка в своей программе, включив его в директиву предварительной обработки C #include , как вы видели включение заголовочного файла stdio.h , который поставляется вместе с вашим компилятором.

Включение файла заголовка равнозначно копированию содержимого файла заголовка, но мы этого не делаем, потому что это будет подвержено ошибкам, и не стоит копировать содержимое файла заголовка в исходные файлы, особенно если мы иметь несколько исходных файлов в программе.

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

Включить синтаксис

И пользовательские, и системные заголовочные файлы включаются с использованием директивы предварительной обработки #include . Он имеет следующие две формы –

#include <file>

Эта форма используется для системных заголовочных файлов. Он ищет файл с именем «file» в стандартном списке системных каталогов. Вы можете добавить каталоги к этому списку с помощью опции -I при компиляции исходного кода.

#include "file"

Эта форма используется для заголовочных файлов вашей собственной программы. Он ищет файл с именем «file» в каталоге, содержащем текущий файл. Вы можете добавить каталоги к этому списку с помощью опции -I при компиляции исходного кода.

Включить операцию

Директива #include работает, заставляя препроцессор C сканировать указанный файл в качестве входных данных, прежде чем продолжить работу с остальной частью текущего исходного файла. Выходные данные препроцессора содержат уже сгенерированные выходные данные, за которыми следуют выходные данные из включенного файла, а затем выходные данные из текста после директивы #include . Например, если у вас есть файл заголовка header.h как показано ниже:

char *test (void);

и основная программа с именем program.c, которая использует заголовочный файл, например:

int x;
#include "header.h"

int main (void) {
   puts (test ());
}

компилятор увидит тот же поток токенов, что и при чтении program.c

int x;
char *test (void);

int main (void) {
   puts (test ());
}

Заголовки только один раз

Если заголовочный файл будет включен дважды, компилятор обработает его содержимое дважды, что приведет к ошибке. Стандартный способ предотвратить это состоит в том, чтобы заключить все реальное содержимое файла в условное выражение, например:

#ifndef HEADER_FILE
#define HEADER_FILE

the entire header file file

#endif

Эта конструкция широко известна как оболочка #ifndef . Когда заголовок включается снова, условное будет ложным, потому что определено HEADER_FILE. Препроцессор пропустит все содержимое файла, и компилятор не увидит его дважды.

Вычисляется Включает

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

#if SYSTEM_1
   # include "system_1.h"
#elif SYSTEM_2
   # include "system_2.h"
#elif SYSTEM_3
   ...
#endif

Но по мере роста он становится утомительным, вместо этого препроцессор предлагает возможность использовать макрос для имени заголовка. Это называется вычисленным включением . Вместо того, чтобы писать имя заголовка в качестве прямого аргумента #include , вы просто помещаете туда имя макроса –

#define SYSTEM_H "system_1.h"
...
#include SYSTEM_H

SYSTEM_H будет расширен, и препроцессор будет искать system_1.h, как если бы изначально был написан #include . SYSTEM_H может быть определен вашим Makefile с опцией -D.

C – Тип литья

Приведение типов – это способ преобразования переменной из одного типа данных в другой тип данных. Например, если вы хотите сохранить значение ‘long’ в простое целое число, вы можете ввести cast ‘long’ в ‘int’. Вы можете явно преобразовать значения из одного типа в другой, используя оператор приведения, следующим образом:

(type_name) expression

Рассмотрим следующий пример, где оператор приведения заставляет деление одной целочисленной переменной на другую как операцию с плавающей запятой:

Live Demo

#include <stdio.h>

main() {

   int sum = 17, count = 5;
   double mean;

   mean = (double) sum / count;
   printf("Value of mean : %fn", mean );
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Value of mean : 3.400000

Здесь следует отметить, что оператор приведения имеет приоритет над делением, поэтому значение суммы сначала преобразуется в тип double и, наконец, оно делится на число, что приводит к двойному значению.

Преобразования типов могут быть неявными, которые выполняются компилятором автоматически, или они могут быть определены явно с помощью оператора приведения . Хорошей практикой программирования считается использование оператора приведения, когда необходимо преобразование типа.

Целочисленное продвижение

Целочисленное продвижение – это процесс, при котором значения целочисленного типа «меньше», чем int или unsigned int , преобразуются либо в int, либо в unsigned int . Рассмотрим пример добавления символа с целым числом –

Live Demo

#include <stdio.h>

main() {

   int  i = 17;
   char c = 'c'; /* ascii value is 99 */
   int sum;

   sum = i + c;
   printf("Value of sum : %dn", sum );
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Value of sum : 116

Здесь значение суммы равно 116, потому что компилятор выполняет целочисленное продвижение и преобразовывает значение ‘c’ в ASCII перед выполнением фактической операции сложения.

Обычное Арифметическое Преобразование

Обычные арифметические преобразования неявно выполняются для приведения их значений к общему типу. Компилятор сначала выполняет целочисленное продвижение ; если операнды по-прежнему имеют разные типы, то они преобразуются в тип, который отображается выше в следующей иерархии –

Обычное Арифметическое Преобразование

Обычные арифметические преобразования не выполняются ни для операторов присваивания, ни для логических операторов && и ||. Давайте возьмем следующий пример, чтобы понять концепцию –

Live Demo

#include <stdio.h>

main() {

   int  i = 17;
   char c = 'c'; /* ascii value is 99 */
   float sum;

   sum = i + c;
   printf("Value of sum : %fn", sum );
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Value of sum : 116.000000

Здесь легко понять, что первый c преобразуется в целое число, но, поскольку конечное значение равно двойному, применяется обычное арифметическое преобразование, и компилятор преобразует i и c в «float» и добавляет их, получая результат «float».

C – Обработка ошибок

Таким образом, программирование на C не обеспечивает прямой поддержки обработки ошибок, но, будучи языком системного программирования, оно предоставляет вам доступ на более низком уровне в форме возвращаемых значений. Большинство вызовов функций C или даже Unix возвращают -1 или NULL в случае любой ошибки и устанавливают код ошибки errno . Он устанавливается как глобальная переменная и указывает на ошибку, возникшую во время любого вызова функции. Вы можете найти различные коды ошибок, определенные в заголовочном файле <error.h>.

Таким образом, программист C может проверить возвращаемые значения и может предпринять соответствующие действия в зависимости от возвращаемого значения. Рекомендуется устанавливать значение errno равным 0 во время инициализации программы. Значение 0 указывает на то, что в программе нет ошибок.

ошибка, perror (). и strerror ()

Язык программирования C предоставляет функции perror () и strerror (), которые можно использовать для отображения текстового сообщения, связанного с errno .

  • Функция perror () отображает строку, которую вы передаете ей, затем двоеточие, пробел, а затем текстовое представление текущего значения errno.

  • Функция strerror () , которая возвращает указатель на текстовое представление текущего значения errno.

Функция perror () отображает строку, которую вы передаете ей, затем двоеточие, пробел, а затем текстовое представление текущего значения errno.

Функция strerror () , которая возвращает указатель на текстовое представление текущего значения errno.

Давайте попробуем смоделировать состояние ошибки и попытаться открыть файл, который не существует. Здесь я использую обе функции, чтобы показать использование, но вы можете использовать один или несколько способов печати ваших ошибок. Вторым важным моментом, который следует отметить, является то, что вы должны использовать поток файлов stderr для вывода всех ошибок.

#include <stdio.h>
#include <errno.h>
#include <string.h>

extern int errno ;

int main () {

   FILE * pf;
   int errnum;
   pf = fopen ("unexist.txt", "rb");
	
   if (pf == NULL) {
   
      errnum = errno;
      fprintf(stderr, "Value of errno: %dn", errno);
      perror("Error printed by perror");
      fprintf(stderr, "Error opening file: %sn", strerror( errnum ));
   } else {
   
      fclose (pf);
   }
   
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Value of errno: 2
Error printed by perror: No such file or directory
Error opening file: No such file or directory

Разделить на ноль ошибок

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

Код ниже исправляет это, проверяя, равен ли делитель нулю перед делением –

Live Demo

#include <stdio.h>
#include <stdlib.h>

main() {

   int dividend = 20;
   int divisor = 0;
   int quotient;
 
   if( divisor == 0){
      fprintf(stderr, "Division by zero! Exiting...n");
      exit(-1);
   }
   
   quotient = dividend / divisor;
   fprintf(stderr, "Value of quotient : %dn", quotient );

   exit(0);
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Division by zero! Exiting...

Состояние выхода из программы

Обычной практикой является выход со значением EXIT_SUCCESS в случае выхода программы после успешной операции. Здесь EXIT_SUCCESS является макросом, и он определен как 0.

Если в вашей программе возникла ошибка, и вы выходите из нее, вам следует выйти со статусом EXIT_FAILURE, который определен как -1. Итак, давайте напишем выше программу следующим образом –

Live Demo

#include <stdio.h>
#include <stdlib.h>

main() {

   int dividend = 20;
   int divisor = 5;
   int quotient;
 
   if( divisor == 0) {
      fprintf(stderr, "Division by zero! Exiting...n");
      exit(EXIT_FAILURE);
   }
	
   quotient = dividend / divisor;
   fprintf(stderr, "Value of quotient : %dn", quotient );

   exit(EXIT_SUCCESS);
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Value of quotient : 4

C – рекурсия

Рекурсия – это процесс повторения предметов самоподобным способом. В языках программирования, если программа позволяет вам вызывать функцию внутри одной и той же функции, то это называется рекурсивным вызовом функции.

void recursion() {
   recursion(); /* function calls itself */
}

int main() {
   recursion();
}

Язык программирования C поддерживает рекурсию, то есть функцию, которая вызывает сама себя. Но при использовании рекурсии программистам нужно быть осторожными, чтобы определить условие выхода из функции, иначе оно войдет в бесконечный цикл.

Рекурсивные функции очень полезны для решения многих математических задач, таких как вычисление факториала числа, генерация рядов Фибоначчи и т. Д.

Номер Факториал

В следующем примере вычисляется факториал данного числа с использованием рекурсивной функции –

Live Demo

#include <stdio.h>

unsigned long long int factorial(unsigned int i) {

   if(i <= 1) {
      return 1;
   }
   return i * factorial(i - 1);
}

int  main() {
   int i = 12;
   printf("Factorial of %d is %dn", i, factorial(i));
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

Factorial of 12 is 479001600

Серия Фибоначчи

В следующем примере генерируется ряд Фибоначчи для заданного числа с использованием рекурсивной функции –

Live Demo

#include <stdio.h>

int fibonacci(int i) {

   if(i == 0) {
      return 0;
   }
	
   if(i == 1) {
      return 1;
   }
   return fibonacci(i-1) + fibonacci(i-2);
}

int  main() {

   int i;
	
   for (i = 0; i < 10; i++) {
      printf("%dtn", fibonacci(i));
   }
	
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –

0	
1	
1	
2	
3	
5	
8	
13	
21	
34

C – Переменные аргументы

Иногда вы можете столкнуться с ситуацией, когда вы хотите иметь функцию, которая может принимать переменное количество аргументов, то есть параметров, вместо предопределенного количества параметров. Язык программирования C предоставляет решение для этой ситуации, и вы можете определить функцию, которая может принимать переменное количество параметров в зависимости от ваших требований. В следующем примере показано определение такой функции.

int func(int, ... ) {
   .
   .
   .
}

int main() {
   func(1, 2, 3);
   func(1, 2, 3, 4);
}

Следует отметить, что функция func () имеет свой последний аргумент в виде эллипсов, то есть три точки ( ) и одна перед эллипсами всегда представляет собой целое число, представляющее общее число переданных аргументов переменной. Чтобы использовать такую ​​функциональность, вам нужно использовать файл заголовка stdarg.h, который предоставляет функции и макросы для реализации функциональности переменных аргументов и выполнения указанных шагов –

  • Определите функцию с последним параметром в виде эллипсов, а перед параметром эллипсы всегда будет int, который будет представлять число аргументов.

  • Создайте переменную типа va_list в определении функции. Этот тип определен в заголовочном файле stdarg.h.

  • Используйте параметр int и макрос va_start, чтобы инициализировать переменную va_list в список аргументов. Макрос va_start определен в заголовочном файле stdarg.h.

  • Используйте макрос va_arg и переменную va_list для доступа к каждому элементу в списке аргументов.

  • Используйте макрос va_end, чтобы очистить память, назначенную переменной va_list .

Определите функцию с последним параметром в виде эллипсов, а перед параметром эллипсы всегда будет int, который будет представлять число аргументов.

Создайте переменную типа va_list в определении функции. Этот тип определен в заголовочном файле stdarg.h.

Используйте параметр int и макрос va_start, чтобы инициализировать переменную va_list в список аргументов. Макрос va_start определен в заголовочном файле stdarg.h.

Используйте макрос va_arg и переменную va_list для доступа к каждому элементу в списке аргументов.

Используйте макрос va_end, чтобы очистить память, назначенную переменной va_list .

Теперь давайте выполним описанные выше шаги и запишем простую функцию, которая может принимать переменное количество параметров и возвращать их среднее значение –

Live Demo

#include <stdio.h>
#include <stdarg.h>

double average(int num,...) {

   va_list valist;
   double sum = 0.0;
   int i;

   /* initialize valist for num number of arguments */
   va_start(valist, num);

   /* access all the arguments assigned to valist */
   for (i = 0; i < num; i++) {
      sum += va_arg(valist, int);
   }
	
   /* clean memory reserved for valist */
   va_end(valist);

   return sum/num;
}

int main() {
   printf("Average of 2, 3, 4, 5 = %fn", average(4, 2,3,4,5));
   printf("Average of 5, 10, 15 = %fn", average(3, 5,10,15));
}

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

Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000

C – Управление памятью

В этой главе описывается динамическое управление памятью на языке C. Язык программирования C предоставляет несколько функций для распределения памяти и управления ею. Эти функции можно найти в заголовочном файле <stdlib.h> .

Sr.No. Описание функции
1

void * calloc (int num, int size);

Эта функция выделяет массив из num элементов, каждый из которых будет иметь размер в байтах.

2

void free (void * address);

Эта функция освобождает блок памяти, указанный в адресе.

3

void * malloc (int num);

Эта функция выделяет массив из num байтов и оставляет их неинициализированными.

4

void * realloc (void * address, int newsize);

Эта функция перераспределяет память, расширяя ее до новостей .

void * calloc (int num, int size);

Эта функция выделяет массив из num элементов, каждый из которых будет иметь размер в байтах.

void free (void * address);

Эта функция освобождает блок памяти, указанный в адресе.

void * malloc (int num);

Эта функция выделяет массив из num байтов и оставляет их неинициализированными.

void * realloc (void * address, int newsize);

Эта функция перераспределяет память, расширяя ее до новостей .

Выделение памяти динамически

При программировании, если вы знаете размер массива, это легко, и вы можете определить его как массив. Например, чтобы сохранить имя любого человека, оно может содержать до 100 символов, поэтому вы можете определить что-то следующим образом:

char name[100];

Но теперь давайте рассмотрим ситуацию, когда у вас нет представления о длине текста, который нужно сохранить, например, вы хотите сохранить подробное описание по теме. Здесь нам нужно определить указатель на символ, не определяя, сколько памяти требуется, и позже, в зависимости от потребности, мы можем выделить память, как показано в следующем примере –

Live Demo

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char name[100];
   char *description;

   strcpy(name, "Zara Ali");

   /* allocate memory dynamically */
   description = malloc( 200 * sizeof(char) );
	
   if( description == NULL ) {
      fprintf(stderr, "Error - unable to allocate required memoryn");
   } else {
      strcpy( description, "Zara ali a DPS student in class 10th");
   }
   
   printf("Name = %sn", name );
   printf("Description: %sn", description );
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат.

Name = Zara Ali
Description: Zara ali a DPS student in class 10th

Эту же программу можно написать с помощью calloc (); единственное, вам нужно заменить malloc на calloc следующим образом:

calloc(200, sizeof(char));

Таким образом, вы имеете полный контроль и можете передавать любое значение размера при выделении памяти, в отличие от массивов, где после определения размера вы не можете его изменить.

Изменение размера и освобождение памяти

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

Кроме того, вы можете увеличить или уменьшить размер выделенного блока памяти, вызвав функцию realloc () . Давайте еще раз проверим вышеуказанную программу и воспользуемся функциями realloc () и free () –

Live Demo

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char name[100];
   char *description;

   strcpy(name, "Zara Ali");

   /* allocate memory dynamically */
   description = malloc( 30 * sizeof(char) );
	
   if( description == NULL ) {
      fprintf(stderr, "Error - unable to allocate required memoryn");
   } else {
      strcpy( description, "Zara ali a DPS student.");
   }
	
   /* suppose you want to store bigger description */
   description = realloc( description, 100 * sizeof(char) );
	
   if( description == NULL ) {
      fprintf(stderr, "Error - unable to allocate required memoryn");
   } else {
      strcat( description, "She is in class 10th");
   }
   
   printf("Name = %sn", name );
   printf("Description: %sn", description );

   /* release memory using free() function */
   free(description);
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат.

Name = Zara Ali
Description: Zara ali a DPS student.She is in class 10th

Вы можете попробовать приведенный выше пример без перераспределения дополнительной памяти, а функция strcat () выдаст ошибку из-за нехватки доступной памяти в описании.

C – Аргументы командной строки

Можно передать некоторые значения из командной строки вашим программам на Си, когда они выполняются. Эти значения называются аргументами командной строки, и во многих случаях они важны для вашей программы, особенно когда вы хотите управлять своей программой извне, а не жестко кодировать эти значения внутри кода.

Аргументы командной строки обрабатываются с помощью аргументов функции main (), где argc ссылается на количество переданных аргументов, а argv [] – массив указателей, который указывает на каждый аргумент, переданный программе. Ниже приведен простой пример, который проверяет, есть ли какой-либо аргумент из командной строки, и предпринимает соответствующие действия:

#include <stdio.h>

int main( int argc, char *argv[] ) {

   if( argc == 2 ) {
      printf("The argument supplied is %sn", argv[1]);
   } else if( argc > 2 ) {
      printf("Too many arguments supplied.n");
   } else {
      printf("One argument expected.n");
   }
}

Когда приведенный выше код компилируется и выполняется с одним аргументом, он дает следующий результат.

$./a.out testing
The argument supplied is testing

Когда приведенный выше код компилируется и выполняется с двумя аргументами, он дает следующий результат.

$./a.out testing1 testing2
Too many arguments supplied.

Когда приведенный выше код компилируется и выполняется без передачи аргумента, он дает следующий результат.

$./a.out
One argument expected

Следует отметить, что argv [0] содержит имя самой программы, а argv [1] – указатель на первый предоставленный аргумент командной строки, а * argv [n] – последний аргумент. Если аргументы не предоставлены, argc будет один, а если вы передадите один аргумент, argc будет установлен в 2.

Вы передаете все аргументы командной строки, разделенные пробелом, но если сам аргумент имеет пробел, вы можете передать такие аргументы, заключив их в двойные кавычки “” или одинарные кавычки “. Давайте еще раз напишем приведенный выше пример, где мы напечатаем имя программы, а также передадим аргумент командной строки, заключив в двойные кавычки –

#include <stdio.h>

int main( int argc, char *argv[] ) {

   printf("Program name %sn", argv[0]);
 
   if( argc == 2 ) {
      printf("The argument supplied is %sn", argv[1]);
   } else if( argc > 2 ) {
      printf("Too many arguments supplied.n");
   } else {
      printf("One argument expected.n");
   }
}

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

Понравилась статья? Поделить с друзьями:
  • Инструкция по охране труда для печатника флексографической печати
  • Jura impressa e75 инструкция на русском
  • Мукосол сироп для детей инструкция по применению
  • Ответственность руководства предприятия за качество
  • Сгмуп гтс руководство