How to declare a pointer to an array of pointer - c

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);
}

Related

allocate a 3d array that contains strings

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.

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;
}

Pass a structure to a function and store values in the structure's element

I want to pass a structure to a function and store value in the structure's element. Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct {
uint32_t len;
uint16_t *arr;
} seq;
void write_seq(seq *q, int val)
{
// How to implement this function?
uint16_t *tmp;
tmp = (uint16_t *)malloc(sizeof(uint16_t));
*tmp = val;
*(q->arr + q->len) = *tmp;
q->len += 1;
}
int main(int argc, char *argv[])
{
seq q;
q.len = 0;
q.arr = NULL;
int i;
for (i = 0; i < 10; i++) {
write_seq(&q, i);
}
printf("length is %d\n", q.len);
for (i = 0; i < q.len; i++) {
printf("%d\n", *(q.arr+i));
}
return 0;
}
I want to write 0 to 9 to a memory block which q.arr points to.
I don't want to use malloc in main(), since I don't know how many bytes I need before I call write_seq. I want to locate new memory every time when write_seq is called. Here's how output should look like.
length is 10
0
1
2
3
4
5
6
7
8
9
My implementation of write_seq() would cause core dumped. I don't know how to fix it. Thank you.
To add members to the array when you don't know in advance the size of that array, you'd need to use realloc() to increase the size on demand. However it's inefficient to do that for every change to the array size, so it would be more usual to allow for a certain amount of headroom (whether that be a fixed increment or a percentage based amount) in the buffer.
The corollary of that is you need to store the current capacity of the buffer as well as the offset to the amount currently used.
This also means that there'll be a certain amount of memory wastage, but that's the trade off you have to make.
My approach would look something like this, abstracting the operations that you might want to perform on a seq.
typedef struct {
size_t capacity;
size_t offset;
uint16_t *arr;
} seq;
static const size_t SEQ_INITIAL = 8;
static const size_t SEQ_INCREMENT = 8;
int seq_init(seq *seq) {
assert(seq != NULL); /* catch null seq */
assert(seq->arr == NULL); /* error to call on already init'd seq */
seq->capacity = SEQ_INITIAL;
seq->offset = 0;
seq->arr = malloc(seq->capacity * sizeof(seq->arr[0]));
return seq->arr == NULL ? -1 : 0;
}
static int seq_grow(seq *seq) { /* private implementation detail */
size_t new_capacity = seq->capacity + SEQ_INCREMENT;
void *p = realloc(seq->arr, new_capacity * sizeof(seq->arr[0]));
if (p == NULL) { /* realloc failed, seq unmodified */
return -1;
}
seq->arr = p;
seq->capacity = new_capacity;
return 0;
}
int seq_write(seq *seq, uint16_t value) {
assert(seq != NULL); /* catch null seq */
if ((seq->offset == seq->capacity) && seq_grow(seq) < 0) {
return -1; /* write failed */
}
assert(seq->arr != NULL); /* catch bad seq */
assert(seq->offset < seq->capacity); /* ensure seq really has room */
seq->arr[seq->offset++] = value;
return 0;
}
void seq_free(seq *seq) {
if (seq != NULL) {
free(seq->arr);
seq->arr = NULL;
}
}
You need to use realloc(), not malloc(), like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct {
int len;
int *arr;
} seq;
void write_seq(seq *q)
{
q->arr = realloc (q->arr, (q->len + 1) * sizeof(int));
q->arr[q->len] = q->len;
q->len++;
}
int main(void)
{
seq q;
q.len = 0;
q.arr = NULL;
for(int i = 0; i < 10; ++i)
write_seq(&q);
printf("length is %d\n", q.len);
for (int i = 0; i < q.len; i++) {
printf("%d\n", q.arr[i]);
}
free(q.arr);
return 0;
}
Output:
length is 10
0
1
2
3
4
5
6
7
8
9

