Сложные типы данных в Си : структуры, объединения, битовые поля

Сложные типы данных в Си

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

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

Общая форма объявления структуры:

 
 
 
 
 
 
 
struct ИмяСтруктуры
{
  тип ИмяЭлемента1;
  тип ИмяЭлемента2;
  . . .
  тип ИмяЭлементаn;
};

После закрывающей фигурной скобки } в объявлении структуры обязательно ставится точка с запятой.

Пример объявления структуры

 
 
 
 
 
 
struct date
{
  int day;     // 4 байта
  char *month; // 4 байта
  int year;    // 4 байта
};

Поля структуры располагаются в памяти в том порядке, в котором они объявлены:

Поля структуры

В указанном примере структура date занимает в памяти 12 байт. Кроме того, указатель *month при инициализации будет началом текстовой строки с названием месяца, размещенной в памяти.

При объявлении структур, их разрешается вкладывать одну в другую.

Пример

 
 
 
 
 
 
struct persone
{
  char lastname[20];   // фамилия
  char firstname[20]; // имя
  struct date bd;     // дата рождения
};

Инициализация полей структуры

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

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

В первом способе инициализация осуществляется по следующей форме:

 
struct ИмяСтруктуры ИмяПеременной={ЗначениеЭлемента1, ЗначениеЭлемента_2, . . . , ЗначениеЭлементаn};

Пример

 
struct date bd={8,"июня", 1978};

Имя элемента структуры является составным. Для обращения к элементу структуры нужно указать имя структуры и имя  самого элемента. Они разделяются точкой:

 
ИмяПеременной.ИмяЭлементаСтруктуры

 
printf("%d %s %d",bd.day, bd.month, bd.year);

Второй способ инициализации объектов языка Си с использованием функций ввода-вывода.

Пример

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
struct date 
{
  int day;
  char month[20];
  int year;
};
struct persone 
{
  char firstname[20];
  char lastname[20];
  struct date bd;
};
int main() 
{
  system("chcp 1251");
  system("cls");
  struct persone p;
  printf("Введите имя : ");
  scanf("%s", p.firstname);
  printf("Введите фамилию : ");
  scanf("%s", p.lastname);
  printf("Введите дату рождения\nЧисло: ");
  scanf("%d", &p.bd.day);
  printf("Месяц: ");
  scanf("%s", p.bd.month);
  printf("Год: ");
  scanf("%d", &p.bd.year);
  printf("\nВы ввели : %s %s, дата рождения %d %s %d года",
    p.firstname, p.lastname, p.bd.day, p.bd.month, p.bd.year);
  getchar(); getchar();
  return 0;
}

Результат выполнения

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

 
 
 
 
 
struct complex_type  // имя структуры
{
  double real;
  double imag;
} number;    // имя структурной переменной

Поля приведенной структурной переменной: number.real, number.imag .

Объединения

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

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

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

Общая форма объявления объединения

 
 
 
 
 
 
 
union ИмяОбъединения
{
  тип ИмяОбъекта1;
  тип ИмяОбъекта2;
  . . .
  тип ИмяОбъектаn;
};

Объединения применяются для следующих целей:

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

Например, удобно использовать объединения, когда необходимо вещественное число типа float представить в виде совокупности байтов.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
union types
{
  float f;
  unsigned char b[4];
};
int main()
{
  types value;
  printf("N = ");
  scanf("%f", &value.f);
  printf("%f = %x %x %x %x", value.f, value.b[0], value.b[1], value.b[2], value.b[3]);
  getchar();
  getchar();
  return 0;
}

Результат выполнения

Пример Поменять местами два младших байта во введенном числе
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main() 
{
  char temp;
  system("chcp 1251");
  system("cls");
  union
  {
    unsigned char p[2];
    unsigned int t;
  } type;
  printf("Введите число : ");
  scanf("%d", &type.t);
  printf("%d = %x шестн.\n", type.t, type.t);
  // Замена байтов
  temp = type.p[0];
  type.p[0] = type.p[1];
  type.p[1] = temp;
  printf("Поменяли местами байты, получили\n");
  printf("%d = %x шестн.\n", type.t, type.t);
  getchar(); getchar();
  return 0;
}

