Freeing malloc of unknown size - c

I'm trying to free the malloc that is generated with a not fixed number of arrays.
char ** get_moves(){
// some code
char **moves = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (!moves){
return NULL;
}
for(int i = 0; i < k; i++){
moves[i] = malloc(82);
if (!moves[i]) {
free (moves);
return NULL;
}
// more code
return moves;
}
int main(){
//some code
char **res = get_moves(some_input);
//more code
for (int i = 0; i < (sizeof(res)/sizeof(res[0)); i ++){
free(res[i]);
}
free(res);
}
In one of the inputs to get_move, res should have 2 arrays but the sizeof(res)/sizeof(res[0) gives me just 1.
How is the proper way to handle this?

The only way is to keep track of the element count of the array, if you don't want to pass it to every function when passing the array, you can combine both pieces of information in a struct, like here
#include <stdlib.h>
struct ArrayOfStrings
{
int count;
char **data;
};
struct ArrayOfStrings get_moves()
{
struct ArrayOfStrings result;
char **moves;
// some code
result.count = 0;
result.data = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (result.data == NULL)
return result;
result.count = k;
moves = result.data;
for (int i = 0; i < k; i++)
{
moves[i] = malloc(82);
if (moves[i] == NULL)
{
/* also free succesfully allocated ones */
for (int j = i - 1 ; j >= 0 ; --j)
free(moves[j]);
free(moves);
}
result.count = 0;
result.data = NULL;
return result;
}
// more code
return result;
}
int main(){
//some code
struct ArrayOfStrings res = get_moves(some_input);
//more code
for (int i = 0; i < res.count ; i ++)
free(res.data[i]);
free(res.data);
return 0; // you should return from main.
}
sizeof is not for the length of an object's content but for the size of a data type, it is computed at compile time.
So in your case
sizeof(res) / sizeof(res[0]) == sizeof(char **) / sizeof(char *) == 1
since sizeof(char **) == sizeof(char *) it's just the size of a pointer.

sizeof(res)
Returns the sizeof(double-pointer);
So if you intend to get the number of pointers stored then you might not get this by doing what you are doing.
You need to do something like
for(i=0;i<k;i++) /* As I see you are allocating k no of pointer Keep track of it*/
free(res[i]);
free(res);

res is in fact not an array of arrays of char type. Instead it is a pointer to pointer to char type. sizeof(res) will give you the size of char**. You need to keep track of the number of allocations.

Since the maximum number of arrays to allocate is small (9), you can simplify your code by allocating the maximum number. Fill the unused elements with NULL:
#define MAX_K 9
char **moves = malloc(sizeof(char *) * MAX_K);
for(int i = 0; i < k; i++){
...
}
for(int i = k; i < MAX_K; i++){
moves[i] = NULL;
}
To deallocate, just ignore the NULL pointers:
for (int i = 0; i < MAX_K; i ++){
if (res[i])
free(res[i]);
}
free(res);

Related

C String Allocation Wonkiness

Having trouble understanding and getting to work String operations in the following code.
Please help, me and my study colleagues are losing our minds over this. ty.
This is a simple method to fill a multi dimensional array with custom strings - which for some reason we cannot figure out for the life of us does simply not work - spits out random junk from the memory instead. Also allocation amounts don't seem to be quite right.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
char*** createKeyPad(int rows, int cols, int num_chars) {
if(num_chars <= 0) return NULL;
char needed = 'a';
char** aptr = NULL;
char*** rptr = NULL;
aptr = (char**) malloc(rows * cols * sizeof(char*));
if(aptr == NULL) {
return NULL;
}
rptr = (char***) malloc(rows * sizeof(char**));
if(rptr == NULL) {
free(aptr);
return NULL;
}
for(int row = 0; row < rows; row++) {
rptr[row] = aptr + (row * cols);
}
for(int row = 0; row < rows; row++) {
for(int col = 0; col < cols; col++) {
char* string;
for(int i = 0; i < num_chars; i++) {
string[i] = needed;
}
string[num_chars] = '\0';
rptr[row][col] = string;
printf("%s", string);
}
}
printf("%s", "hallo");
return rptr;
}
int main() {
printf("Hello, World!\n");
char*** keypad = createKeyPad(5, 5, 3);
for(int row = 0; row < 5; row++) {
for(int col = 0; col < 5; col++) {
printf("%s", keypad[row][col]);
}
printf("\n");
}
}
You have plenty problems in this code.
string is a dangling pointer - ie it was not initialized and does not reference a valid char array
even if string was referencing a valid object you assign the same pointer to all (pseudo)array elements.
Do not use *** pointers.
use the correct type for sizes
Use positive checks and try to minimize function returns.
arrays are indexed from 0 in C and even if the string was referencing an array of num_chars elements, string[num_chars] = '\0'; is accessing an element outside the array bounds.
I would use array pointers and use only one allocation to allocate the space for the whole 3D array.
Use objects instead of types in sizeofs
int createKeyPad(size_t rows, size_t cols, size_t numChars, char (**pad)[cols][numChars])
{
int result = 0;
if(numChars > 1)
{
*pad = malloc(rows * sizeof(**pad));
if(*pad)
{
result = 1;
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
for(size_t i = 0; i < numChars - 1; i++)
{
(*pad)[row][col][i] = row * cols + col + '0';
}
(*pad)[row][col][numChars - 1] = 0;
}
}
}
}
return result;
}
int main(void)
{
printf("Hello, World!\n");
char (*keypad)[5][3];
if(createKeyPad(5, 5, 3, &keypad))
{
for(size_t row = 0; row < 5; row++)
{
for(size_t col = 0; col < 5; col++)
{
printf("%s ", keypad[row][col]);
}
printf("\n");
}
}
free(keypad);
}
https://godbolt.org/z/6zY4zbGW3
The main problem is that char* string; followed by string[i] = needed; is dereferencing an invalid pointer because string is not pointing to anything valid.
In the code's current style of allocating one block for each level and dividing the block up, the memory for all the strings could be allocated in one big block:
char* sptr = (char*) malloc(rows * cols * (num_chars + 1) * sizeof(char));
(Note: The (char*) typecast is not required. Also the * sizeof(char) is not required since sizeof(char) is 1 by definition, but I put it in there in case the code is changed to use something other than char at a later date.)
Then the string variable in the nested loop can be initialized as follows:
char* string = sptr + (row * cols + col) * (num_chars + 1);

Why do I get a segmentation fault by declaring a 2d array in c?

I am new to threads and I have a program that uses threads to find the minimum number out of a 2d array and later on, it finds the distance that the other elements of the array have from the minimum number and stores them in another array.
The user should enter the size of the array and the number of threads he wants to use.
I tried the program below for 1d array and it worked just fine. When I converted it to work for a 2d array it started crashing and throwing a segmentation fault. I, however, cannot find which part of the 2d declaration is wrong.
Any help is really appreciated.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>
struct Parameters
{
// input
int s,p; //n is size of array, p is number of threads
int** array; //array with elements
int start;
int end;
// output
int smallest;
int pos; //position if minimum
int** B; //array that holds the distances
};
void* min(void* args)
{
struct Parameters* p = (struct Parameters*)args;
int **array = p->array;
int **B1 = p->B;
int start = p->start;
int end = p->end;
int smallest = array[start][start];
int pos = p->pos;
int distance;
//find the smallest
for (int i = start; i < end; i++)
{
for(int j = start; j < end; j++)
{
if (array[i][j] < smallest)
{
smallest = array[i][j];
pos = i;
}
}
}
//find the distances
for(int i = 0; i < ((struct Parameters*)args) -> s; i++)
{
for(int j = 0; j < ((struct Parameters*)args) -> s; j++)
{
distance = abs(pos - i);
B1[i][j] = distance;
}
}
params->smallest = smallest;
params->B = B1;
return NULL;
}
int main()
{
int smallest,pos;
int s,p;
struct Parameters *ptr = (struct Parameters *)malloc(sizeof(struct Parameters));
if(ptr == NULL)
{
printf("Not enough. Try again \n");
exit(0);
}
printf("Type s\n");
scanf("%d",&(ptr->s));
printf("Type p\n");
scanf("%d", &(ptr->p));
// declare an array of threads and associated parameter instances
pthread_t threads[(ptr->p)];
struct Parameters thread_parameters[(ptr->p)] ;
int arr[ptr->s][ptr->s];
int B2[ptr->s][ptr->s];
// intialize the array
for(int i=0; i< ptr->s; i++)
{
for(int j=0; j< ptr->s; j++)
{
printf("Type a \n");
scanf("%d",&arr[i][j]);
}
}
// smallest needs to be set to something
smallest = arr[0][0];
// start all the threads
for (int i = 0; i < ptr->p; i++)
{
memcpy(arr, thread_parameters[i].array, sizeof(arr));
thread_parameters[i].s = ptr->s;
memcpy(Bb, thread_parameters[i].B, sizeof(B2));
thread_parameters[i].start = i * (ptr->s / ptr->p);
thread_parameters[i].end = (i+1) * (ptr->s / ptr->p);
pthread_create(&threads[i], NULL, min, &thread_parameters[i]);
}
// wait for all the threads to complete
for (int i = 0; i < ptr->p; i++)
{
pthread_join(threads[i], NULL);
}
// Now aggregate the "smallest" and "largest" results from all thread runs
for (int i = 0; i < ptr->p; i++)
{
if (thread_parameters[i].smallest < smallest)
{
smallest = thread_parameters[i].smallest;
}
}
printf("Smallest is %d\n", smallest);
thread_parameters[ptr->p].B[ptr->s][ptr->s];
for (int i = 0; i < 1; i++)
{
for(int j = 0; j < ptr->s;j++)
{
for(int k = 0; k < ptr->s; k++)
{
printf("Element %d is %d away from min\n",j,thread_parameters[i].B[j][k]);
}
}
}
return 0;
}
Thank you!!
The issue with your code might also come from :
memcpy(arr, thread_parameters[i].array, sizeof(arr));
...
memcpy(Bb, thread_parameters[i].B, sizeof(B2));
as thread_parameters[i].array and thread_parameters[i].B are not allocated, if you are only reading the array it might b fine to only pass them by address
thread_parameters[i].array = arr
but for thread_parameters[i].B you would need to allocate the arrays and perform a deep copy (memcpy would not work)
The below text does not answer the question but does provide some insight on VLA usage
One reason for causing the segmentation with a declaration of a Variable Length Array is that the value is to large to allocate the array on the stack (some compiler choose this option, this choice might have performance reason).
The is not much option to recover cleanly from failure to allocate memory on the stack as there is little way to clean up stack memory during runtime within the same stack context.
You can mitigate the issue by allocating your 2D arrays on the heap instead, some of the strategies are available here(thanks #Lundin) and here.
int** alloc_2d_int_array(size_t rows, size_t cols) {
int **result = malloc(rows * sizeof(int *));
if(result == NULL) {
// could not allocate more memory
return NULL;
}
size_t row_size = cols * sizeof(int);
for(int i=0; i < rows; ++i) {
result[i] = malloc(row_size);
if(result[i] == NULL) {
// could not allocate more memory
// cleanup
return NULL;
}
}
return result;
}
the above implementation have not been tested, but does compile, there are still risk of integer overflow.
Then use the above define function as following:
int **arr = alloc_2d_int_array(ptr->s, ptr->s);
int **B2 = alloc_2d_int_array(ptr->s, ptr->s);
easier implementation (see here(thanks #Lundin))
int **arr = malloc(sizeof(int[ptr->s][ptr->s]);
int **B2 = malloc(sizeof(int[ptr->s][ptr->s]);

Allocating memory for pointer struct which has pointer members

I am trying to read and print using struct pointer which has pointer members. So I am trying to read and print array of double struct pointers.
I tried the folowing but it is giving me error saying "Access violation writing location (somewhere in memory)"
How can I allocate memory dynamically for this?
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include<string.h>
#include <stdlib.h>
typedef struct template{
char *name;
int *birthdate;
int *phoneNum;
} detailsOf;
void inputValue(detailsOf **person, int maxSize);
int main() {
detailsOf **person;
int maxSize = 0, menu = 0;
printf("Max:");
scanf("%d", &maxSize);
person = (detailsOf **)malloc(maxSize * sizeof(detailsOf **));
if (person == NULL) {
printf("Failed to allocate");
exit(0);
}
for (int i = 0; i < maxSize; i++) {
person[i]->name = (char *)calloc(21, sizeof(char ));
person[i]->birthdate = (int *)calloc(8, sizeof(int ));
person[i]->phoneNum = (int *)calloc(16, sizeof(int ));
}
inputValue(person, maxSize);
for (int i = 0; i < maxSize; i++) {
free(person[i]);
for (int j = 0; j < 21; j++) {
free(person[i]->name[j]);
}
for (int j = 0; j < 15; j++) {
free(person[i]->phoneNum[j]);
}
for (int j = 0; j < 8; j++) {
free(person[i]->birthdate[j]);
}
}
return 0;
}
void inputValue(detailsOf **person, int maxSize) {
for (int i = 0; i < maxSize; i++) {
printf("Name of %d", i + 1);
scanf("%s", person[i]->name);
for (int j = 0; j < 8; j++) {
printf("Birth %d:", i + 1);
scanf("%d", person[i]->birthdate[j]);
}
for (int k = 0; k < 8; k++) {
printf("Phone %d:", i + 1);
scanf("%d", person[i]->phoneNum[k]);
}
}
printf("SUCCESS\n");
}
person = (detailsOf **)malloc(maxSize * sizeof(detailsOf **));
should be
person = malloc(maxSize * sizeof(detailsOf *));
Then, this allocated memory to hold pointers to detailsOf but you never allocate memory for each detailsOf
for(int i=0; i<maxSize; i++)
{
person[i]=malloc(sizeof(detailsOf));
}
Also your freeing of memory should be
for (int i = 0; i < maxSize; i++)
{
free(person[i]->name);
free(person[i]->phoneNum);
free(person[i]->birthdate);
free(person[i]);
}
free(person);
Remember while freeing just match your free calls with malloc calls.
Rule is simple -- a pointer is uninitialized until it has had a valid address assigned to it, or memory has been allocated within which to store things and the starting address for the new block of memory assigned to it.
You allocate maxSize pointers for person, but then fail to allocate a struct for each person[i] before allocating for name, etc..
So you must allocate a struct, e.g. pointer[i] = malloc (sizeof *pointer[i]) before attempting to allocate person[i]->name = calloc(21, sizeof(char ));, ...
Also note, if you allocate based on the size of the derefernced pointer -- you will never get your allocation wrong, (your allocation of person is only correct as the result of happy-accident), instead, e.g.
person = malloc (maxSize * sizeof *person);
...
person[i] = malloc (sizeof *person[i]);
(and note a [] or -> counts as a dereference)
person[i]->name = calloc (21, sizeof *person[i]->name);
There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?
person = (detailsOf **)malloc(maxSize * sizeof(detailsOf **));
This allocates an array of double pointers to type detailsOf with array size as maxSize.
sizeof(detailsOf**) is the size of an address, it does not give you the size of your user-defined datatype detailsOf.
Also, double pointer means, it is an address location which will store the address of another pointer which points to the memory location of detailsOf
/* if you want to use double pointer then */
detailsOf **dptr; // two dimensional array of detailsOf */
detailsOf *sptr; /* one dimentional array of detailsOf */
/* This allocates the memory for storing 3 detailsOf struct data */
sptr = malloc(3 * sizeof(detailsOf));
dptr = &sptr;
/* Now to access double ptr */
for (int i = 0; i < 3; ++i) {
dptr[0][i].birthdate = malloc(3 * sizeof(int));
}
for (int i = 0; i < 3; ++i) {
dptr[0][i].birthdate[0] = i;
dptr[0][i].birthdate[1] = i + 10;
dptr[0][i].birthdate[2] = i + 1990;
}
for (int i = 0; i < 3; ++i) {
printf("%d\\", dptr[0][i].birthdate[0]);
printf("%d\\", dptr[0][i].birthdate[1]);
printf("%d\n", dptr[0][i].birthdate[2]);
}
/* Not to free the double pointer,
* you have to free the inner pointer first then the outer pointers
* Easy to remember is to free in reverse order of your allocation order
*/
for (int i = 0; i < 3; ++i) {
free(dptr[0][i].birthdate);
free(dptr[0]);
/* free(dptr); this is not needed in this example because
* dptr is pointer to address of a local variable,
* but if it points to address of another array of detailOf*
* then this free is needed
*/
}
In your case, you have just an array of pointer and not an array of double pointers.

How to malloc/free a struct with a contained 2D array

So my goal is to malloc a maze struct that contains a 2D array; however, when I try to allocate memory for each "cell" of the 2D array I can't seem to free it properly afterwards. Is there a way that I could malloc the struct in one line or at least in a way that I can easily free the allocated memory with the free_maze function? I've attached my .c file along with the header file that defines the struct. Additionally, I have attached an example of a maze that is contained within a text file.
#include <stdlib.h>
#include "maze.h"
Maze* malloc_maze(int num_rows, int num_cols){
Maze* maze = malloc(sizeof(*maze));
if (maze == NULL){
free(maze);
return NULL;
}
maze -> cells = malloc(sizeof(maze -> cells)*(num_cols));
if (maze -> cells == NULL){
free(maze);
return NULL;
}
for(int i = 0; i < num_cols; i++){
maze -> cells[i] = malloc(sizeof(*(maze -> cells))*(num_rows));
}
maze -> num_rows = num_rows;
maze -> num_cols = num_cols;
return maze;
}
void free_maze(Maze* maze){
free(maze);
}
Maze* read_maze(FILE* fp){
Maze* maze;
char c = fgetc(fp);
int rows = 0;
int cols = 0;
int chars = 0;
while(c != EOF){
chars++;
c = fgetc(fp);
}
rewind(fp);
while(c != '\n'){
cols++;
c = fgetc(fp);
}
rows = chars / cols;
cols--;
maze = malloc_maze(rows, cols);
rewind(fp);
for(int row_count =0; row_count <= rows; row_count++){
for(int col_count = 0; col_count < cols; col_count++){
fseek(fp, (row_count*(cols+1)+col_count), SEEK_SET);
maze -> cells[col_count][row_count] = fgetc(fp);
}
}
maze -> num_rows = rows;
maze -> num_cols = cols;
return maze;
}
bool write_maze(const char* filename, const Maze* maze){
FILE* ha;
ha = fopen(filename, "w");
if(ha == NULL){
return false;
}
rewind(ha);
int rows = maze -> num_rows;
int cols = maze -> num_cols;
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
fputc(maze -> cells[j][i], ha);
}
fputc('\n', ha);
}
fclose(ha);
return true;
}
/////////////////header file//////////////////////////
#ifndef MAZE_H
#define MAZE_H
#define WALL 'X'
#define PATH ' '
#include <stdio.h>
#include <stdbool.h>
typedef struct _Maze {
int num_rows;
int num_cols;
char** cells;
} Maze;
Maze* malloc_maze(int num_rows, int num_cols);
void free_maze(Maze* maze){
__attribute__((nonnull));
}
Maze* read_maze(FILE* fp){
__attribute__((nonnull));
}
bool write_maze(const char* filename, const Maze* maze){
__attribute__((nonnull));
}
///////////////example maze within .txt file/////////////////////
XXXXX XXX
X X
X XXX XXX
X X X X
X X XXXXX
X X
XXXXX XXX
Given an allocator function, the deallocator writes itself - you free the pointers in roughly the reverse order they were allocated.
So, given that the allocator is (only reformatted from the question — functionality unchanged):
Maze *malloc_maze(int num_rows, int num_cols)
{
Maze *maze = malloc(sizeof(*maze));
if (maze == NULL)
{
free(maze);
return NULL;
}
maze->cells = malloc(sizeof(maze->cells) * (num_cols));
if (maze->cells == NULL)
{
free(maze);
return NULL;
}
for (int i = 0; i < num_cols; i++)
{
maze->cells[i] = malloc(sizeof(*(maze->cells)) * (num_rows));
}
maze->num_rows = num_rows;
maze->num_cols = num_cols;
return maze;
}
the deallocator should be:
void free_maze(Maze *maze)
{
for (int i = 0; i < num_cols; i++)
free(maze->cells[i]);
free(maze->cells);
free(maze);
}
This makes sure the code doesn't try to access memory after it is freed.
However, closer analysis of the allocator shows that there are some (minor) problems. For example, normally you treat the pair of indexes as maze->cells[row][col], but the memory allocation requires it to be used as maze->cells[col][row]. Both can work, but the row-column order is more usual in C. Also, the sizes in the second and third malloc() calls are incorrect. Fortunately for you, the second one allocates in units of sizeof(char **) instead of sizeof(char *), but those are the same size, so it "doesn't matter". The third one allocates sizeof(char *) units, instead of sizeof(char), so there is much more memory allocated than memory (normally, sizeof(char *) is 4 or 8 bytes but sizeof(char) is 1 by definition).
So, you might do better to use this, which keeps the maze->cells[col][row] access notation:
Maze *malloc_maze(int num_rows, int num_cols)
{
Maze *maze = malloc(sizeof(*maze));
if (maze == NULL)
return NULL;
maze->cells = malloc(sizeof(maze->cells[0]) * num_cols);
if (maze->cells == NULL)
{
free(maze);
return NULL;
}
for (int i = 0; i < num_cols; i++)
{
maze->cells[i] = malloc(sizeof(maze->cells[0][0]) * num_rows);
if (maze->cells[i] == 0)
{
for (int j = 0; j < i; j++)
free(maze->cells[j]);
free(maze->cells);
free(maze);
return NULL;
}
}
maze->num_rows = num_rows;
maze->num_cols = num_cols;
return maze;
}
This cleans up the partially allocated memory on allocation failure. It doesn't change the deallocation code (unless you want to add a null check, but if the allocation failed, you shouldn't be calling the deallocation code).
NOTE: I believe the code automatically takes care of alignment in OP's case. I am still working on to tweak it to work with any data type of members of Maze. The alignment is broken if sizeof(char*) exceeds sizeof(T) where T is the type of cell[0][0].
You can allocate memory for the entire maze in one malloc call. This will allow you to free the memory in one free call. It improves performance because:
it requires a single malloc (and free) call
the memory allocated is contiguous (cache friendly)
Maze *malloc_maze(int num_rows, int num_cols)
{
const size_t mem_size = sizeof(Maze)
+ num_cols*sizeof(((Maze*)0)->cells[0]) /* indirection array */
+ sizeof((((Maze*)0)->cells[0][0]))*num_cols*num_rows; /* matrix */
void *block = malloc(mem_size);
if(block == NULL)
return NULL;
Maze *maze = block;
maze->cells = (void*)(maze + 1);
block = &maze->cells[0] + num_cols;
for(int i = 0; i < num_cols; i++)
{
maze->cells[i] = block;
block = &maze->cells[i][0] + num_rows;
}
maze->num_rows = num_rows;
maze->num_cols = num_cols;
return maze;
}
void free_maze(Maze *maze)
{
free(maze);
}

Generate int of numbers between 1 and n with dynamic n

I am struggling with an algorithm to print numbers between 1 and a dynamic variable n into an int.
int n = // dynamic value
int i = 0;
int output[n];
for(i = 0; i < n; i++) {
output[i] = i;
}
However, as n is dynamic, the code won't compile.
Any help would be much appreciated - thanks in advance.
You need to allocate a buffer, or dynamic-sized array, with malloc:
int n = // whatever
int i = 0;
int* output = NULL;
// Allocate the buffer
output = malloc(n * sizeof(int));
if (!output) {
fprintf(stderr, "Failed to allocate.\n");
exit(1);
}
// Do the work with the array
for(i = 0; i < n; i++) {
output[i] = i;
}
// Finished with the array
free(output);
output is a pointer to the beginning of the buffer you allocated, and you can treat it as an array of n ints.
When you're finished with the array, you need to de-allocate the memory with free.
This should work:
int n = // whatever
int i = 0;
int* output = (int*)malloc(sizeof(int)*n);
for(i = 0; i < n; i++) {
output[i] = i;
}
Don't forget to free(output); when you don't need it anymore.
EDIT: Made it C.
If 'n' is changing during runtime, then you could use malloc like suggested in the comments. Then check if you need more space, then automatically realloc more space should it be needed

Resources