Program is causing a segmentation fault in VI but works fine in emacs

I'm not sure why my program will not compile right on vi. it only prints the first occurrence of the function show(var) and then exits and lists a segmentation fault and core dumped, however, it compiled without any errors on emacs and displayed all the strings after being quicksorted.
The program is supposed to read in data from a text file that I have stored in the same directory, and quicksort it using one of the 2 compare functions (which don't have to be meaningful, they just need to be functional) and then prints it out to the screen.
Thanks in advance.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
void show(void *array[]){
int i = 0;
while(array[i]!=NULL){
printf("String %d : %s\n",i, array[i]);
i++;
}
printf("\n");
}
void *readData(void * lineArray[]){
static const char filename[] = "sampledata.txt";
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
int i ;
char line [ 128 ]; /* or other suitable maximum line size */
void *lineadrs ;
i = 0;
lineadrs = malloc(sizeof(void) * 1024);
while ( fgets ( lineadrs, sizeof line, file ) != NULL ) /* read a line */
{
lineArray[i] = lineadrs;
lineadrs = malloc(sizeof(void) * 1024);
i++;
}
fclose ( file );
}
else {
perror ( filename );
return 0;
}
return lineArray ;
}
void swap(void *v[], int i, int j)
{
void *temp;
temp = v[i];
v[i] = v[j];
v[j]=temp;
}
//normal compare
int cmp1 (void *first_arg, void *second_arg)
{
if ( *(char*)first_arg < *(char*)second_arg )
{
return -1;
}
if ( *(char*)first_arg == *(char*)second_arg )
{
return 0;
}
else {
return 1;
}
}
//reverse the compare
int cmp2 (void * a, void * b)
{
char *ia = (char *)a; // casting pointer types
char *ib = (char *)b;
return *ib - *ia;
//return ( *(int *)b + *(int *)a );
}
void QSort(void *v[],int left, int right, int (*compare)(void *first, void *second))
{
int i, last;
void swap (void *v[],int ,int);
if(left >= right){
return;
}
swap(v,left,(left+right)/2);
last=left;
for(i=left+1;i<=right; i++){
if((*compare)(v[i],v[left])<0){
swap(v,++last,i);
}
}
swap(v,left,last);
QSort(v,left,last-1,compare);
QSort(v,last+1,right,compare);
}
int main(){
void * var[6];
readData(var);
printf("Original String:\n");
show(var);
QSort(var,0,4,cmp1);
printf("After cmp 1 which compares alphabetically.\n");
show(var);
QSort(var,0,4,cmp2);
printf("After cmp 2 which compares reverse alphabetically.\n");
show(var);
return 0;
}
The list of things wrong in this code is almost too numerous to mention
the line array is fixed. it should be dynamic. reading more than 4 lines of text will invoke undefined behavior by exceeding your input array length
the comparators are wrong for string content.
the memory leaks are numerous.
The code below is, I believe, what you're trying to do. I sincerely hope you take the time to learn from it. There are still several things that should be done, but the difference is night and day already. And I should warn you I wrote this online and have given no test-time to it, but it should be correct. Since I have no example data from you, this is the extent of what I can do. I wish you the best of luck.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// read data from a named file one line at a time, storing each
// in a ever-expanding line array. The return result is the
// number of lines allocated. The resulting line array is passed
// as an output parameter
int readData(const char filename[], void ***results)
{
// default answer: no lines, zero-length
void **lines = NULL;
int i=0;
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
char line [ 128 ];
while ( fgets ( line, sizeof line, file ) != NULL )
{
// trim the newline from line buffer
size_t slen = strlen(line);
if (slen > 0 && line[slen-1] == '\n')
line[--slen] = 0;
// resize lines array
void **new_lines = realloc(lines, (i+1)*sizeof(*new_lines));
if (new_lines == NULL)
{
perror("Failed to realloc lines array.");
exit(EXIT_FAILURE);
}
// save new line entry, terminate with NULL;
lines = new_lines;
lines[i++] = strdup(line);
}
fclose ( file );
}
else
{
perror(filename);
exit(EXIT_FAILURE);
}
// setup output result and return value
*results = lines;
return i;
}
// display an array of a specified length
void show(void *array[], int len)
{
int i=0;
for (; i<len; ++i)
printf("String %d : %s\n", i, array[i]);
printf("\n");
}
//normal compare
int cmp1 (void *first_arg, void *second_arg)
{
return strcmp((const char*)first_arg, (const char*)second_arg);
}
//reverse the compare
int cmp2 (void *first_arg, void *second_arg)
{
return strcmp((const char*)second_arg, (const char*)first_arg);
}
// swap to void* by address
void swap(void **lhs, void **rhs)
{
void *tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
// the simplest quicksort I can fathom
void QSort(void *v[], int len, int (*compare)(void*, void*))
{
if (len < 2)
return;
// swap random element to last slot
swap(v+(rand() % len), v+(len-1));
// partition around the pivot value
int pvt=0,i;
for (i=0; i<len; ++i)
{
if (compare(v[i], v[len-1]) < 0)
swap(v+i, v+pvt++);
}
// swap pivot into place
swap(v+pvt, v+(len-1));
// recurse. note the pivot slot is skipped.
QSort(v, pvt++, compare);
QSort(v+pvt, len-pvt, compare);
}
int main()
{
static const char filename[] = "sampledata.txt";
srand((unsigned)time(NULL));
void **var = NULL;
int len = readData(filename, &var);
if (len > 0)
{
printf("Original String:\n");
show(var, len);
QSort(var, len, cmp1);
printf("After cmp 1 which compares alphabetically.\n");
show(var, len);
QSort(var, len, cmp2);
printf("After cmp 2 which compares reverse alphabetically.\n");
show(var, len);
// release lines when finished
while (len-- != 0)
free(var[len]);
free(var);
}
return 0;
}

invalid pointer from trying to use realloc for an array of structs in c

My program compiles but I am not working with pointers and realloc correctly. I have tried looking at other examples but I can't seem to translate it to my own program. The point of the program is to read in words from a file and increment the count if they appear more than once. Once the array of structs goes over my base (5), I want to realloc space, copy the array over and then add the next word.
Any help would be greatly appreciated!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BASE 5
#define MAX 50
typedef char *string;
struct wordCount
{
string word;
unsigned int count;
};
int main (void)
{
unsigned int i;
unsigned int incremented;
unsigned int j;
char temp [40];
struct wordCount wordArray[BASE];
struct wordCount *holder;
FILE *infile;
j = 0;
infile = fopen("input.txt","r");
while (fscanf(infile, "%s", temp) == 1) {
incremented = 0;
for (i = 0; i < j; i++){
if(strcmp(temp,wordArray[i].word) == 0){
wordArray[i].count++;
incremented++;
}
}
if (incremented == 0){
if (j<BASE){
wordArray[j].word = (char *)malloc((strlen(temp)+1) *
sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
} else {
holder = realloc(wordArray, sizeof(wordArray) +1);
*wordArray = *holder;
wordArray[j].word = (char *)malloc((strlen(temp)+1) * sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
}
}
}
fclose(infile);
/* bring in next file*/
/*delete du plicates */
/*sort*/
for (i = 0; i < j; i++) {
printf("%s ", wordArray[i].word);
printf("%d\n", wordArray[i].count);
}
/* and when done:*/
for(i = 0; i < j; i++){
free(wordArray[i].word);
}
return 0;
}
Here's the most obvious place you're going wrong:
holder = realloc(wordArray, sizeof(wordArray) +1);
Note this line from the man page of realloc():
void *realloc(void *ptr, size_t size);
...
Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc().
Your wordArray is a statically allocated array, it was not dynamically allocated via malloc() or friends.

Resources