В вашем коде вы выделили память только для структуры, но поля этой структуры все еще "ждут" назначения адреса. Указатели являются только псевдонимами адресов в памяти, и благодаря этому управление этими адресами более читабельно для человека.
Есть несколько способов решить вашу проблему. Я создал четыре разные функции и использовал два разных типа структуры.
- структура с указателями типа int и float;
- структура с полями int и float, которая уже распределила память.
код
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int rain;
float avgtemp;
float avgwind;
} weather;
typedef struct {
int *rain;
float *avgtemp;
float *avgwind;
} weatherp;
/* Obtain amount of items in array (implemented in <sys/params.h> header). */
#define nitems(x) (sizeof((x)) / sizeof((x)[0]))
/* Ex. 1: Using array of defined size. */
void
first_option()
{
weather year[2];
int ii;
for (ii = 0; ii < nitems(year); ii++) {
fscanf(stdin, "%d %f %f", &year[ii].rain, &year[ii].avgtemp, &year[ii].avgwind);
}
for (ii = 0; ii < nitems(year); ii++) {
fprintf(stdout, "%d %f %f\n", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
}
}
/* Ex. 2: Using malloc(3). */
void
second_option()
{
const int n = 2;
weather *year = (weather *)malloc(n * sizeof(weather));
int ii;
for (ii = 0; ii < n; ii++) {
fscanf(stdin, "%d %f %f", &year[ii].rain, &year[ii].avgtemp, &year[ii].avgwind);
}
for (ii = 0; ii < n; ii++) {
fprintf(stdout, "%d %f %f\n", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
}
free(year);
}
/* Ex. 3: Values in struct are pointers. */
void
third_option()
{
const int n = 2;
weatherp *year = (weatherp *) malloc(n * sizeof(weatherp));
int ii;
for (ii = 0; ii < n; ii++) {
year[ii].rain = (int *)malloc(sizeof(int));
year[ii].avgtemp = (float *)malloc(sizeof(float));
year[ii].avgwind = (float *)malloc(sizeof(float));
fscanf(stdin, "%d %f %f", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
}
for (ii = 0; ii < n; ii++) {
fprintf(stdout, "%d %f %f\n", *year[ii].rain, *year[ii].avgtemp, *year[ii].avgwind);
}
for (ii = 0; ii < n; ii++) {
free(year[ii].rain);
free(year[ii].avgtemp);
free(year[ii].avgwind);
}
free(year);
}
/* Ex. 4: Using array of defined size but struct fields are pointers. */
void
fourth_option()
{
weatherp year[2];
int ii;
for (ii = 0; ii < nitems(year); ii++) {
year[ii].rain = (int *)malloc(sizeof(int));
year[ii].avgtemp = (float *)malloc(sizeof(float));
year[ii].avgwind = (float *)malloc(sizeof(float));
fscanf(stdin, "%d %f %f", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
}
for (ii = 0; ii < nitems(year); ii++) {
fprintf(stdout, "%d %f %f\n", *year[ii].rain, *year[ii].avgtemp, *year[ii].avgwind);
}
for (ii = 0; ii < nitems(year); ii++) {
free(year[ii].rain);
free(year[ii].avgtemp);
free(year[ii].avgwind);
}
}
int
main()
{
first_option();
second_option();
third_option();
fourth_option();
return (0);
}
В функции first_option () Я определил двухэлементный массив структур (определен как weather
тип). Поля массива и структуры уже распределили память, потому что я не использовал поля как указатели, а экземпляры типов int
/ float
.
В функции second_option () Я определил указатель, который будет содержать экземпляры структуры погоды. Поля структуры уже распределили память, потому что внутри структуры я не использовал поля, являющиеся указателями. Есть экземпляры int
/ float
типов. Но я должен назначить память для указателя. По сравнению с предыдущим примером, у меня нет массива структур, поэтому я должен его создать. Поэтому я выделяю память для n
экземпляров weather
struct. Это похоже на создание нескольких (n) полок для нескольких блоков данных (контейнеров / структур, содержащих некоторую важную информацию).
В конце концов, память, выделенная malloc, должна быть освобождена функцией free(3)
.
В функции third_option () У меня нет определенной памяти для полей массива и структуры. Как видите, теперь я использовал только что созданный тип weatherp
. В этом случае я должен назначить память как для структурных полей, так и для «полок» для блоков данных (массив). Поэтому я выделяю память для n
экземпляров структуры weatherp
, а затем, перед использованием fscanf(3)
, я назначаю память для каждого поля структуры отдельно. В конце концов, память, выделенная malloc(3)
, должна быть освобождена с помощью free(3)
(каждое поле структуры и в конце - контейнер для экземпляров структуры).
Последняя функция четвертая_опция () определен двухэлементный массив структур (определен как weather
тип), но поля структуры не имеют выделенной памяти. Поэтому перед использованием fscanf(3)
я назначаю память для каждого поля структуры отдельно. В конце концов, память, выделенная malloc(3)
, должна быть освобождена с помощью free(3)
.
Дополнительная информация:
Каждый адрес для переменных, объявленных как int a;
, struct type name;
или char tab[10];
, уже динамически распределяет память в стеке, и эта память автоматически «освобождается» после завершения функции. Пространство, выделенное вручную (например, используя malloc(3)
), выделяется в куче до вызова функции free(3)
. В настоящее время ядра операционной системы после завершения программы могут освободить память, выделенную вручную, но рекомендуется устранить утечки памяти, и это показывает, что вы знаете, что делаете.
PS. Во время тестов я заменил количество месяцев с 12 на 2, и я читаю данные из stdin
, а не из файла. И, конечно, мы должны проверять такие вещи, как успешное выполнение функции (например, если указатель после malloc(3)
вызова не равен NULL
). Я просто не хотел усложнять код.