Статьи

Операторы в Си, часть 2

Эта статья является продолжением предыдущей статьи « Операторы на C» , где мы начали с Postfix Operators и обсудили оператор индекса Array и оператор вызова функции. Продолжая операторы постфикса, третий оператор — это оператор точки (.) И оператор стрелки (->) , используемый для доступа к элементам структуры и объединения.

3. Структура и члены Союза

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

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

например:

  struct student {
                int student_id;
                char [] student_name;
                }; 

Приведенное выше объявление структуры создает определенный пользователем тип данных с именем student . Структура student состоит из двух членов: student_id и student_name.

Чтобы получить доступ к членам структуры, нам нужно сначала объявить переменную определяемого пользователем типа данных student , а затем мы будем использовать оператор точки (.) Для доступа к отдельным членам структуры.

  структура студент студент1; 

Вышеупомянутое утверждение создает структурную переменную student1 типа student . Теперь для доступа к каждому члену структуры мы будем использовать оператор точки.

Точка Оператор

Точечный оператор используется для доступа к структуре или члену объединения.

Синтаксис:

structurevariable.membername;

пример:

  student1.student_id = 101;
                     student1.student_name = "Алиса"; 

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

Доступ к объединению также осуществляется аналогичным образом с помощью оператора точки. Союз объявляется следующим образом:

название объединения {

datatype1 member1;

datatype2 member2;

,

,

,

тип данныхN memberN;

};

Синтаксис для объявления переменной объединения:

переменная unionname;

Чтобы получить доступ к члену профсоюза:

variable.member

Стрелка Оператор

Начальный адрес переменной структуры / объединения может быть сохранен в переменной указателя, а затем к отдельным членам структуры / объединения можно получить доступ с помощью переменной указателя и оператора Arrow ->.

Например:

  структура студент студент1; 
  структура студента * Stud1; 

объявляет указатель на структуру student . Чтобы сохранить начальный адрес структурной переменной student1 в переменной-указателе *stud1 мы будем использовать адрес оператора & .

  * Stud1 = & student1; 

Теперь для доступа к отдельным членам мы можем использовать указатель *stud1 и оператор стрелки следующим образом:

  stud1-> student_id; 
  stud1-> student_name; 

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

4. Постфиксные операторы инкремента и декремента

Операторы постфиксного приращения и постфиксного декремента работают только с одним операндом, который может быть либо переменной-указателем, либо переменной, принадлежащей к реальным типам данных: целочисленным типам и типам с плавающей запятой ( int, float, double вместе с модификаторами различных типов) ,

Операция увеличения постфикса (операнд ++) увеличивает значение переменной на 1, а операция уменьшения постфикса (операнд -) уменьшает значение переменной на 1.

Постфиксное выражение в форме E ++, где E — переменная, эквивалентно E = E + 1. Аналогично, постфиксное выражение вида E– эквивалентно E = E-1.

Следовательно ,

  int i = 10;
 я ++; 
  Е ( "% d", я);  // печатает 11
 я--; 
  Е ( "% d", я);  // печатает 10 

Результат операции увеличения или уменьшения постфикса отличается в сочетании с оператором присваивания (=). В операции увеличения / уменьшения постфикса предыдущее значение переменной, которая увеличивается / уменьшается, сначала присваивается переменной, содержащей результат операции увеличения / уменьшения постфикса, а затем выполняется операция увеличения / уменьшения; то есть сначала происходит присвоение, а затем увеличение / уменьшение . Чтобы понять это, рассмотрим следующий пример:

  #include <stdio.h>

 int main ()
 {
 int a, i = 10;
 а = я ++;
 printf («a =% d, i =% d», a, i);
 а = i--;
 printf («a =% d, i =% d», a, i);
 вернуть 0;
 } 
  Выход: 
  а = 10, я = 11 
  а = 11, I = 10 

Это связано с тем, что в операции постфиксного увеличения / уменьшения значение i сначала присваивается, а затем обновляется.

Поэтому в первом утверждении a=i++; Сначала присваивается предыдущее значение i равное 10, а затем обновляется до 11.

Во втором утверждении a=i--; a снова присваивается предыдущее значение i (i = 11 сейчас, из-за предыдущей операции приращения), а затем i уменьшается до 10.

5. Составные литералы

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

Составной литерал инициализирует неназванный объект. Если имя типа данных указывает массив неизвестного размера, размер определяется количеством элементов в списке инициализатора.

Некоторые примеры составных литералов:

Массив неизвестного размера

  (int []) {2,4,7,6}; 

Вышеупомянутый составной литерал является массивом целочисленного типа неизвестного размера. Размер массива определяется как 4 после завершения инициализации.

Создание объектов структуры с использованием составных литералов

