allocate a 3d array that contains strings - c

I wrote a 'class' that can store strings (2d array/matrix). This works fine, but now I need a way to store that matrix. So I need to calloc the 3tensor but i am not sure how to do it beyond the matrice allocation.
My 2d array looks like this: \
#pragma once
#include <stdlib.h>
#include <stdint.h> /* uints */
#include <string.h> /* char */
/* struct that holds data about the matrix, so it can be resized when needed */
struct Arr {
char** cArr;
unsigned int currentSize, maxSize;
};
/* initial allocation function that is used when a array needs te be calloced at first */
uint8_t initialAlloc(struct Arr* arr);
/* reallocate the array to a hardcoded size */
uint8_t reallocArr(struct Arr* arr);
/* add an element to the array in arr */
void addToArr(struct Arr* arr, char* element);
#include "arr.h"
uint8_t initialAlloc(struct Arr* arr) {
arr->currentSize = 0;
arr->maxSize = 2;
arr->cArr = calloc(2, sizeof(char*));
if (!arr->cArr) {
return 0;
}
for (uint8_t x = 0; x < arr->maxSize; ++x) {
arr->cArr[x] = calloc(600, sizeof(char));
if (!arr->cArr[x]) {
return 0;
}
}
return 1;
}
void addToArr(struct Arr* arr, char* element) {
if (arr->currentSize == arr->maxSize) {
if (!reallocArr(arr)) {
/* if the memory allocation fails something is bad wrong */
exit(1);
}
}
strncpy(arr->cArr[arr->currentSize], element, strlen(element));
++arr->currentSize;
}
uint8_t reallocArr(struct Arr* arr) {
uint16_t resizeTo = arr->maxSize * 2;
arr->cArr = realloc(arr->cArr, resizeTo * sizeof(char*));
if (!arr->cArr) {
return 0;
}
for (uint16_t x = arr->currentSize; x < resizeTo; ++x) {
arr->cArr[x] = calloc(600, sizeof(char));
if (!arr->cArr[x]) {
return 0;
}
}
arr->maxSize = arr->maxSize * 2;
return 1;
}
I want to use the Arr struct inside the 3tensor.
#pragma once
#include <stdlib.h> /* basic functions */
#include <stdint.h> /* uint */
/* user includes */
#include "characterArr.h"
/* user includes */
struct Tensor {
char*** mArr;
unsigned int currentSize, maxSize;
};
uint8_t initialAllocTensor(struct Tensor* tensor);
uint8_t reallocTensor(struct Tensor* tensor);
void addToTensor(struct Tensor* tensor, struct Arr* arr);
/* user includes */
#include "tensor.h"
/* user includes */
/* initial allocation function that is used when a array needs te be calloced at first */
uint8_t initialAllocTensor(struct Tensor* tensor) {
tensor->currentSize = 0;
tensor->maxSize = 2;
tensor->mArr = calloc(2, sizeof(struct *Arr));
if (!tensor->mArr) {
return 0;
}
for (uint8_t x = 0; x < arr->maxSize; ++x) {
arr->cArr[x] = calloc(600, sizeof(char));
if (!arr->cArr[x]) {
return 0;
}
}
return 1;
}
After I allocate the memory that will contain the pointers to the Arr struct, I get lost. The reason is, I need the information in the Arr struct for later use, so why would I recopy all the data from the Arr struct that i already have into the newly created 3Tensor. Could I just store a pointer to the Arr struct in the Tensor then be done? If i do this, would I be able to access the Arr struct just fine? Since I malloced this, I wouldn't need to worry about the memory getting taken when it goes out of scope.

Related

Use realloc() in function