Результат выполнения
Поменять местами байты

Битовые поля

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

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

 
тип имя: КоличествоБит

При работе с битовыми полями нужно внимательно следить за тем, чтобы значение переменной не потребовало памяти больше, чем под неё выделено.

Пример Разработать программу, осуществляющую упаковку даты в формат

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define YEAR0 1980
struct date
{
  unsigned short day : 5;
  unsigned short month : 4;
  unsigned short year : 7;
};
int main() 
{
  struct date today;
  system("chcp 1251");
  system("cls");
  today.day = 16;
  today.month = 12;
  today.year = 2013 - YEAR0; //today.year = 33
  printf("\n Сегодня %u.%u.%u \n", today.day, today.month, today.year + YEAR0);
  printf("\n Размер структуры today : %d байт"sizeof(today));
  printf("\n Значение элемента today = %hu = %hx шестн.", today, today);
  getchar();
  return 0;
}

Результат выполнения

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

Работа с массивами структур аналогична работе со статическими массивами других типов данных.

Пример Библиотека из 3 книг

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
struct book
{
  char title[15];
  char author[15];
  int value;
};
int main()
{
  struct book libry[3];
  int i;
  system("chcp 1251");
  system("cls");
  for (i = 0; i<3; i++)
  {
    printf("Введите название %d книги : ", i + 1);
    gets_s(libry[i].title);
    printf("Введите автора %d книги : ", i + 1);
    gets_s(libry[i].author);
    printf("Введите цену %d книги : ", i + 1);
    scanf_s("%d", &libry[i].value);
    getchar();
  }
  for (i = 0; i<3; i++)
  {
    printf("\n %d. %s ", i + 1, libry[i].author);
    printf("%s %d", libry[i].title, libry[i].value);
  }
  getchar();
  return 0;
}

Результат выполнения
Массив структур

Указатели на структуры

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

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

 
указатель->поле

или

 
(*указатель).поле
  • указатель — указатель на структуру или объединение;
  • поле  — поле структуры или объединения;

Динамическое выделение памяти для структур

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

Пример Библиотека из 3 книг

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct book
{
  char title[15];
  char author[15];
  int value;
};
int main()
{
  struct book* lib;
  int i;
  system("chcp 1251");
  system("cls");
  lib = (struct book*)malloc(3 * sizeof(struct book));
  for (i = 0; i < 3; i++)
  {
    printf("Введите название %d книги : ", i + 1);
    gets_s((lib + i)->title);
    printf("Введите автора %d книги : ", i + 1);
    gets_s((lib + i)->author);
    printf("Введите цену %d книги : ", i + 1);
    scanf_s("%d", &(lib + i)->value);
    getchar();
  }
  for (i = 0; i < 3; i++)
  {
    printf("\n %d. %s ", i + 1, (lib + i)->author);
    printf("%s %d", (lib + i)->title, (lib + i)->value);
  }
  getchar();
  return 0;
}

Результат выполнения аналогичен предыдущему решению.