Чтобы создать объект структуры, мы инициализируем каждого члена структуры через отдельные операторы инициализации; такие как

  структура студент студент1; 
  student1.student_id = 101; 
  student2.student_name = "Алиса"; 

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

  (struct student1) { .  student_id = 101,
 ,  student_name = "Алиса"}; 

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

Указатель на структуру, используемую в качестве составного литерала

Чтобы инициализировать элемент структуры с помощью указателей, мы объявляем указатель на объект структуры, а затем инициализируем каждый элемент в отдельных операторах инициализации с помощью оператора стрелки; как в:

  struct student student1, * stud1; 
  * Stud1 = & student1; 
  stud1-> student_id = 101; 
  stud1-> student_name = "Алиса"; 

Для выполнения той же работы с использованием составных литералов мы не используем оператор стрелки. Скорее, то же самое можно сделать очень компактным способом, используя оператор точки и адрес оператора (&), как показано ниже:

  & (struct student1) { .  student_id = 101, .student_name = "Алиса"}; 

Создание константы сложного литерала

Составной литерал только для чтения; то есть константный составной литерал, может быть задан префиксом ключевого слова const:

  (   const int []) {1,2,3,4,5}; 
  (const char []) {"Температура"}; 

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

Унарные операторы

Унарные операторы работают только с одним операндом. Есть четыре унарных оператора:

1. Префиксные операторы увеличения и уменьшения

2. Адреса и адреса операторов

3. Размеры и выравнивание операторов

4. Унарные арифметические операторы

Операторы приращения и уменьшения префикса

Префиксные операторы увеличения и уменьшения работают только с одним операндом, который может быть либо переменной-указателем, либо переменной, принадлежащей к реальным типам данных: целочисленным типам и типам с плавающей запятой ( int, float, double вместе с модификаторами различных типов).

Операция увеличения префикса (операнд ++) увеличивает значение на 1, а операция уменьшения префикса (операнд -) уменьшает значение на 1. Постфиксное выражение в форме ++ E, где E — переменная, эквивалентно E = E + 1. Аналогично, постфиксное выражение вида –E эквивалентно E = E-1.

Было видно, что в случае постфикса сначала происходит приращение / уменьшение, а затем приращение / уменьшение. Однако в случае операции увеличения или уменьшения префикса предыдущее значение сначала увеличивается / уменьшается, а затем происходит присвоение.

Чтобы понять это, рассмотрим следующий фрагмент кода.

  #include <stdio.h>

 int main ()
 {
 int i = 10, a;
   ++ I;
 printf ("Значение i =% d", i); // печатает 11
   --я;
 printf ("Значение i =% d", i); // печатает 10
 а = ++ я;
 printf ("Значение a =% d", a); // печатает 11
 printf ("Значение i =% d", i); // печатает 11
 а = - я;
 printf ("Значение a =% d", a); // печатает 10
 printf ("Значение i =% d", i); // печатает 10
 вернуть 0;
 } 

Здесь мы видим, что значение i было сначала обновлено, а затем присвоено. Следовательно, a содержит обновленное значение i, а не предыдущее значение, как в случае с постфиксным увеличением / уменьшением.

Адреса и операторы переадресации

Адрес оператора & используется для оценки адреса его операнда.

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

Пример указателя данных:

  #include <stdio.h>

 int main ()

 {

 int val, a = 10;

 int * p;  // объявляем переменную указателя

 р = & а;  // теперь p хранит адрес

 Val = * р;  // теперь val хранит значение

 printf («Адрес a:% X», p);

 printf («Значение a:% d», val);

 вернуть 0;

 } 

В вышеприведенной программе оператор int *p объявляет целочисленный указатель (указатель, в котором хранится адрес целочисленной переменной).

Для сохранения адреса a в p адрес оператора применяется к a, а результат сохраняется в p, как показано в инструкции p=&a;

Теперь p=&a;

Предположим, что адрес a равен 1004, т.е. &a=1004

Поскольку p хранит адрес a, то p=&a p = 1004

Теперь значение, присутствующее по адресу 1004, является значением, хранящимся в a, которое равно 10 (a = 10).

Чтобы получить доступ к значению, хранящемуся в переменной-указателе p нам нужно применить оператор косвенности * к p . Когда оператор косвенности применяется к p (*p) , он считывает значение, хранящееся по адресу, указанному в p; т.е. значение хранится по адресу 1004; значение a . Результат косвенного действия сохраняется в переменной целочисленного типа val как показано в инструкции val =*p ; Оператор косвенного обращения также называется значением в операторе, поскольку он дает значение, хранящееся по определенному адресу.

Чтобы прочитать адрес, сохраненный в p, в выражении printf используется printf формата %X как адреса обычно в шестнадцатеричном формате.

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

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