Массивы структур и функции
Массив структур
Если структура описывает одну запись, то массив структур — набор записей:
typedef struct
{
int id;
int course;
double score;
} Student;
Student group[100];
int n;
Ввод:
if (scanf("%d", &n) != 1 || n < 0 || n > 100)
{
return 1;
}
for (int i = 0; i < n; i++)
{
if (scanf("%d %d %lf",
&group[i].id,
&group[i].course,
&group[i].score) != 3)
{
return 1;
}
}
Вывод:
for (int i = 0; i < n; i++)
{
printf("%d %d %.2f\n",
group[i].id,
group[i].course,
group[i].score);
}
Динамический массив структур
В лабораторной работе количество записей заранее неизвестно. Выделяем память после ввода
N:
Student *group = malloc((size_t)n * sizeof(*group));
if (group == NULL && n != 0)
{
return 1;
}
sizeof(*group) — размер одной структуры. Не используйте sizeof(Student *): это размер
указателя, а не записи. Освобождение — одним вызовом: free(group);.
Передача массива структур в функцию
Массив при передаче в функцию становится указателем на первый элемент. Поэтому параметр
имеет вид Student *group, int n:
void print_group(const Student *group, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d %d %.2f\n",
group[i].id,
group[i].course,
group[i].score);
}
}
Вызов: print_group(group, n); — только имя массива, без &.
const означает, что функция не должна менять записи. Если нужно изменить — уберите
const:
void add_bonus(Student *group, int n, double bonus)
{
for (int i = 0; i < n; i++)
{
group[i].score += bonus;
}
}
Внутри функции group[i] — это структура; чтобы изменить поле, не нужен дополнительный
&, потому что group[i] уже обозначает саму запись.
Сортировка массива структур
Сортировать можно по любому полю. Меняем местами целые структуры:
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (group[j].score < group[j + 1].score)
{
Student tmp = group[j];
group[j] = group[j + 1];
group[j + 1] = tmp;
}
}
}
Это сортировка по убыванию score. Для составного ключа сравните сначала course, затем
score:
if (group[j].course > group[j + 1].course ||
(group[j].course == group[j + 1].course &&
group[j].score < group[j + 1].score))
{
/* обменять */
}
Для устойчивой сортировки при равных ключах сохраняйте исходный порядок.
Поиск по полю
Поиск по id:
int find_by_id(const Student *group, int n, int id)
{
for (int i = 0; i < n; i++)
{
if (group[i].id == id)
{
return i;
}
}
return -1;
}
Поиск по course:
int find_by_course(const Student *group, int n, int course)
{
for (int i = 0; i < n; i++)
{
if (group[i].course == course)
{
return i;
}
}
return -1;
}
Функция возвращает индекс или -1. Вызывающий код обязан проверить результат.
Вставка и удаление записей
Для вставки в середину нужно сдвинуть элементы вправо, начиная с последнего:
void insert_at(Student *group, int *n, int pos, Student value)
{
for (int i = *n; i > pos; i--)
{
group[i] = group[i - 1];
}
group[pos] = value;
(*n)++;
}
Для удаления — сдвинуть элементы влево:
void remove_at(Student *group, int *n, int pos)
{
for (int i = pos; i < *n - 1; i++)
{
group[i] = group[i + 1];
}
(*n)--;
}
При вставке проверяйте, что массив имеет запас по размеру. В лабораторной работе для
динамического массива используйте realloc или выделяйте память с запасом.
Пример программы
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int id;
int course;
double score;
} Student;
int input_group(Student *group, int n);
void print_group(const Student *group, int n);
int find_best(const Student *group, int n);
int main(void)
{
int n;
if (scanf("%d", &n) != 1 || n < 0)
{
return 1;
}
Student *group = malloc((size_t)n * sizeof(*group));
if (group == NULL && n != 0)
{
return 1;
}
if (!input_group(group, n))
{
free(group);
return 1;
}
print_group(group, n);
if (n > 0)
{
int best = find_best(group, n);
printf("Лучший: %d %.2f\n", group[best].id, group[best].score);
}
free(group);
return 0;
}
int input_group(Student *group, int n)
{
for (int i = 0; i < n; i++)
{
if (scanf("%d %d %lf",
&group[i].id,
&group[i].course,
&group[i].score) != 3)
{
return 0;
}
}
return 1;
}
void print_group(const Student *group, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d %d %.2f\n",
group[i].id,
group[i].course,
group[i].score);
}
}
int find_best(const Student *group, int n)
{
int best = 0;
for (int i = 1; i < n; i++)
{
if (group[i].score > group[best].score)
{
best = i;
}
}
return best;
}
Частые ошибки
| Ошибка | Что не так |
|---|---|
sizeof(Student *) при malloc | выделен размер указателя, а не записи |
group[i].score без & в scanf | запись по «мусорному» адресу |
n не изменили после вставки/удаления | последний элемент остаётся «лишним» |
сдвиг при вставке начали с pos, а не с конца | затирание элементов |
не проверили malloc | падение при нехватке памяти |
забыли free | утечка памяти |
сравнили структуры через == | в C структуры нельзя сравнивать целиком |
Документация
Что запомнить
- Массив структур — набор записей; поля доступны через
group[i].field. - Динамический массив структур выделяют через
malloc(n * sizeof(*group)). - В функцию передают указатель на первый элемент и количество записей.
constзащищает данные от случайного изменения.- Сортировка меняет местами целые структуры; сравнение составного ключа — вручную.
- При вставке и удалении не забывайте менять
nи проверять границы.