Учебники

C — Краткое руководство

Язык 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: %E\n", FLT_MIN );
   printf("Maximum float positive value: %E\n", FLT_MAX );
   printf("Precision value: %d\n", 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).

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

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

Live Demo

#include <stdio.h>

int main() {
   printf("Hello\tWorld\n\n");

   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 %d\n", 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 %d\n", 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 : %d\n", 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 = %d\n", 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 = %d\n",  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() = %d\n",  a);
  c = sum( a, b);
  printf ("value of c in main() = %d\n",  c);

  return 0;
}

/* function to add two integers */
int sum(int a, int b) {

   printf ("value of a in sum() = %d\n",  a);
   printf ("value of b in sum() = %d\n",  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] = %d\n", 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: %x\n", &var1  );
   printf("Address of var2 variable: %x\n", &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: %x\n", &var  );

   /* address stored in pointer variable */
   printf("Address stored in ip variable: %x\n", ip );

   /* access the value using the pointer */
   printf("Value of *ip variable: %d\n", *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 : %x\n", 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', '\0'};

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

char greeting[] = "Hello";

Ниже приводится представление в памяти определенной выше строки в C / C ++ —

Строковая презентация в C / C ++

На самом деле, вы не помещаете нулевой символ в конец строковой константы. Компилятор C автоматически помещает ‘\ 0’ в конец строки, когда инициализирует массив. Давайте попробуем напечатать вышеупомянутую строку —

Live Demo

#include <stdio.h>

int main () {

   char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
   printf("Greeting message: %s\n", 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) :  %s\n", str3 );

   /* concatenates str1 and str2 */
   strcat( str1, str2);
   printf("strcat( str1, str2):   %s\n", str1 );

   /* total lenghth of str1 after concatenation */
   len = strlen(str1);
   printf("strlen(str1) :  %d\n", 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 : %s\n", Book1.title);
   printf( "Book 1 author : %s\n", Book1.author);
   printf( "Book 1 subject : %s\n", Book1.subject);
   printf( "Book 1 book_id : %d\n", Book1.book_id);

   /* print Book2 info */
   printf( "Book 2 title : %s\n", Book2.title);
   printf( "Book 2 author : %s\n", Book2.author);
   printf( "Book 2 subject : %s\n", Book2.subject);
   printf( "Book 2 book_id : %d\n", 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 : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", 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 : %s\n", book->title);
   printf( "Book author : %s\n", book->author);
   printf( "Book subject : %s\n", book->subject);
   printf( "Book book_id : %d\n", 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 : %d\n", 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 : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", 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 : %d\n", data.i);
   
   data.f = 220.5;
   printf( "data.f : %f\n", data.f);
   
   strcpy( data.str, "C Programming");
   printf( "data.str : %s\n", 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 : %d\n", sizeof(status1));
   printf( "Memory size occupied by status2 : %d\n", 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 ) : %d\n", sizeof(Age) );
   printf( "Age.age : %d\n", Age.age );

   Age.age = 7;
   printf( "Age.age : %d\n", Age.age );

   Age.age = 8;
   printf( "Age.age : %d\n", 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 : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", 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 : %d\n", TRUE);
   printf( "Value of FALSE : %d\n", 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 : %s\n", buff );

   fgets(buff, 255, (FILE*)fp);
   printf("2: %s\n", buff );
   
   fgets(buff, 255, (FILE*)fp);
   printf("3: %s\n", 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 :%s\n", __FILE__ );
   printf("Date :%s\n", __DATE__ );
   printf("Time :%s\n", __TIME__ );
   printf("Line :%d\n", __LINE__ );
   printf("ANSI :%d\n", __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: %s\n", 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 %d\n", 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 : %f\n", 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 : %d\n", 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 : %f\n", 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: %d\n", errno);
      perror("Error printed by perror");
      fprintf(stderr, "Error opening file: %s\n", 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 : %d\n", 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 : %d\n", 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 %d\n", 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("%d\t\n", 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 = %f\n", average(4, 2,3,4,5));
   printf("Average of 5, 10, 15 = %f\n", 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 memory\n");
   } else {
      strcpy( description, "Zara ali a DPS student in class 10th");
   }
   
   printf("Name = %s\n", name );
   printf("Description: %s\n", 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 memory\n");
   } 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 memory\n");
   } else {
      strcat( description, "She is in class 10th");
   }
   
   printf("Name = %s\n", name );
   printf("Description: %s\n", 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 %s\n", 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 %s\n", argv[0]);
 
   if( argc == 2 ) {
      printf("The argument supplied is %s\n", argv[1]);
   } else if( argc > 2 ) {
      printf("Too many arguments supplied.\n");
   } else {
      printf("One argument expected.\n");
   }
}

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