#include <stdio.h>
#include <stdlib.h>
void Increase(int *array1,int *Nums) {
int*array2 = realloc(array1,(*Nums+1)*sizeof(int));
array2[*Nums] = 13;
array2[*Nums-1] = 14;
++(*Nums);
}
int main() {
int NumOfElements=0,i;
int*array=(int*)malloc(0*sizeof(int));
Increase(array,&NumOfElements);
for(i=0;i<NumOfElements;i++) {
printf("%d ", array[i]);
}
free(array);
}
How many elements will be in the array in main() if I run this program?
Does the Increase() function increase the number of memory cells of the array in main(), or will the array in main() still just have 0 memory cells?
From the realloc manual page:
The realloc() function returns a pointer to the newly allocated
memory, which is suitably aligned for any kind of variable and may be
different from ptr, or NULL if the request fails.
... so the answer to your question will depend on whether the call to realloc() was able to change the memory-allocation's size in-place, or not.
If realloc() was able to do an in-place resize (e.g. because the heap had allocated a larger-than-necessary array for the original malloc() call, allowing realloc() to simply mark some of the extra bytes in the buffer as in-use), then realloc() would return the same pointer that was passed in to it as an argument, which is the same memory-location that main() points to via array. In this scenario, main() could access the now-larger-array via array without any problems.
On the other hand, if realloc() wasn't able to do an in-place resize, then realloc() would be forced to allocate a newer/larger array, copy over the contents of the old array, free() the old array, and return the pointer to the larger array. In that case, array2 would point to a different location in memory than array and array1, and (worse), after Increase() returns, main() would invoke undefined behavior by dereferencing array, which is (at that point) a dangling pointer because realloc() freed the memory it used to point to.
I think one is intending to implement a common container known a dynamic array for use in a stack (or similar structure.)
#include <stddef.h>
struct int_stack { int *data; size_t size, capacity; };
struct int_stack int_stack(void);
void int_stack_(struct int_stack *);
int *int_stack_new(struct int_stack *);
This is what I'd use as int_stack.h. Notice that it's logical size and it's capacity are not necessarily the same, but size <= capacity.
#include "int_stack.h"
#include <stdlib.h>
#include <errno.h>
/** Initialises `s` to idle. */
struct int_stack int_stack(void) {
struct int_stack s;
s.data = 0;
s.capacity = s.size = 0;
return s;
}
/** Destroys `s`; returns it idle. */
void int_stack_(struct int_stack *const s) {
free(s->data);
*s = int_stack();
}
/** Ensures `min_capacity` of `s`. Returns success, otherwise, `errno` will be
set. */
static int int_stack_reserve(struct int_stack *const s, const size_t min) {
size_t c0;
int *data;
const size_t max_size = (size_t)-1 / sizeof *s->data, min_size = 3;
if(s->data) {
if(min <= s->capacity) return 1;
c0 = s->capacity < min_size ? min_size : s->capacity;
} else { /* Idle. */
if(!min) return 1;
c0 = min_size;
}
if(min > max_size) return errno = ERANGE, 0;
/* `c_n = a1.625^n`, approximation golden ratio `\phi ~ 1.618`. */
while(c0 < min) {
size_t c1 = c0 + (c0 >> 1) + (c0 >> 3);
if(c0 > c1) { c0 = max_size; break; }
c0 = c1;
}
if(!(data = realloc(s->data, sizeof *s->data * c0)))
{ if(!errno) errno = ERANGE; return 0; }
s->data = data, s->capacity = c0;
return 1;
}
/** Increases the capacity of `s` to at least `n` elements beyond the size.
Returns the start of the buffered space at the back of the array or null and
`errno`. */
static int *int_stack_buffer(struct int_stack *const s, const size_t n) {
if(s->size > (size_t)-1 - n) { errno = ERANGE; return 0; } /* Unlikely. */
return int_stack_reserve(s, s->size + n) && s->data ? s->data + s->size : 0;
}
/** Adds `n` elements to the back of `s` and returns a pointer to the elements.
Null indicates an error and `errno` will be set. */
static int *int_stack_append(struct int_stack *const s, const size_t n) {
int *buffer;
if(!(buffer = int_stack_buffer(s, n))) return 0;
return s->size += n, buffer;
}
/** Adds one new element of `s` and returns it as an uninitialized pointer or
null and `errno`. */
int *int_stack_new(struct int_stack *const s) { return int_stack_append(s, 1); }
This is an example of what I'd use as the implementation int_stack.c. The function int_stack_reserve is where the realloc is called once the size reaches the capacity. A temporary data is assigned the realloc; this is checked for error, then assigned into s->data. Reserving a geometrically increasing capacity will avoid the cost of expanding each time. Thus, the array will have amortized cost of O(n) to insert n elements.
#include <stdio.h>
#include <stdlib.h>
#include "int_stack.h"
int main(void) {
int status = EXIT_SUCCESS;
int *e1, *e2;
struct int_stack stack = int_stack();
if(!(e1 = int_stack_new(&stack)) || !(e2 = int_stack_new(&stack))) {
status = EXIT_FAILURE;
perror("stack");
} else {
*e1 = 13;
*e2 = 14;
for(size_t i=0; i<stack.size; i++) {
printf("%d ", stack.data[i]);
}
fputc('\n', stdout);
}
int_stack_(&stack);
return status;
}
Instead of a fixed-size, we now have unlimited size, but one has to check for out-of-memory condition.