33 комментария к “Сложные типы данных в Си”

  1. Александр

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

    1. Елена

      sizeof поможет определить размер поля данных структуры, но не тип. Тип должен быть известен на этапе формирования структуры. При обращении к полям структуры мы знаем их тип.

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

      1. Елена

        Сформировать в виде последовательности байтов. При расшифровке посылки ориентироваться по меткам, какие в последовательности данные за что отвечают. Например, первый байт посылки это однобайтное значение, второй и третий байты отвечают за двухбайтное. Порядок передачи и восстановления байтов 2-байтных значений естественно сохраняем.

  2. Фёдор К

    Здравствуйте, имею такой вопрос по поводу структур в Си. Допустим, я инициализирую поля структуры при её объявлении. Но не все возможные поля, а лишь некоторые.
    Например:

    1
    2
    3
    4
    5
    6
    7
    8
    struct date
    {
      int day;     // 4 байта
      char *month; // 4 байта
      int year;    // 4 байта
    };

    struct date bd={.day = 8, /* поле month пропустили*/ .year = 1978};

    Какие данные будут находится в не затрагиваемом при инициализации поле month? NULL или мусор из стека?

    1. Елена Вставская

      При частичной инициализации пропущенные значения заполняются нулями

  3. Денис

    Здравствуйте! Подскажите пожалуйста, как сделать поиск по фамилиям, Я так понимаю, нужно сравнить фамилию (Записанную ранее пользователем) с фамилией, введенной с клавиатуры, и вывести все фамилии схожей с той который ввел пользователь

    1
    return strcmp(((struct book*)a)->familia, ((struct book*)b)->familia);

    это сравнение со всеми фамилиями, а как сравнить с той, которую ввел пользователь, я не пойму

    1. Елена Вставская

      Ввести в строку (массив char) и передать как аргумент в функцию сравнения

  4. Вадим

    Здравствуйте! Спасибо Вам за статью.

    Мне непонятен доступ к элементам структуры когда одним из элементов является массив.

    Например есть структура

    1
    2
    3
    4
    5
    6
    struct book { 
      char massiv[20];
      int b [5];
      char c;  
    };
    struct book lolik;

    массиву massiv необходимо присвоить значение:

    1
    lolik.b={5, 3, 8, 0, 1};

    Почему так нельзя делать?
    а так можно

    1
    lolik.b[3]=5;
    1. Елена Вставская

      Мы можем проинициализировать поля структуры только при ее объявлении. Дальше уже идут операции присваивания. Причем инициализация должна быть выполнена для всех полей одновременно. Нельзя проинициализировать часть полей (причем из середины).
      Можно сделать так:

      1
      struct book lolik = { "", {5, 3, 8, 0, 1}, 0 };
  5. Николай

    Здравствуйте. Подскажите, как при задании массива структур правильно инициализировать поля каждой структуры? Массив статический. Если можно, хотелось бы увидеть какие-нибудь примеры.

    1. Елена Вставская

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      #include <iostream>
      using namespace std;
      struct student
      {
        const char* name;
        int age;
        const char* group;
      };
      int main()
      {
        system("chcp 1251");
        system("cls");
        student Students[] = { {"Иванов", 18, "КЭ-117"}, {"Петров", 19, "ЕН-153"} };
        for(int i=0; i<sizeof(Students)/sizeof(student); i++)
          cout << Students[i].name << " " << Students[i].age << " " << Students[i].group << endl;
        cin.get();
        return 0;
      }
  6. Подскажите, пожалуйста, как сначала вывести тех, у кого доходы меньше двух минимальных зарплат, а потом всех остальных в порядке уменьшения среднего балла.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #include<stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #include <string.h>
    struct spisok
    {
        char FIO[70];
        char group[7];
        int AvMark;
        int Income;
    };
    int main() {
        struct spisok dorm[3];
        int i, minwage = 500;
        for (i = 0; i < 3; i++) {
            printf("Enter FIO %d : ", i + 1);
            gets_s(dorm[i].FIO);
            printf("Enter group %d : ", i + 1);
            gets_s(dorm[i].group);
            printf("Enter AvMark %d : ", i + 1);
            scanf_s("%d", &dorm[i].AvMark);
            printf("Enter Income %d : ", i + 1);
            scanf_s("%d", &dorm[i].Income);
            printf("\n");
            getchar();
        }
        for (i = 0; i < 3; i++) {
            printf("\n%s ", dorm[i].FIO);
            printf("\nGroup: ");
            printf("%s ", dorm[i].group);
            printf("\nAverage mark: ");
            printf("%d", dorm[i].AvMark);
            printf("\nIncome: ");
            printf("%d", dorm[i].Income);
        }
        getchar();
        return 0;
    }
    1. Елена Вставская

      Отсортировать всех.
      Выводить пока доход меньше введённого значения (мин.з.п. и т.п.). Перевести строку, запомнить номер элемента.
      Вывести элементы с конца массива до текущего.

  7. Алексей

    Подскажите пожалуйста почему if второе условие не выполняет. Заранее спасибо.Вот если что задание.
    Створити структуру та зробити необхідні розрахунки.
    Поля структури:Прізвище, вік, освіта, посада.
    Вивести дані про працівників старших 30-ти років, які не мають вищої освіти.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #include<stdio.h>
    #include<conio.h>
    #define n 3
    typedef struct{
      char Prizv[20],Osvita[30],Posada[30];
      int Vik;}Pracxivniki;
    int main(){
    clrscr();
    Pracxivniki p[n];
    int i;
    for(i=0;i<n;i++){
      printf("Vvedit dani %d-y osobi\n",i+1);
      printf("Prizvische: ");
      scanf("%s",p[i].Prizv);
      printf("Vik: ");
      scanf("%d",&(p[i].Vik));
      printf("Osvita: ");
      scanf("%s",p[i].Osvita);
      printf("Posada: ");
      scanf("%s",p[i].Posada);}
    printf("Dani pro pracxivnikiv starsche 30 bez vischoi osviti\n");
    char rt[]="Vischa";
    for(i=0;i<n;i++){
      if ((p[i].Vik>30)&&(p[i].Osvita!=rt)){
        printf("Prizvische: %s",p[i].Prizv);
        printf(" Vik: %d",p[i].Vik);
        printf(" Osvita: %s",p[i].Osvita);
        printf(" Posada: %s\n",p[i].Posada);}}
    getch();
    return 0;}
    1. Елена Вставская

      Потому что две строки лежат по разным адресам, и сравнивать эти адреса бессмысленно. Строки нужно сравнивать посимвольно — или в цикле, или, например, с помощью функции strcmp

  8. Алексей

    Посмотрите пожалуйста задание и мой код не пойму как исправить ошибки. Створити структуру даних згідно варіанту, створена програма повинна передбачати введення даних з клавіатури, задання кількості записів, перегляд структури.
    12. «Чоловік»:
    прізвище; ім'я; батькові; стать; національність; зріст; вага; дата народження (рік, місяць, число); номер телефону; домашню адресу (поштовий індекс, країна, область, район, місто, вулиця, будинок, квартира).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    #include<stdio.h>
    #include<conio.h>
    #include<stdlib.h>
    typedef struct {
      int Rik, Mis, Chislo;}Datanarod;
    typedef struct {
      char Poind[10], Kraina[20], Oblast[20], Raion[20], Misto[20], Vul[20], Bud[10], Kvart[10];}Domadres;
    typedef struct {
      char Prizv[20], Imia[20], Batko[20], Stat[10], Nacxion[20];
      int Zrist, Vaga;
      struct Datanarod;
      char Nomertel[10];
      struct Domadres;}Cholovik;
    int main(){
    Cholovik *p;
    int n,i;
    printf("Vvedit kilkist zapisiv\t");
    scanf("%d",&n);
    p=(Cholovik*) malloc (n*sizeof(Cholovik));
    if(p==NULL){
      printf("Nestacha pamiati\n");
      return -1;}
    for(i=0;i<n;++i){
      printf("Vvedit dani %d-y osobi\n",i+1);
      printf("Prizvische:\t");
      scanf("%s",&p[i].Prizv);
      printf("\nImia:\t");
      scanf("%s",&p[i].Imia);
      printf("\nPo batkovi:\t");
      scanf("%s",&p[i].Batko);
      printf("\nStat:\t");
      scanf("%s",&p[i].Stat);
      printf("\nNacxionalnist:\t");
      scanf("%s",&p[i].Nacxion);
      printf("\nZrist:\t");
      scanf("%d",&p[i].Zrist);
      printf("\nVaga:\t");
      scanf("%d",&p[i].Vaga);
      printf("\nData narodzhennia(rik,misiacx,den):\t");
      scanf("%d%d%d",&p[i].Datanarod.Rik,&p[i].Datanarod.Mis,&p[i].Datanarod.Chislo);
      printf("\nNomer telefona:\t");
      scanf("%s",&p[i].Nomertel);
      printf("\nDomaschnia adresa(poshtovyj indekc, derhava, krajina, oblact, rajon, misto, vulitsja, budynok, kvartyra):\t");
      scanf("%s%s%s%s%s%s%s%s%s",&p[i].Domadres.Poind,&p[i].Domadres.Kraina,&p[i].Domadres.Oblast,&p[i].Domadres.Raion,&p[i].Domadres.Misto,&p[i].Domadres.Vul,&p[i].Domadres.Bud,&p[i].Domadres.Kvart);
    int k;
    printf("Dlia prosmotra strukturi nazhmite 1, a dlia vihoda nazhmite lubuyu klavishu\t");
    scanf("%d",&k);
    if(k==1){
      for(i=0;i<n;++i){
      printf("Dani %d-y osobi",i+1);
      printf("Prizvische:\t%s",p[i].Prizv);
      printf("\nImia:\t%s",p[i].Imia);
      printf("\nPo batkovi:\t%s",p[i].Batko);
      printf("\nStat:\t%s",p[i].Stat);
      printf("\nNacxionalnist:\t%s",p[i].Nacxion);
      printf("\nZrist:\t%d",p[i].Zrist);
      printf("\nVaga:\t%d",p[i].Vaga);
      printf("\nData narodzhennia(rik,misiacx,den):\t%d%d%d",p[i].Datanarod.Rik,p[i].Datanarod.Mis,p[i].Datanarod.Chislo);
      printf("\nNomer telefona:\t%s",p[i].Nomertel);
      printf("\nDomaschnia adresa(poshtovyj indekc, derhava, krajina, oblact, rajon, misto, vulitsja, budynok, kvartyra):\t%s%s%s%s%s%s%s%s%s",
      p[i].Domadres.Poind,p[i].Domadres.Kraina,p[i].Domadres.Oblast,p[i].Domadres.Raion,p[i].Domadres.Misto,p[i].Domadres.Vul,p[i].Domadres.Bud,p[i].Domadres.Kvart);}
    else { return 1;}}
    free(p);
    return 0;}
    1. Елена Вставская

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

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      typedef struct {
        char Prizv[20], Imia[20], Batko[20], Stat[10], Nacxion[20];
        int Zrist, Vaga;
        Datanarod Dn;
        char Nomertel[10];
        Domadres Da;
      }Cholovik;[\code]

      Ну, и есть несколько других мелких ошибок. В частности, строчка
      [code]printf("\nDomaschnia adresa(poshtovyj indekc, derhava, krajina, oblact, rajon, misto, vulitsja, budynok, kvartyra):\t");
      scanf("%s%s%s%s%s%s%s%s", p[i].Da.Poind, p[i].Da.Kraina, p[i].Da.Oblast, p[i].Da.Raion, p[i].Da.Misto, p[i].Da.Vul, p[i].Da.Bud, p[i].Da.Kvart);

      Poind это уже указатель, поэтому перед p.Da.Poind амперсанд не ставится.
      Нужно проверить количество форматов для ввода и количество вводимых полей - они должны совпадать. Сейчас printf запрашивает 9 полей, а scanf вводит 8.

  9. Сергей

    Доброе время суток, не могли бы Вы помочь разобраться в структуре, а именно возникла проблема с частью "void seach_a_table(char* FileName)". Заранее спасибо.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    #include<stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #include <string.h>

    struct price //прайс
    {  
      char nsr[30]; //название товара
      char nfr[30]; //название магазина
      int nr;  //стоимость
    };

    void in_table(char* FileName)
    {  
      FILE *ou = fopen(FileName, "a+");
      struct price item;  
      rewind(stdin);  
      printf("Введите:\n");
      printf("Название товара: ");
      gets(item.nsr);
      rewind(stdin);
      printf("Название магазина: ");
      gets(item.nfr);
      printf("Стоимость: ");
      scanf("%d", &item.nr);  
      fwrite(&item, sizeof(struct price), 1, ou);
      fclose(ou);
      printf("\nДанные записаны в файл.\n");  
    }

    void pnt_item(struct price item)
    {
      printf("Название магазина: %s\n", item.nfr);
      printf("Название товара: %s\n", item.nsr);
      printf("Стоимость: %d\n", item.nr);
    }

    void print_table(char* FileName)
    {
      FILE *in = fopen(FileName, "r");
      struct price item;
      while (fread(&item, sizeof(struct price), 1, in))
      {    
        pnt_item(item);
        printf("\n");    
      }
      fclose(in);
    }

    void seach_a_table(char* FileName)
    {
      FILE *in = fopen(FileName, "r");
      struct price item;
      char* nfr;
      printf("Введите название магазина: ");
      scanf("%s", &nfr);  
      while (fread(&item, sizeof(struct price), 1, in))    
      :
            :
      :  
      fclose(in);  
      if (k == 0)  
        printf("магазин %s не найден.\n\n", nfr);        
    }

    int main()
    {  
      system("chcp 1251");
      system("cls");
      char* fn ="PriceList.dat";
      char key;
      do {
        system("cls");
        printf("1 — Ввод информации в прайс\n");
        printf("2 — Вывод информации из прайса\n");
        printf("3 — Поиск товара в магазине\n");    
        printf("0 — Выход\n");    
        key = getch();
        system("cls");    
        switch (key)
        {
          case '1': in_table(fn);  break;
          case '2': print_table(fn); break;
          case '3': seach_a_table(fn); break;    
        }
        system("pause");    
      } while (key != '0');
      
      return 0;
    }

      1. Сергей

        Да эту часть кода писал, но она не работает.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        void seach_a_table(char* FileName)
        {
          FILE *in = fopen(FileName, "r");
          struct price item;
          char nfr[30], k = 0;
          printf("Введите название магазина: ");
          scanf("%d", &nfr);  
          while (fread(&item, sizeof(struct price), 1, in))    
          {
            if (item.nfr == nfr)
            {    
              pnt_item(item);
              printf("\n");
              k++;
            }
          }  
          fclose(in);  
          if (k == 0)  
            printf("магазин %d не найден.\n\n", nfr);        
        }
        1. Елена Вставская

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          void seach_a_table(char* FileName)
          {
            FILE* in = fopen(FileName, "r");
            struct price item;
            char nfr[30], k = 0;
            printf("Введите название магазина: ");
            scanf("%s", &nfr);
            while (fread(&item, sizeof(struct price), 1, in))
            {
              if (strcmp(item.nfr,nfr)==0)
              {
                pnt_item(item);
                printf("\n");
                k++;
              }
            }
            fclose(in);
            if (k == 0)
              printf("магазин %d не найден.\n\n", nfr);
          }
          1. Сергей

            Елена, Большое спасибо все работает.

  10. Здравствуйте. Задание звучит так: "Сведения о студентах-иностранцах: фамилия, имя, страна, факультет, группа, оценки по предметам за два семестра обучения . Составить списки студентов-иностранцев по факультетам и по странам." Первую часть задания сделала, а вот как дальше сделать задание не понимаю 🙁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    struct svedenia
    {
      char surname[15];
      char name[15];
      char country[20];
      char faculty[5];
      char group[15];
      char semester1_grade[15];
      char semester2_grade[15];
    } mas[7];

    void data_input(int n)
    {
      FILE *data;
      data= fopen("data_to_LAB11.txt", "w");
      for(int i=0;i<n;i++)
      {
        printf("Введите фамилию ");
        scanf("%s", &mas[i].surname);
        printf("Введите имя ");
        scanf("%s", &mas[i].name);
        printf("Введите страну ");
        scanf("%s", &mas[i].country);
        printf("Введите факультет");
        scanf("%d", &mas[i].faculty);
        printf("Введите группу");
        scanf("%d", &mas[i].group);
        printf("Введите оценки за 1 семестр ");
        scanf("%s", &mas[i].semester1_grade);
        printf("Введите оценки за 2 семестр");
        scanf("%d", &mas[i].semester2_grade);
        fprintf(data,"%s %s %s %s %s %s %s", mas[i].surname, mas[i].name, mas[i].country, mas[i].faculty, mas[i].group, mas[i].semester1_grade, mas[i].semester2_grade);
        system("cls");
      }
      fclose(data);
    }

    void obrabotka(int n)
    {
      int i, palata=1;
      FILE *data;
      data= fopen("data_to_LAB11.txt", "r");

    1. Елена Вставская

      А это точно задание не по базам данных?
      Если на С++, то, наверное, придется использовать сравнение строк strcmp().
      И в каком виде эти списки составить надо? В консоль вывести или в файлы?

      1. Да, это задание по обработке структур. В задании просят вывести данные как и в консоль, так и в файл.

        1. Елена Вставская

          Здесь есть пример сортировки строк с помощью дерева с возможностью подсчета количества одинаковых строк. Думаю, можно выполнить на его основе.

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <stdio.h>
    #include "string.h"
    #include "stdlib.h"

    #ifndef STUDENT_H_
    #define STUDENT_H_
    #define  SIZE 50
    #define N 1000
    struct student{
        char nm[SIZE];
        unsigned char age;
        unsigned char course;
    };
    #endif
    #define  SIZE 50
    int main() {
        struct student *a = NULL,b[SIZE],c;
        a = (struct student *)malloc(N * sizeof(struct student *));
        if (!(a= (struct student *)(int *)malloc(N * sizeof(a)))) {
            printf("Allocation error.");
            return 1;
        }
        for (int i = 0; strcmp((a + i)->nm,"0") != 0 ; ++i)
        {
            scanf("%s",(a + i)->nm);
            printf("%s",(a + i)->nm);
        }
        free(a);

        return 0;
    }

    1. Елена Вставская

      Сначала i увеличивается на 1, а потом идет сравнение strcmp((a + i)->nm,"0") != 0 с ещё не введенным элементом.
      Вариант решения:

      1
      2
      3
      4
      5
      6
      7
      int i = -1;
        do
        {
          i++;
          scanf("%s", (a+i)->nm);
          printf("%s", (a+i)->nm);
        } while (strcmp((a + i)->nm, "0") != 0);
  12. Дмитрий

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    struct c_struct
    {
      float x, y, z;
    };

    struct c_struct *c_function (r)
      struct c_struct *r;
    {
    struct c_struct *r2;
    r2 = (struct c_struct *) malloc (sizeof(struct c_struct));
    //здесь функция, например:
    r2->x = 5.01;
    r2->y = r->x;
    r2->z = 6.355;
    return(r2);
    }

    Все работает. Компилирую как внешнюю библиотеку для Lisp. r служит для приема параметров, r2, понятно, для передачи наверх. Хочу понять внутриструктурную организацию и взаимосвязь с функцией.

    Если возможно, ответьте на почту.

    Спасибо,
    С уважением,
    Дмитрий.

    1. Елена Вставская

      Вижу ошибку в строках 6, 7. скорее всего это должно выглядеть как

      1
      struct c_struct *c_function (struct c_struct *r)

      Сама структура содержит 3 поля типа float. Не знаю уж, с чем тут разбираться.

    2. Дмитрий

      Ваш вариант тоже работает, но логически понятен и синтаксически верен. Будем иметь в виду, что С такое позволяет) Спасибо!

Оставьте комментарий

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

Прокрутить вверх