Язык программирования Си. Глава(Chapter) 14
Tags: c, russian
Published: 2022-06-24 17:58:20

1. Переменные типа структур(Structure Variables) с ключевым словом struct и объединений(Unions)(для хранения и инициализации одного значения, но разных типов) с ключевым словом union: их члены(members) или поля(fields), объявление(схема не инициализируется и не выделяет пространство в памяти, а сообщает компилятору, как представлять данные) или шаблон(template) и необязательным дескриптором(tag), также их инициализация(identifier = { value1, value2 };) и присваивание(identifier1 = identifier2;) в соответствии с типами членов и классами хранения  ANSI C, средство назначенной инициализации(identifier = { .member = 12.99 };) и составных литералов((struct tag) { value1, value2 }) в C99, вдобавок связывание объявления с определением(struct tag { fields } identifier;) или просто определение переменной(struct { fields } identifier;), доступ к членам(gaining access to members) через оператор членства(membership operator) .(identifier.member;, где member — индекс), ещё анонимные структуры(Anonymous Structures) или неименованный член-структура в структуре в C11: struct name { struct { char first[20]; char last[20]; }; }; 

2. Массивы(в стеке и в куче) структур и идентификация их членов, вложенные структуры, указатели на структуры и доступ к членам через оператор косвенного членства(indirect membership operator) ->(pointer->member == (*pointer).member == identifier.member;) и размер структуры(иногда больше суммы её частей из-за выравнивания), также передача в качестве аргумента и возврат: членов, адреса и самой(в ANSI C) структуры функцией(fun(&struct_variable); т.к. имя структуры не есть её адрес)

3. Члены с типами гибких(не VLA) массивов(Flexible Array Members) в C99: struct marks { double average; double scores[]; } * ptrtostruct = malloc(sizeof(struct flex) + 5 * sizeof(double));, должны быть последними и единственными среди обязательно присутствующих членов с другими типами, нельзя использовать, инициализировать с помощью списка инициализации, при присваивании для копирования(*ptrtoflexstruct1 = *ptrtoflexstruct2;) или при передаче в функцию в качестве фактического аргумента копируются только члены структуры, но не гибкий массив, также невозможен доступ к гибкому массиву если структура является вложенной или элементом массива, вдобавок конструкция “Struct Hack": double scores[0]; вместо double scores[];(не входил в стандарт С, работал только на GCC)

4. Перечислимые типы(Enumerated Types) с ключевым словом enum, их перечислители(enumerators) или член, инициализация со дефолтными(от 0) или присвоенными(assigned) значениями с автоматическим присваиванием значения на один больше предыдущего члена(enum spectrum { black, white = 0, red = 10, orange } color;) , также возможность инкрементирования в C(но не в C++): color = red; color++;

5. Совместно используемые пространства имен(Shared Namespaces) в C: дескрипторы структур, объединений и перечислений хранятся в пространстве имён отличном от пространства имён обычных переменных. Допустимо, но не желательно в C(не в C++, где дескрипторы и идентификаторы в одном пространстве имён) struct book { int price; } book; или struct book { int price; }; char * book = "Ulysses";

6. Средство typedef(подобно #define) шаблонизирует идентификатор, назначает символические имена типам, но не значениям и интерпретируется компилятором, а не препроцессором, может повторяться, имеет соответствующую месту объявления область видимости и ПНМ в пространстве имён переменных, также отличие typedef char * STRING; и #define STRING char * при STRING name, sign;, и ещё пример: typedef struct { float real; float imaginary; } COMPLEX;(анонимная структура) или typedef struct complex { float real; float imaginary; } COMPLEX;(шаблон с дескриптором)

7. Адрес(идентификатор) функции и указатели(с обычной арифметикой и соответствием типов) на функции, причудливые объявления(Fancy Declarations) char *(*c[10])(int **p);, также передача указателя на функцию в качестве аргумента функции, массив указателей на функции, обращение к функции через указатель: (*ptrtofun)(); или ptrtofun();(в ANSI C)

```c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv[])
{
    struct book {
        char (* (name));
    } const (book1) = (struct book) { .name = { {"H" "e"}, {"l" "l" "o"} } };
    {
        (fprintf(stdout, "%zd\n%s", (sizeof(book1)),
            ((book1).name)));
    }
    return EXIT_SUCCESS;
}
```

```c
#include <stdio.h>

int fun(int i) { return i; }
int (* return_fun(int (* ptrtofun)(int)))(int) { return ptrtofun; }

int main(void)
{
    int i;
    printf("Output%2$n%s", ": ", &i);
    printf("%d\n", return_fun(**fun)(i));

    return 0;
}
```

```c
#include <stdio.h>

int square(int n) { return n * n; }

int main(void)
{
    typedef int fun(int);
    fun * f1 = square;

    typedef int (* ptrtofun)(int);
    ptrtofun f2 = square;

    printf("%d", f1(8) + f2(6));
    return 0;
}
```

```c
int printf(char *, ...);

int main(void)
{
    typedef int ARR_OF_5_INT[5];
    ARR_OF_5_INT def_arr;
    //def_arr == int arr[5]

    typedef ARR_OF_5_INT * PTR_TO_ARR_OF_5_INT;
    PTR_TO_ARR_OF_5_INT def_ptr;
    //def_ptr == * def_arr == int (* arr)[5]

    typedef PTR_TO_ARR_OF_5_INT ARR_OF_10_PTR_TO_ARR_OF_5_INT[10];
    ARR_OF_10_PTR_TO_ARR_OF_5_INT def_arr_of_ptr;
    //def_arr_of_ptr == def_ptr[10] == (* def_arr)[10] == int (* (arr[10]))[5]

    printf("%zd", sizeof def_arr_of_ptr);
    //sizeof def_arr_of_ptr == sizeof arr_of_ptr
}
```

```c
#include <stdio.h>

int main(void)
{
    typedef int arr_type1[4];
    typedef arr_type1 arr_type2[3];
    typedef arr_type2 arr_type3[5];
    arr_type3 some_array;
    printf("%zd", sizeof some_array / sizeof(int));
}
```

> Язык программирования Си 6 издание. Стивен Прата
> C Primer Plus 6th edition. Stephen Prata