How to properly make a dynamically allocated multi-array in C

I have been working to create a set of functions that allow for the creation and manipulation of a dynamically allocated array in C for any data type. I have created several functions, but of most relevance to this post are the following functions;
vector_mem_alloc This function is not called directly, but when indirectly called in a wrapper it allocates memory for the array based on the data type
init_vector This function is called directly by a user and is a wrapper around vector_mem_alloc. This function preps data and instantiates certain parameters in the Vector struct.
append_vector This function allows a user to append the 1-D array with scalar values or another already created array.
The code for these working functions is shown below.
vector.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef enum
{
FLOAT,
DOUBLE,
CHAR,
INT
} dat_type;
typedef struct
{
void *array; // Pointer to array
size_t len; // Active length of array
size_t size; // Number of allocated indizes
int elem; // Memory consumption per indice
char name[20]; // The array name
dat_type dat;
} Vector;
// --------------------------------------------------------------------------------
void vector_mem_alloc(Vector *array, size_t num_indices);
// --------------------------------------------------------------------------------
Vector init_vector(dat_type dat, size_t num_indices, char *name);
// --------------------------------------------------------------------------------
int append_vector(Vector *array, void *elements, size_t count);
#endif /* ARRAY_H */
vector.c
#include "vector.h"
// Begin code
void vector_mem_alloc(Vector *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
exit(0);
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
array->size = num_indices;
}
}
// --------------------------------------------------------------------------------
Vector init_vector(dat_type dat, size_t num_indices, char *name) {
// Determine memory blocks based on data type
int size;
switch(dat) {
case FLOAT:
size = sizeof(float);
break;
case INT:
size = sizeof(int);
break;
case DOUBLE:
size = sizeof(double);
break;
case CHAR:
size = sizeof(char);
break;
default:
printf("Data type not correctly entered, instantiating int array!\n");
size = sizeof(int);
dat = INT;
}
// Allocate indice size and call array_mem_alloc
Vector array;
array.dat = dat;
array.elem = size;
vector_mem_alloc(&array, num_indices);
strncpy(array.name, name, sizeof(array.name));
return array;
}
// --------------------------------------------------------------------------------
int append_vector(Vector *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len + count > array->size) {
size_t size = (array->len + count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
return 0;
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Append variables and increment the array length
memcpy((char *)array->array + array->len * array->elem, elements, count * array->elem);
array->len += count;
return 1;
}
main.c
// - This shows an implementation for an integer array, but it works
// for FLOAT, DOUBLE, and CHAR as well.
size_t indices = 10;
char name[6] = "array";
dat_type dtype = INT;
Vector arr_test = init_vector(dtype, indices, name);
int a[3] = {10, 9, 8};
append_vector(&arr_test, &a, 3);
Everything listed above works just fine. However, I am trying to expand the capability of the above code to cover multi-arrays of any data type; however, in the near term I am particularly interested in string arrays. I am trying to add another struct to the vector.h file that references marray[] as a data type of Vector. In the long run, I hope to be able to reference the name of each array in the multi-array and treat it similar to a dictionary. I have tried several function that might allow an interface like shown below, but so far none of them work. Does anyone have any suggestions that I might be able to use as a starting point in building this functionality. My intended addition to the vector.h file is shown below with a main.c implentation that shows how I hope to interface with this.
typedef struct
{
size_t len;
size_t size;
int elem;
dat_type dat;
Vector *marray[];
} MVector;
size_t indices = 10;
dat_type dtype = INT;
MVector arr_test = init_vector(dtype, indices);
int a[3] = {10, 9, 8};
append_vector(&arr_test[0], &a, 3);
int b = 3;
append_vector(&arr_test[1], &b, 1);
append_vector(&arr_test[1], &b, 1);
b = 4;
append_vector(&arr_test[1], &b, 1)
append_vector(&arr_test[1], &b, 1);
// result [[10, 9, 8], [3, 3, 4, 4]]

function to clear malloc, and make pointer to null

in my last question, I've asked how to use function to free an malloc'ed array, I wanted to improve my code so that the function won't just free the memory but also will set the pointer to NULL once it finishes the clearing.
Also I want a single function to do both - setting and clearing, depending on the command I'm passing, this is what I've done so far:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint-gcc.h>
char **set_arr(int number, char *command);
int command_read(char *command);
void clear_arr(char *arr[], int size);
char set[] = "set";
char clear[] = "clear";
int main() {
int num = // get number from user;
char** my_arr = NULL;
my_arr = set_arr(num, set);
// so far the code works as excepted
set_arr((size_t)&my_arr, clear);
return 0;
}
int command_read(char *command) {
if (strcmp(command, set) == 0)
return 'S';
if (strcmp(command, clear) == 0)
return 'C';
}
char **set_arr(int number, char *command) {
static char **arr = NULL;
static int size;
switch (command_read(command)) {
case 'S':
size = (int)number;
arr = malloc((size + 1) * sizeof(char *));
for (int i = 0; i <= size; i++) {
arr[i] = NULL;
if (i == size)
break;
arr[i] = malloc((string_len) * sizeof(char));
}
break;
case 'C':
clear_arr(arr, size);
free(arr);
uintptr_t value = number;
uint64_t *temp = (void *)value;
*temp = 0x0;
break;
}
return arr;
}
void clear_arr(char *arr[], int size) {
for (int i = 0; i < size; i++) {
free(arr[i]);
arr[i] = NULL;
}
}
I know that there is better methods to clear (and allocate memory?) but my primary question is, did I free all the memory I allocated for the array, and after the clearing, does the pointer my_arr is set correctly to NULL?
Writing a generic function to achieve your goal is not possible in Standard C because pointers to different types of objects may have a different representation so you cannot pass the address of a pointer and expect the function to handle it in a generic manner.
Yet this provision in the C Standard is not used on most current systems today. In particular, the POSIX standard mandates that all pointers have the same representation. Hence your generic function can work on these systems, with some precautions to avoid compilation warnings:
// free an array of allocated things
void free_array(void ***p, size_t count) {
void **array = *p;
for (size_t i = 0; i < count; i++) {
free(array[i]);
array[i] = NULL; // for safety
}
free(array);
*p = NULL;
}
// deal with the non portable conversion with macros
#define FREE_ARRAY(p, n) free_array((void ***)(void *)&(p), n)
// allocate an array of pointers to allocated things of size `size`.
// return a pointer to the array or `NULL` if any allocation failed
void **malloc_array(size_t count, size_t size) {
void **array = malloc(count * sizeof(*array));
if (array) {
for (size_t i = 0; i < count; i++) {
array[i] = calloc(size, 1); // allocate and initialize to all bits zero
if (array[i] == NULL) {
while (i-- > 0) {
free(array[i]);
array[i] = NULL;
}
return NULL;
}
}
}
return array;
}
#define MALLOC_ARRAY(n, type) ((type **)(void *)malloc_array(n, sizeof(type)))
#define MALLOC_2D_ARRAY(n1, n2, type) ((type **)(void *)malloc_array(n1, (n2) * sizeof(type)))
Passing the command as a string is very inefficient. You should use an int or an enum for the command, but you can use the above macros and code in your program this way:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint-gcc.h>
int main() {
int string_len = 100;
int num = 10; // get number from user;
char **my_arr = MALLOC_2D_ARRAY(num, string_len, char);
FREE_ARRAY(my_arr, num);
return 0;
}

How to declare a pointer to an array of pointer

I have a task to create an array of pointers to structure. I need to use just void functions and "malloc". I have no idea how to do it, could you help me?
void create1(apteka*** a, int size)
{
**a = (apteka**) malloc(size* sizeof(apteka*));
for (int i = 0; i < size; i++)
{
x[0][i] = (apteka*)malloc(size * sizeof(apteka));
}
}
I have a task to create an array of pointers to structure
You need two "sizes":
The number of pointers
The size of the struct
You only pass one.
So fix your code for example like this
#include <stdlib.h> /* for malloc(), free() */
void create1(void *** pppv, size_t n, size_t s)
{
assert(NULL != pppv);
*pppv = malloc(n * sizeof **pppv);
if (NULL != *pppv)
{
for (size_t i = 0; i < n; ++i)
{
(*pppv)[i] = malloc(s);
if (NULL == (*pppv)[i])
{
/* Failed to completely allocate what has been requested,
so clean up */
for (--i; i >= 0; --i)
{
free((*pppv)[i]);
}
free(*pppv);
*pppv = NULL;
break;
}
}
}
}
Use it like this:
#include <stdlib.h> /* for size_t, free(), exit(), EXIT_FAILURE */
#include <stdio.h> /* for fputs() */
void create1(void ***, size_t, size_t);
struct my_struct
{
int i;
... /* more elements here */
}
#define N (42) /* Number of elements */
int main(void)
{
struct my_struct ** pps = NULL;
create1(&pps, N, sizeof **pps);
if (NULL == pps)
{
fputs(stderr, "create1() failed\n", stderr);
exit(EXIT_FAILURE);
}
/* use array pps[0..N]->i here */
/*Clean up */
for (size_t i = 0; i < N; --i)
{
free(pps[i]);
}
free(pps);
}

Returning a 2D char array in C

I messed around with this enough but I really don't get it.
Here is what I want to do: Take a 2D char array as an input in a function, change the values in it and then return another 2D char array.
That's it. Quite simple idea, but ideas do not get to work easily in C.
Any idea to get me started in its simplest form is appreciated. Thanks.
C will not return an array from a function.
You can do several things that might be close enough:
You can package your array in struct and return that. C will return structs from functions just fine. The downside is this can be a lot of memory copying back and forth:
struct arr {
int arr[50][50];
}
struct arr function(struct arr a) {
struct arr result;
/* operate on a.arr[i][j]
storing into result.arr[i][j] */
return result;
}
You can return a pointer to your array. This pointer must point to memory you allocate with malloc(3) for the array. (Or another memory allocation primitive that doesn't allocate memory from the stack.)
int **function(int param[][50]) {
int arr[][50] = malloc(50 * 50 * sizeof int);
/* store into arr[i][j] */
return arr;
}
You can operate on the array pointer passed into your function and modify the input array in place.
void function(int param[][50]) {
/* operate on param[i][j] directly -- destroys input */
}
You can use a parameter as an "output variable" and use that to "return" the new array. This is best if you want the caller to allocate memory or if you want to indicate success or failure:
int output[][50];
int function(int param[][50], int &output[][50]) {
output = malloc(50 * 50 * sizeof int);
/* write into output[i][j] */
return success_or_failure;
}
Or, for the caller to allocate:
int output[50][50];
void function(int param[][50], int output[][50]) {
/* write into output[i][j] */
}
You cannot return an array from a function.
You have several options:
wrap arrays inside structs
struct wraparray {
int array[42][42];
};
struct wraparray foobar(void) {
struct wraparray ret = {0};
return ret;
}
pass the destination array, as a pointer to its first element (and its size), to the function; and change that array
int foobar(int *dst, size_t rows, size_t cols, const int *src) {
size_t len = rows * cols;
while (len--) {
*dst++ = 42 + *src++;
}
return 0; /* ok */
}
// example usage
int x[42][42];
int y[42][42];
foobar(x[0], 42, 42, y[0]);
change the original array
int foobar(int *arr, size_t rows, size_t cols) {
size_t len = rows * cols;
while (len--) *arr++ = 0;
return 0; /* ok */
}
char **foo(const char * const * bar, size_t const *bar_len, size_t len0) {
size_t i;
char** arr = malloc(sizeof(char *) * len0);
for (i = 0; i < len0; ++i) {
arr[i] = malloc(bar_len[i]);
memcpy(arr[i], bar[i], bar_len[i]);
}
/* do something with arr */
return arr;
}
Somewhere else in your code:
char **pp;
size_t *pl;
size_t ppl;
/* Assume pp, pl are valid */
char **pq = foo(pp, pl, ppl);
/* Do something with pq */
/* ... */
/* Cleanup pq */
{
size_t i;
for (i = 0; i < ppl; ++i)
free(pq[i]);
free(pq);
}
Because you're passing by-pointer instead of by-value and you want to write to the input array, you have to make a copy of it.
Here's another example. Tested and works.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char**,unsigned int,unsigned int);
const unsigned int sz_fld = 50 + 1;
const unsigned int sz_ffld = 10;
int main(void) {
char fld[sz_ffld][sz_fld];
for (unsigned char i=0;i<sz_ffld;++i) {
strcpy(fld[i],"");
}
strcpy(fld[0],"one");
strcpy(fld[1],"two");
strcpy(fld[2],"three");
char** pfld = malloc(sz_ffld*sizeof(char*));
for (unsigned int i=0;i<sz_ffld;++i) {
*(pfld+i) = &fld[i][0];
}
test(pfld,sz_ffld,sz_fld);
printf("%s\n",fld[0]);
printf("%s\n",fld[1]);
printf("%s\n",fld[2]);
free(pfld);
return(0);
}
void test(char** fld,unsigned int m,unsigned int n) {
strcpy(*(fld+0),"eleven");
strcpy(*(fld+1),"twelve");
return;
}
Note the following:
For compiling, I am using gcc with the C99 option.
I defined the function to include the two sizes information, but I wrote very basic code and am not actually using the information at all, just the strcpy(), so this certainly is not security-safe code in any way (even though I'm showing the "m" and "n" for such facility). It merely shows a technique for making a static 2D char array, and working with it in a function through the intermediate of an array of pointers to the "strings" of the array.
When you pass a 2D array to a function as a parameter, you need to explicitly tell it the size of the arrays second dimension
void MyFunction(array2d[][20]) { ... }
The following will do what you want. it will print "One" and "Ten". Also note that it is typed to the exact array dimensions of 10 and 8.
char my_array[10][8] =
{
{"One"},
{"Two"},
{"One"},
{"One"},
{"One"},
{"One"},
{"One"},
{"One"},
{"Nine"},
{"Ten"},
};
void foo ( char (**ret)[10][8] )
{
*ret = my_array;
}
void main()
{
char (*ret)[10][8];
foo(&ret);
printf("%s\r\n", (*ret)[0] )
printf("%s\r\n", (*ret)[9] )
}
The original question was about RETURNING the array, so I'm updating this to show returning a value. You can't "return an array" directly, but you CAN make a typedef of an array and return that...
char my_array[10][8];
typedef char ReturnArray[8];
ReturnArray* foo()
{
return my_array;
}

Resources