Главная страница
Навигация по странице:

  • Инициализация и присваивание структур.

  • Доступ к элементам структур.

  • Массивы и структуры в качестве элементов структур.

  • Массивы структур.

  • Курс на Си. Подбельский. Курс программирования на Си. В., Фомин С. С. Курс программирования на языке Си Учебник


    Скачать 1.57 Mb.
    НазваниеВ., Фомин С. С. Курс программирования на языке Си Учебник
    АнкорКурс на Си
    Дата18.02.2023
    Размер1.57 Mb.
    Формат файлаdocx
    Имя файлаПодбельский. Курс программирования на Си.docx
    ТипУчебник
    #943863
    страница20 из 42
    1   ...   16   17   18   19   20   21   22   23   ...   42

    struct goods { char* name; long price; float percent;

    int vol; char date [9]

    };

    Элементы размещены подряд

    Названия элементов:

    name

    price

    percent

    vol

    date

    их типы:

    char*

    long

    float

    int

    char[9]

    байты:

    «—4->

    «—4—>

    <—4—>

    «-2->

    < 9 >


    Размещение элементов с выравниванием данных

    Названия элементов: их типы: байты:

    name

    price

    percent

    "дыра"

    vol

    date

    char*

    long

    float




    int

    char[9]

    <—4—>

    <—4—>

    <—4—>




    <—2->

    < 9 >

    Рис. 6.1. Размещение структуры типа goods в памяти
    (размеры в байтах для разных реализаций
    могут быть другими)


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

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

    sizeof (имя_структуры)

    sizeof (имя_структурного_типа)

    Для нашего примера одинаковые результаты дадут операции:

    sizeof (struct goods)

    sizeof (tea)

    sizeof coat

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

    sizeof (имя_типа_данных)

    sizeof выражение

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

    Примечание

    На рис. 6.1 элементы несут следующую смысловую нагрузку:

    • name - наименование товара;

    • prict - оптовая цена;

    • percent - наценка;

    • vol - объем партии;

    • date - дата поставки.

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

    struct goods coat={

    "пиджак черный", 3600, 7.5, 220, "12.01.2011" };

    complex sigma={1.3, 12.6};

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

    float z[5], x[5]={1.0, 2.0, 3.0, 4.0, 5.0 }; int j;

    for (j=0; j
    Попытка использовать имена массивов без индексов в операции присваивания будет обречена на провал (ведь имя массива есть не­изменяемый указатель):

    z=x; /* Ошибка в операции */

    В то же время стандарт языка Си разрешает присваивание струк­тур. Если не обращать внимания на смысл имен введенных выше структур типа struct goods (tea - чай; coat - пиджак), то допустимо следующее присваивание:

    tea=coat;

    Определив структуру типа complex, можно выполнить, напри­мер, такое присваивание (структура sigma того же типа определена и инициализирована выше):

    complex sport;

    sport=sigma;

    Отметим, что для структур не определены операции сравнения даже на равенство. И сравнивать структуры нужно только поэле­ментно.

    Доступ к элементам структур. Наиболее наглядно и естественно доступ к элементам структур обеспечивается с помощью уточнен­ных имен. Конструкция

    имя_структуры. имя_элемента

    играет роль названия (имени) объекта того типа, к которому отнесен элемент в соответствии с определением структурного типа. В нашем примере с инициализацией структуры типа struct goods:

    • coat.name - указатель типа char* на строку «пиджак черный»;

    • coat.price - переменная типа long со значением 3600;

    • coat.percent - переменная типа float со значением 7.5;

    • coat.vol - переменная типа int со значением 220;

    • coat.date - массив типа char [9], содержащий «12.01.2011».

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

    Уточненное имя - это выражение с двумя операндами и опера­цией «точка» между ними. Операция «точка» называется операцией доступа к элементу структуры (или объединения). У нее самый высокий ранг наряду со скобками (и операцией «стрелка» для до­ступа к элементам структуры через адресующий ее указатель, см. табл. 1.4).

    Уточненное имя используется для выбора правого операнда опе­рации «точка» из структуры (или объединения), задаваемой левым операндом. Левый операнд должен иметь структурный тип, а правый операнд должен быть именем компонента (элемента) этой структу­ры. Тип результата операции «точка» - это тип именуемого уточнен­ным именем компонента (элемента) структуры. Именно такие типы указаны в приведенных выше примерах, то есть coat.vol - объект типа int и т. д.

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

    Пример программы с инициализацией структуры и выводом зна­чений ее элементов:

    #include void main( ) { struct goods { char* name; long price; float percent; int vol;

    char date[9];

    };

    struct goods coat={

    "пиджак черный", 3600, 7.5, 220, "12.01.2011"};

    printf("\n Товар на складе:")

    printf("\n Наименование: %s.", coat.name);

    printf("\n Оптовая цена: %ld руб.", coat.price);

    printf("\n Наценка: %4.1f %%.", coat.percent);

    printf("\n Объем партии: %d штук.", coat.vol);

    printf("\n Дата поставки: %s.", coat.date);

    }

    Результат выполнения программы:

    Товар на складе:

    Наименование: пиджак черный.

    Оптовая цена: 3600 руб.

    Наценка: 7.5 %

    Объем партии: 220 штук.

    Дата поставки: 12.01.2011.

    Уточненные имена элементов структур обладают всеми правами имен объектов соответствующих типов. Их можно использовать в выражениях, их значения можно вводить с клавиатуры и т. д. На­пример, с помощью следующих операторов можно изменить торго­вую наценку (элемент coat.price) и вычислить розничную цену на определенный в программе товар (пиджак черный):

    printf("\n Введите торговую наценку:");

    scanf("%f", &coat.percent);

    printf("Цена товара: %ld руб.",

    (long)(coat.price*(1.0+coat.percent/100));

    Обратите внимание, что в качестве аргумента функции scanf( ) используется адрес элемента percent структуры coat. Для этого опе­рация получения адреса & применяется к уточненному имени coat. percent. При вычислении розничной цены товара приходится вво­дить явное приведение типов (long), так как результат умножения элемента coat.price на вещественное выражение 1.0+coat.percent/100 имеет по умолчанию тип double.

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

    #include

    typedef struct {

    double real;

    double imag;

    } complex;

    void main( )

    {

    complex x, y, z;

    printf("\n Введите два комплексных числа:");

    printf("\n Вещественная часть: ");

    scanf(" %lf", &x.real);

    printf(" Мнимая часть:");

    scanf(" %lf", &x.imag);

    printf(" Вещественная часть:");

    scanf(" %lf", &y.real);

    printf(" Мнимая часть:");

    scanf(" %lf", &y.imag);

    z.real=x.real+y.real;

    z.imag=x.imag+y.imag;

    prinf("\n Результат: z.real=%f z.imag=%f", z.real, z.imag); }

    Возможный результат выполнения программы:

    Введите два комплексных числа:

    Вещественная часть: 1.3

    Мнимая часть: 0.84

    Вещественная часть: 2.2

    Мнимая часть: 6.16

    Результат: z.real= 3.500000 z.imag=7.000000

      1. Структуры, массивы и указатели

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

    • значение массы (double);

    • массив координат (float [3]).

    Проиллюстрируем основные особенности работы с такими струк­турами. Введя величину и координаты точечной массы, вычислим ее удаление от начала координат (модуль радиус-вектора).

    #include

    #include /* Для функции sqrt( ) */ void main( )

    {

    struct {

    double mass;

    float coord [3];

    } point={12.3, {1.0, 2.0, -3.0}};

    int i;

    float s=0.0;

    for (i=0, i<3; i++) s+=point.coord [i]* point.coord [i];

    printf("\n Длина радиус-вектора: %f", sqrt(s));

    }

    Результат выполнения программы:

    Длина радиус-вектора: 3.741657

    Для структуры point структурный тип введен как безымянный. Структура point получает значения своих элементов в результате инициализации. В списке начальных значений использовано вложе­ние инициализаторов, так как элементом структуры является мас­сив. Можно обратить внимание на индексирование при обращении к элементу внутреннего массива coord[3]. Индексы записываются после имени массива-элемента, а не после имени структуры.

    Так как элементами структур могут быть данные любых типов, то естественным образом допускается вложение структур, то есть элементом структуры может быть другая (и только другая, не та же самая!) структура. В качестве примера еще раз рассмотрим структурный тип для представления сведений о студенте. До­полнительно к тем элементам, которые уже были (имя, фамилия, курс), введем в качестве элемента структуру с именем (названием) структурного типа struct birth. В ней будут сохраняться сведения о рождении - место рождения и дата рождения. В свою очередь, дату рождения представим структурой (типа date) с элементами число, месяц, год.

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

    /* Определение структурных типов: */ struct date { /* тип "дата" */

    int day; /* число */

    int month; /* месяц */ int year; /* год */ };

    struct birth { /* тип "данные о рождении" */ char place [20] /* место рождения */ struct date dd; /* дата рождения */ };

    struct student { /* тип "студент" */

    char name [15]; /* имя */

    char surname [20]; /* фамилия */ int year; /* курс */

    struct birth bir;/* данные о рождении*/ };

    /* Работа с конкретным студентом: */ void main( )

    {

    /* Конкретная структура: */

    struct student stud= {"Павел”, "Иванов", 1, "Петербург", 22, 11, 1888 };

    printf("\n Введите курс студента: ");

    scanf("%d", &stud.year);

    printf("Сведения о студенте:");

    printf("\n Фамилия: %s", stud.surname);

    printf("\n Имя:%з", stud.name);

    printf("\n Курс: %б-й", stud.year);

    printf("\n Место рождения: %d", stud.bir.place);

    printf("\n Дата рождения: %d.%d.%d", stud.bir.dd.day, stud.bir.dd.month, stud.bir.dd.year);

    }

    Результаты выполнения программы:

    Введите курс студента:3

    Сведения о студенте:

    Фамилия: Иванов

    Имя: Павел

    Курс: 3-й

    Место рождения: Петербург

    Дата рождения: 22.11.1888

    Конкретная структура-объект stud типа struct student получает значение элементов при инициализации. Затем с помощью scanf( ) из­меняется элемент stud.year (Иванов Павел перешел уже на 3-й курс!). Содержимое структуры выводится на дисплей, причем для доступа к элементам вложенных структур используются уточненные имена с нужным количеством «точек».

    Массивы структур. Определяются массивы структур так же, как и массивы других типов данных. Естественное отличие - служебное слово struct в названии структурного типа (если обозначение типа не введено с помощью typedef). Для введенных выше структурных типов можно определить:

    struct goods list [MAX_GOODS]; complex set [80];

    Эти предложения определяют list как массив, состоящий из MAX_GOODS-элементов - структур типа goods, а set - массив структур типа complex, состоящий из 80 элементов. (Идентификатор MAX_GOODS должен быть именем константы.)

    Имена list и set не являются именами структур, это имена массивов, элементами которых являются структуры. list[0] есть структура типа goods, list[1] - вторая структура типа goods из массива list[ ] и т. д.

    Для доступа к компонентам структур, входящих в массив струк­тур, используются уточненные имена с индексированием первого имени (имени массива). Например:

    • set[4].real - первый компонент (с именем real) типа double структуры типа complex, входящей в качестве пятого (от на­чала) элемента в массив структур set[ ];

    • list[0] .price - второй компонент (с именем price) типа long структуры типа goods, входящей в качестве первого элемента (с нулевым индексом) в массив структур list[ ].

    На рис. 6.2 условно изображена схема размещения в памяти мас­сива list[ ]. Его элементы (как и элементы любого другого массива) размещаются в основной памяти подряд в соответствии с возрас­танием индекса.

    Определение массива структур:

    struct goods list [MAX GOODS];

    list[O].name

    list[O].price

    list[O].percent

    list[0].vol

    list[O].date




    >list[O]

    char*

    long

    float

    int

    char|9]




    list[l].name

    listf 1 ].price

    list[ 1]. percent

    listf 1 ].vol

    listfl].date




    >list[l]

    char*

    long

    float

    int

    char[9]

























    list[99].name

    list[O] .price

    list[O] .percent

    list[0].vol

    list[O].date




    4ist[99]

    char*

    long

    float

    int

    char|9]

    J

    Рис. 6.2. Массив структур (MAX_GOODS==100)

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

    list.percent[8] /* Ошибка ! */

    - ошибочное имя; percent - переменная типа float, а не массив.

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

    В следующей программе вводится и инициализируется массив структур, каждая из которых описывает точечную массу (мате­риальную точку). Для определенной таким образом системы мате­риальных точек вычисляется центр масс (координаты xc, yc, zc центра масс).

    Если m 1, m2, ..., mn - массы материальных точек; xy, z. - коорди­наты отдельной точки (i=1, n), то имеем:

    п

    mt - общая масса системы точек.

    / = 1

    Координаты центра масс:



    Текст программы с массивом структур:

    #include

    /* Определение структурного типа: */ struct particle {

    double mass;

    float coord [3];

    };

    void main ( )

    { /* Определение массива структур: */

    struct particle mass_point[ ]={

    20.0, {2.0, 4.0, 6.0},

    40.0, {6.0, -2.0, 8.0}, 10.0, {1.0, 3.0, 2.0}

    };

    int N; /* N - число точек */

    /* Структура для формирования результатов: * struct particle center= { /* центр масс */ 0.0, {0.0, 0.0, 0.0}

    };

    int i;

    N=sizeof(mass_point) / sizeof(mass_point[0]);

    for (i=0; i
    {

    center.mass+=mass_point[i].mass;

    center.coord[0] += mass_point[i].coord[0] * mass_point[i].mass;

    center.coord[1] += mass_point[i].coord[1] * mass_point[i].mass;

    center.coord[2] += mass_point[i].coord[2] * mass_point[i].mass;

    }

    printf("\n Координаты центра масс:");

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

    {

    center.coord[i]/=center.mass;

    printf("\n Координата %d: %f", (i+1), center. coord [i]);

    }

    }

    Результат выполнения программы:

    Координаты центра масс: Координата 1: 4.142857 Координата 2: 0.428571 Координата 3: 6.571429
    1   ...   16   17   18   19   20   21   22   23   ...   42


    написать администратору сайта