У вас очень много мелких проблем.Для начала, как упоминалось в моем комментарии, ваша попытка выделить для struct letter_t* letters[n_letters[i]];
не соответствует struct letter_t** letters;
Далее, прежде чем идти дальше, нит '*'
принадлежит имени переменной, а невведите в большинстве случаев.Почему?
int* a, b, c;
Выше, конечно, вы не объявляете 3-х указатели на int
.Вместо этого вы объявляете целочисленный указатель a
и целые числа b, c
.Гораздо понятнее записывается как:
int *a, b, c;
Когда вы выделяете память, вы должны проверять, что выделение выполнено успешно - каждый раз, например,
size_t n_people = sizeof name / sizeof *name;
// layout memory and populate letterbox_t array
struct letterbox_t *letterboxes;
/* allocate letterboxes for each of the people */
letterboxes = malloc (sizeof *letterboxes * n_people);
if (!letterboxes) { /* validate Every allocation */
perror ("malloc-letterboxes");
return 1;
}
Теперь у вас есть память для 3 letterbox_t
и может начать работу над содержанием.Вы можете назначить имена и количество букв каждому:
for (size_t i = 0; i < n_people; i++) {
/* assigning pointer to string literal */
letterboxes[i].name = name[i];
letterboxes[i].n_letters = n_letters[i]; /* int assignment */
( примечание: Будьте осторожны. Понимайте, что вы присваиваете String Literal из name[i]
каждому letterboxes[i].name
. Это означает, что letterboxes[i].name
не может быть изменено и не должно быть освобождено. Как правило, вы должны выделить хранилище для name
и копирования)
letterboxes[i].letters
- это указатель науказатель на letter_t
.Это означает, что вы должны сначала выделить указатели, а затем выделить хранилище для каждого letter
и назначить начальный адрес для этого блока памяти каждому из указателей, например, letterboxes[i].letters[j]
.Например:
/* allocate letterboxes[i].n_letters pointers */
letterboxes[i].letters =
malloc (sizeof *letterboxes[i].letters * letterboxes[i].n_letters);
if (!letterboxes[i].letters) { /* validate allocation */
perror ("malloc-letterboxes.letters");
return 1;
}
/* allocate letters per-pointer */
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j] =
malloc (sizeof *letterboxes[i].letters[j]);
if (!letterboxes[i].letters[j]) {
perror ("malloc-letterboxes[i].letters[j]");
return 1;
}
}
Теперь, когда все ваше хранилище правильно выделено и проверено , вы можете заполнить каждую букву каждому из людей и затем вывестирезультаты, например
// populate letter_t array for each letterbox_t
for (size_t i = 0; i < n_people; i++) {
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j]->from = "spammer";
/* added lines just to complete assignments */
letterboxes[i].letters[j]->lines = letterboxes[i].n_letters * 10;
}
}
// output all letterboxes and letters
for (size_t i = 0; i < n_people; i++) {
printf("%s has %d letters from\n",
letterboxes[i].name, letterboxes[i].n_letters);
for (int j = 0; j < letterboxes[i].n_letters; j++) {
printf(" %s %d\n", letterboxes[i].letters[j]->from,
letterboxes[i].letters[j]->lines);
}
}
Как только вы закончили использовать выделенную память, вы должны убедиться, что она правильно освобождена.(что становится критичным по мере роста ваших программ, и вы начинаете выделять их внутри функций).Неспособность освободить то, что вы используете, приводит к утечкам памяти в программах.Для этого имеет смысл написать простую функцию для полного освобождения letterbox_t
, например,
/* simple function to free single letterbox_t completely */
void freeletterbox (letterbox_t *l)
{
for (int i = 0; i < l->n_letters; i++)
free (l->letters[i]);
free (l->letters);
}
Затем, когда вы закончите с памятью, вы можете free()
ее, например,
for (size_t i = 0; i < n_people; i++) /* free each letterbox */
freeletterbox (&letterboxes[i]);
free (letterboxes); /* free pointers */
Сложив все вместе, вы можете сделать:
#include <stdio.h>
#include <stdlib.h>
typedef struct letter_t {
char *from;
int lines;
} letter_t;
typedef struct letterbox_t {
char *name;
int n_letters;
struct letter_t **letters;
} letterbox_t;
/* simple function to free single letterbox_t completely */
void freeletterbox (letterbox_t *l)
{
for (int i = 0; i < l->n_letters; i++)
free (l->letters[i]);
free (l->letters);
}
int main (void) {
char *name[] = {"amy", "bob", "claud"};
int n_letters[] = {1, 3, 2};
size_t n_people = sizeof name / sizeof *name;
// layout memory and populate letterbox_t array
struct letterbox_t *letterboxes;
/* allocate letterboxes for each of the people */
letterboxes = malloc (sizeof *letterboxes * n_people);
if (!letterboxes) { /* validate Every allocation */
perror ("malloc-letterboxes");
return 1;
}
for (size_t i = 0; i < n_people; i++) {
/* assigning pointer to string literal */
letterboxes[i].name = name[i];
letterboxes[i].n_letters = n_letters[i]; /* int assignment */
/* allocate letterboxes[i].n_letters pointers */
letterboxes[i].letters =
malloc (sizeof *letterboxes[i].letters * letterboxes[i].n_letters);
if (!letterboxes[i].letters) { /* validate allocation */
perror ("malloc-letterboxes.letters");
return 1;
}
/* allocate letters per-pointer */
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j] =
malloc (sizeof *letterboxes[i].letters[j]);
if (!letterboxes[i].letters[j]) {
perror ("malloc-letterboxes[i].letters[j]");
return 1;
}
}
}
// populate letter_t array for each letterbox_t
for (size_t i = 0; i < n_people; i++) {
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j]->from = "spammer";
/* added lines just to complete assignments */
letterboxes[i].letters[j]->lines = letterboxes[i].n_letters * 10;
}
}
// output all letterboxes and letters
for (size_t i = 0; i < n_people; i++) {
printf("%s has %d letters from\n",
letterboxes[i].name, letterboxes[i].n_letters);
for (int j = 0; j < letterboxes[i].n_letters; j++) {
printf(" %s %d\n", letterboxes[i].letters[j]->from,
letterboxes[i].letters[j]->lines);
}
}
for (size_t i = 0; i < n_people; i++) /* free each letterbox */
freeletterbox (&letterboxes[i]);
free (letterboxes); /* free pointers */
return 0;
}
Пример использования / Вывод
$ ./bin/letters
amy has 1 letters from
spammer 10
bob has 3 letters from
spammer 30
spammer 30
spammer 30
claud has 2 letters from
spammer 20
spammer 20
Использование памяти / ОшибкаПроверьте
В любом написанном вами коде, который динамически выделяет память, у вас есть 2 обязанностей в отношении любого выделенного блока памяти: (1) всегда сохраняйте указатель на начальныйадрес для блока памяти, таким образом, (2) он может быть освобожден , когда он больше не нужен.
Обязательно, чтобы вы использовали программу проверки ошибок памяти для обеспеченияВы не пытаетесь получить доступ к памяти или выполнить запись за пределами / за пределами выделенного блока, пытаетесь прочитать или основать условный переход на неинициализированном значении и, наконец, подтвердить, что вы освобождаете всю выделенную память.
Для Linux valgrind
- это нормальный выбор.Для каждой платформы есть похожие проверки памяти.Все они просты в использовании, просто запустите вашу программу через него.
$ valgrind ./bin/letters
==4735== Memcheck, a memory error detector
==4735== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4735== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4735== Command: ./bin/letters
==4735==
amy has 1 letters from
spammer 10
bob has 3 letters from
spammer 30
spammer 30
spammer 30
claud has 2 letters from
spammer 20
spammer 20
==4735==
==4735== HEAP SUMMARY:
==4735== in use at exit: 0 bytes in 0 blocks
==4735== total heap usage: 10 allocs, 10 frees, 216 bytes allocated
==4735==
==4735== All heap blocks were freed -- no leaks are possible
==4735==
==4735== For counts of detected and suppressed errors, rerun with: -v
==4735== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.
Посмотрите вещии дайте мне знать, если у вас есть дополнительные вопросы.