В дополнение к комментариям, как вы должны сделать вывод, API, используемый в отношении вашего назначения, представляет собой просто набор функций и структур данных, доступных для использования. (примечание: в C, стиль обычно избегает использования CamelCase и ЗАГЛАВНЫМИ БУКВАМИ для переменных и имен структуры, так что я буду делать то же ниже.)
В API вы получили предоставляет четыре функции allocatepool
, freepool
, store
и retrieve
вместе с одним pool
datastruct. (примечания: нет необходимости в различные struct
и typedef
тегов, поскольку они занимают разные пространства имен и не буду противоречить другу другу.) Учитывая Вашу структуру:
typedef struct pool { /* note: struct tag and typedef are not */
int size; /* required to be different (_pool, pool) */
void* memory;
} pool;
при выделении памяти для этого struct
, необходимо выделить память для struct
, и выделить хранилище для memory
. Вы можете использовать либо malloc
, либо calloc
(который будет выделять и обнулять всю новую память). Как минимум, распределение потребуется:
pool *p = malloc (sizeof *p);
p->memory = malloc (n); /* for a pool of size n */
Однако, в любое время выделения памяти, вы должны убедиться, что действительный указатель на новый блок памяти был возвращен. Так что для вашей allocatepool
функции, вы бы что-то подобное:
pool *allocatepool (int n)
{
if (n <= 0) {
fprintf (stderr, "error: invalid allocation size.\n");
return NULL;
}
pool *p = malloc (sizeof *p); /* allocate struct */
if (!p) { /* validate */
fprintf (stderr, "error: virtual memory exhausted.\n");
return NULL;
}
p->size = n;
if (!(p->memory = malloc (n))) {/* allocate pool */
fprintf (stderr, "error: virtual memory exhausted.\n");
return NULL;
}
return p;
}
Чтобы освободить память с freepool
, вы, по сути освобождая объекты, которые вы выделили, в обратном порядке. Если есть вероятность, что этот объект может быть освобожден в какой-либо промежуточной точке вашей программы, хорошо проверить, что у вас есть действительный адрес перед вызовом free
. Например, вы freepool
функция может выглядеть следующим образом:
void freepool (pool *p)
{
if (!p) return; /* validate pool address */
if (p->memory)
free (p->memory); /* free memory pool */
free (p); /* free struct */
}
Для вашего store
функции вы хотите проверить size
и offset
не превышает допустимое хранилище. Так как вы захватили size
распределения в качестве члена вашей структуры, вам нужно сравнить только запрошенные size
и offset
с членом вашей организации size
. Например:
void store (pool *p, int offset, int size, void *object)
{
if (!p) { /* validate pool address */
fprintf (stderr, "error: invalid parameter 'p'.\n");
return;
}
if (size + offset > p->size) { /* validate request */
fprintf (stderr, "error: offset + size > p->size\n");
return;
}
memcpy (p + offset, object, size); /* copy object to pool */
}
Наконец, ваш retrieve
функция, по существу, делает в обратном, что ваша store
функция делается для того, чтобы восстановить сохраненную информацию из того же offset
, к которому она была сохранена.Однако, поскольку вам нужно вернуть указатель на новый объект, вам нужно будет выделить новый объект в пределах retrieve
(в отличие от простого возврата указателя на смещение в исходном пуле памяти, где хранятся данные.) должен отслеживать возвращаемый адрес, чтобы он мог быть освобожден, когда он больше не требуется. Например:
void *retrieve (pool *p, int offset, int size)
{
if (!p) return NULL; /* validate pool address */
void *obj = malloc (size); /* allocate obj */
if (!obj) { /* validate */
fprintf (stderr, "error: virtual memory exhausted.\n");
return NULL;
}
/* copy and return */
return memcpy (obj, p + offset, size);
}
Вы можете поместить все кусочки головоломки вместе с небольшой пример программы:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { SIZE = 10 }; /* enum defining a constant SIZE as 10 */
typedef struct pool { /* note: struct tag and typedef are not */
int size; /* required to be different (_pool, pool) */
void* memory;
} pool;
pool *allocatepool (int n); /* function declarations */
void freepool (pool *p);
void store (pool *p, int offset, int size, void *object);
void *retrieve (pool *p, int offset, int size);
int main (void) {
size_t sz = SIZE; /* declare/initialize variables */
char str[] = "hello";
pool *p = NULL, *obj = NULL;
p = allocatepool (2 * sz); /* allocate p */
store (p, sz/2, sizeof str, str); /* store str in p's pool at sz/2 */
if (!(obj = retrieve (p, sz/2, sizeof str))) { /* retrieve in obj */
fprintf (stderr, "error: retrieve failed.\n");
return 1;
}
printf ("Pool API says:\n %s world.\n", (char *)obj); /* use obj */
free (obj); /* free allocated memory */
freepool (p);
return 0;
}
/* function definitions below */
Запуск программы будет производить следующие действия:
Выходной
$ ./bin/pool
Pool API says:
hello world.
Ошибка/проверка памяти Ошибка
Каждый раз, когда вы распределяете память динамически, вам необходимо (1) сохранить указатель на начальный адрес памяти, поэтому он может быть освобожден (2), когда он больше не нужен. Чтобы проверить использование вашей памяти, запустите программу, хотя проверите память, например valgrind
на Linux (на всех платформах есть аналогичные средства проверки памяти). Это просто сделать, например.
$ valgrind ./bin/pool
==16664== Memcheck, a memory error detector
==16664== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==16664== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==16664== Command: ./bin/pool
==16664==
Pool API says:
hello world.
==16664==
==16664== HEAP SUMMARY:
==16664== in use at exit: 0 bytes in 0 blocks
==16664== total heap usage: 3 allocs, 3 frees, 42 bytes allocated
==16664==
==16664== All heap blocks were freed -- no leaks are possible
==16664==
==16664== For counts of detected and suppressed errors, rerun with: -v
==16664== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Ознакомьтесь с примерами и примерами определений функций. Дело в том, чтобы продумать, какие проверки и проверки необходимы для работы вашего кода без чтения или записи за пределами выделенного пространства памяти. Это минимальные требования.
Чтобы вы определили определения для вышеперечисленных функций, они будут делать то, что предлагают имена и комментарии. – pikkewyn
@pikkewyn, поэтому мне нужно создать программу, чтобы эти ссылки (которые выполняют то, что указаны в комментариях) функционируют по назначению? – Gherkin
См. Https://en.wikipedia.org/wiki/Application_programming_interface – markgz