I'm facing a problem that seems complicated to me so i'll be very grateful to who can help me.
I'm sort of trying to replicate the array of string behavior only with structures
so instead of having for example
char **mys={"hello","this is a long message"};
I'm trying to have an array with structures (each structure containing an array of variable length). I'm not quite sure if I exposed my problem very well so i hope the code is going to indicate what i'm trying to do:
my two structures :
typedef struct
{
int *iTab;
int iTail;
}strDynArr;
typedef struct
{
strDynArr **iTab;
int iTailStruct;
int iTail;
}strDynDynArr;
All the functions related to those two structures :
void initArray(strDynArr *ar)
{
ar->iTab=malloc(sizeof(int));
ar->iTail=1;
}
void pushArray(int iElement,strDynArr *ar)
{
ar->iTab[ar->iTail-1]=iElement;
realloc(ar->iTab,(ar->iTail++)*sizeof(int));
}
void freeDynArray(strDynArr *ar)
{
free(*ar->iTab);
}
void initDynDynArray(strDynDynArr *ar)
{
ar->iTab=malloc(sizeof(int));
ar->iTail=1;
ar->iTailStruct=1;
}
//the problem
void pushDynDynArray(strDynArr *daElement,strDynDynArr *ar)
{
//ar->iTab[ar->iTail-1]=daElement;
ar->iTailStruct+=(daElement->iTail+1);
realloc(ar->iTab,(ar->iTailStruct)*sizeof(int));
ar->iTab[ar->iTailStruct-(daElement->iTail+1)]=daElement;
//realloc(ar->iTab,(ar->iTail++)*sizeof(int));
}
void freeDynDynDynArray(strDynDynArr *ar)
{
free(*ar->iTab);
}
And the one function where i'm stuck is pushDynDynArray so far i've attempted two things either just using the pointer that points on à structure strDynArr but i don't know how space is managed at all so i tryed to allocate the size of the all the structures contained in the array of the structure strDynDynArr.
So what i would like to know is how to allocate space for my array (iTab) for a structure of type strDynDynArr.
In other words what is the way for me to store several structures containing for example :
//content of structure 1
int *iTab={2,3,4};
int iTail=3;
//content of structure 2
int *iTab={5,8,9,10,54,8,2};
int iTail=7;
All help is welcome and thanks à lot for it !
For simplicity, lets call each array of "strings" a table (of arrays), and each "string" an array of items. In your case, the item type seems to be int:
typedef int item;
typedef struct {
size_t size; /* Number of items allocated for */
size_t used; /* Number of items in item[] */
item *item;
} array;
typedef struct {
size_t size; /* Number of array (pointers) allocated for */
size_t used; /* Number of arrays in array[] */
array *array;
} table;
It is common to define initializer macros and functions for such types:
#define ARRAY_INIT { 0, 0, NULL }
#define TABLE_INIT { 0, 0, NULL }
static inline void array_init(array *ref)
{
if (!ref) {
fprintf(stderr, "array_init(): NULL array!\n");
exit(EXIT_FAILURE);
}
ref->size = 0;
ref->used = 0;
ref->item = NULL;
}
static inline void table_init(table *ref)
{
if (!ref) {
fprintf(stderr, "table_init(): NULL table!\n");
exit(EXIT_FAILURE);
}
ref->size = 0;
ref->used = 0;
ref->array = NULL;
}
Also, free functions are obviously useful:
static inline void array_free(array *ref)
{
if (!ref) {
fprintf(stderr, "array_free(): NULL array!\n");
exit(EXIT_FAILURE);
}
free(ref->item); /* Note: free(NULL) is safe; it does nothing. */
ref->size = 0;
ref->used = 0;
ref->item = NULL;
}
static inline void table_free(table *ref)
{
size_t i;
if (!ref) {
fprintf(stderr, "table_free(): NULL table!\n");
exit(EXIT_FAILURE);
}
i = ref->size;
while (i-->0)
array_free(ref->array + i); /* array_free(&(ref->array[i])); */
free(ref->array);
ref->size = 0;
ref->used = 0;
ref->array = NULL;
}
When freeing a table, we want to free all (possible) arrays individually, then the memory used by the pointers. Note that one could assume that only used arrays are in use; however, I wanted the above to be thorough, and free all size arrays allocated for.
Both the init and free functions above take a pointer to an array or table. They should never be NULL. (That is, the item or array member in the structure may well be NULL; it's just that you should never call e.g. array_init(NULL); or table_free(NULL).)
Let us implement a function to push and pop individual ints from a solitary array (that may or may not be part of a table):
void array_push(array *ref, const item value)
{
if (!ref) {
fprintf(stderr, "array_push(): NULL array!\n");
exit(EXIT_FAILURE);
}
/* Need to grow the array? */
if (ref->used >= ref->size) {
size_t size; /* Minimum is ref->used + 1 */
void *temp;
/* Dynamic growth policy. Pulled from a hat. */
if (ref->used < 64)
size = 64; /* Minimum 64 elements */
else
if (ref->used < 1048576)
size = (3*ref->used) / 2; /* Grow by 50% up to 1048576 */
else
size = (ref->used | 1048575) + 1048577; /* Grow to next multiple of 1048576 */
temp = realloc(ref->item, size * sizeof ref->item[0]);
if (!temp)
return -1; /* Out of memory */
ref->item = temp;
ref->size = size;
}
/* Append value to array. */
ref->item[ref->used++] = value;
}
and a corresponding pop operation:
item array_pop(array *ref)
{
if (!ref) {
fprintf(stderr, "array_pop(): NULL array!\n");
exit(EXIT_FAILURE);
}
if (ref->used < 1) {
fprintf(stderr, "array_pop(): Array is already empty; nothing to pop.\n");
exit(EXIT_FAILURE);
}
/* Since ref->used is the *number* of items in the array,
we want to decrement it first, to get the last item in array. */
return ref->item[--ref->used];
}
In your program, you can use an array for example thus:
array scores = ARRAY_INIT;
array_push(&scores, 5);
array_push(&scores, 2);
printf("%d\n", array_pop(&scores)); /* Will print 2 */
printf("%d\n", array_pop(&scores)); /* Will print 5 */
array_free(&scores);
The line array scores = ARRAY_INIT; both declares and initializes the array (to an empty array). You could also equivalently use array scores; array_init(&scores);.
The resize or growth policy in array_push() is roughly along the lines I'd personally recommend, although the actual numerical values are pulled from a hat, and you may wish to adjust them. The idea is that there is a minimum number of items allocated for (say, 64). For bigger arrays, we increase the size fractionally, so that when the array is large, the size increase is also large. Many people use 100% increase in size (doubling the size, i.e. size = 2 * ref->used;), but I like 50% increase better (multiplying the size by one and one half, size = (3 * ref->used) / 2;). For huge arrays, we don't want to waste potentially lots of memory, so we allocate in fixed-size (but huge) chunks instead. (There is no need or real benefit to align the huge size to some multiple like I did; I just like it that way. And the more complicated code ensures you need to understand it and edit it, rather than submitting it raw as yours; otherwise, you'll instructor will catch you cheating.)
Pushing a single value to the last array in the table is now simple to implement:
void table_push_value(table *ref, const item value)
{
size_t i;
if (!ref) {
fprintf(stderr, "table_push_value(): NULL table!\n");
exit(EXIT_FAILURE);
}
/* Ensure there is at least one array. */
if (!ref->size < 1) {
/* Empty table: ref->size = 0, and ref->used must be 0 too. */
const size_t size = 1; /* Allocate for exactly one array. */
void *temp;
temp = realloc(ref->array, size * sizeof ref->array[0]);
if (!temp) {
fprintf(stderr, "table_push_value(): Out of memory.\n");
exit(EXIT_FAILURE);
}
ref->size = size;
ref->array = temp;
for (i = 0; i < size; i++)
array_init(ref->array + i); /* array_init(&(ref->array[i])); */
}
if (ref->used > 0)
i = ref->used - 1; /* Last array in table */
else
i = 0; /* Table is empty, so use first array */
array_push(ref->array + i, value); /* array_push(&(ref->array[i])); */
}
This time, you need special logic for an empty table, for both allocating the description for an array, as well as where to push.
Pop is simpler:
item table_pop_value(table *ref)
{
size_t i;
if (!ref) {
fprintf(stderr, "table_pop_value(): NULL table!\n");
exit(EXIT_FAILURE);
}
i = ref->used;
/* Find the last array with items in it, and pop from it. */
while (i-- > 0)
if (ref->array[i].used > 0) {
return array_pop(ref->array + i); /* array_pop(&(ref->array[i])); */
fprintf(stderr, "table_pop_value(): Empty table, no items to pop!\n");
exit(EXIT_FAILURE);
}
To push an entire array to a table (pushing the array of items in it, not making a copy of the items) is pretty simple, but we do need to implement a reallocation/growth policy again:
void table_push_array(table *ref, array *one)
{
if (!ref) {
fprintf(stderr, "table_push_array(): NULL table!\n");
exit(EXIT_FAILURE);
}
if (!one) {
fprintf(stderr, "table_push_array(): NULL array!\n");
exit(EXIT_FAILURE);
}
if (ref->used >= ref->size) {
size_t size, i;
void *temp;
if (ref->used < 1)
size = 1; /* Minimum size is 1 */
else
size = (ref->used | 7) + 9; /* Next multiple of 8 */
temp = realloc(ref->array, size * sizeof ref->array[0]);
if (!temp) {
fprintf(stderr, "table_push_array(): Out of memory.\n");
exit(EXIT_FAILURE);
}
ref->array = temp;
for (i = ref->size; i < size; i++)
array_init(ref->array + i); /* array_init(&(ref->array[i])); */
ref->size = size;
}
ref->array[ref->used] = *one; /* "shallow copy" */
ref->used++;
}
The corresponding pop operation should be pretty obvious by now:
array *table_pop_array(table *ref)
{
array retval = ARRAY_INIT;
if (!ref) {
fprintf(stderr, "table_pop_array(): NULL table!\n");
exit(EXIT_FAILURE);
}
if (ref->used < 1) {
fprintf(stderr, "table_pop_array(): Table is empty, no arrays to pop!\n");
exit(EXIT_FAILURE);
}
/* Decrement the used count, so it refers to the last array in the table. */
ref->used--;
/* Shallow copy the array. */
retval = ref->array[ref->used];
/* Init, but do not free, the array in the table. */
array_init(ref->array + ref->used); /* array_init(&(ref->array[ref->used)); */
/* Return the array. */
return retval;
}
There is a "trick" in table_pop_array() above, that you should understand. While we cannot return pointers to local variables, we can return structures. In the above case, the structure describes the array, and the pointer in it does not refer to a local variable, but to a dynamically allocated array of items. Structure types can be assigned just as normal scalar types (like int or double); it is basically the same as if you assigned each member separately.
Overall, you should notice I have not used a single malloc() call. This is because realloc(NULL, size) is equivalent to malloc(size), and simply initializing unused pointers to NULL makes everything simpler.
When a table is grown (reallocated), we do need to initialize all the new arrays, because of the above realloc() use pattern.
The above approach does not preclude direct access to specific arrays in the table, or specific items in an array. If you intend to implement such functions, two helper functions similar to
void table_need_arrays(table *ref, const size_t size);
void array_need_items(array *ref, const size_t size);
that ensure that the table has room for at least size arrays, and an array has room for at least size items. They are also useful when pushing multiple items or arrays consecutively, as then one can do e.g. table_need_arrays(&mytable, mytable.used + 10); to ensure there is room for additional 10 arrays in the table.
All throughout the functions above, you can see notation name_of_array + index, and a comment with corresponding &(name_of_array[index]). This is because the two notations are equivalent: pointer to the index'th element in name_of_array.
I didn't bother to compile-check the above code, so there might be typos hidden in there. (This too is intentional, because I want you to understand the code, and not just copy it and use it as your own without understanding any of the details.) However, the logic is sound. So, if you find a typo or issue, let me know in a comment, and I shall fix.
Related
This is my very first post on stackoverflow. I am a CS student learning C, and I am having some issues with the problem I'm working on. Additionally, I should mention that I know very little, so if anything I put here comes off as foolish or ignorant, it is absolutely not my intention
I am aware that there are other posts similar to this one, however so far I feel that I have tried making a lot of amendments that all end with the same result.
I am given a text file in which each line contains studentName(tab)gpa. The total size of the file is unknown, this I must use dynamic memory allocation.
Example of text file format
Jordan 4.0
Bhupesh 2.51
General steps for program
Many details will be left out to save myself from embarrassment, however I will give a high-level overview of the process I am struggling with:
1.) Create dynamic memory array to hold struct for each line
2.) Start looping through file
3.) check the current size of the array to see if reallocation is necessary
4.) Create dynamic array to hold name
5.) Place name and gpa into struct
6.) rinse & repeat
Finally, one last thing. The error occurs when my initial allocated memory limit is reached and the program attempts to reallocate more memory from the heap.
Screenshot of error being thrown in clion debugger
My code is shown below:
#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2
struct Student {
float gpa;
char * name;
};
// read the file, pack contents into struct array
struct Student * readFileContents(char *filename, int *rowCounter) {
// setup for loop
int maxDataSize = ROW_COUNT;
float currentStudentGpa = 0;
char studentNameBuffer[BUFFER_SIZE];
// initial structArray pre-loop
struct Student * structArray = calloc(maxDataSize, sizeof(*structArray));
FILE *pFile = fopen(filename, "r");
validateOpenFile(pFile);
// loop through, get contents, of eaach line, place them in struct
while (fscanf(pFile, "%s\t%f", studentNameBuffer, ¤tStudentGpa) > 0) {
structArray = checkArraySizeIncrease(*rowCounter, &maxDataSize, &structArray);
structArray->name = trimStringFromBuffer(studentNameBuffer);
structArray->gpa = currentStudentGpa;
(*rowCounter)++, structArray++;
}
fclose(pFile);
return structArray;
}
// resize array if needed
struct Student * checkArraySizeIncrease(int rowCount, int * maxDataSize, struct Student ** structArray) {
if (rowCount == *maxDataSize) {
*maxDataSize += ROW_COUNT;
**// line below is where the error occurs**
struct Student * newStructArray = realloc(*structArray, *maxDataSize * sizeof(*newStructArray));
validateMalloc(newStructArray);
return newStructArray;
}
return *structArray;
}
// resize string from initial data buffer
char *trimStringFromBuffer(char *dataBuffer) {
char *string = (char *) calloc(strlen(dataBuffer), sizeof(char));
validateMalloc(string);
strcpy(string, dataBuffer);
return string;
}
Once again, I apologize if similar questions have been asked, but please know I have tried most of the recommendations that I have found on stack overflow with no success (of which I'm well aware is the result of my poor programming skill level in C).
I will now promptly prepare myself for my obligatory "first post on stackoverflow" roasting. Cheers!
You are reusing structArray as both the base of the array and a pointer to the current element. This won't work. We need two variables.
There are a number of "loose" variables related to the dynamic array. It's cleaner to define a struct (e.g. dynarr_t below) to contain them and pass just the struct pointer around.
When you're duplicating the string, you must allocate strlen + 1 [not just strlen]. But, the entire function does what strdup already does.
I tried to save as much as possible, but I've had to refactor the code a fair bit to incorporate all the necessary changes.
By passing sizeof(*structArray) to the arrnew function, this allows the struct to be used for arbitrary size array elements.
Anyway, here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2
struct Student {
float gpa;
char *name;
};
// general dynamic array control
typedef struct {
void *base; // base address
size_t size; // bytes in array element
size_t count; // current number of used entries
size_t max; // maximum number of entries
size_t grow; // number of entries to grow
} dynarr_t;
// arrfind -- return pointer to array element
void *
arrfind(dynarr_t *arr,size_t idx)
{
void *ptr;
ptr = arr->base;
idx *= arr->size;
ptr += idx;
return ptr;
}
// arrnew -- create new array control
dynarr_t *
arrnew(size_t siz,size_t grow)
// siz -- sizeof of array element
// grow -- number of elements to grow
{
dynarr_t *arr;
arr = calloc(1,sizeof(*arr));
if (arr == NULL)
sysfault("arrnew: calloc fail -- %s\n",strerror(errno));
arr->size = siz;
arr->grow = grow;
return arr;
}
// arrgrow -- grow array [if necessary]
// RETURNS: pointer to element to fill
void *
arrgrow(dynarr_t *arr)
{
void *ptr;
// grow array if necessary
// NOTE: use of a separate "max" from "count" reduces the number of realloc
// calls
if (arr->count >= arr->max) {
arr->max += arr->grow;
arr->base = realloc(arr->base,arr->size * arr->max);
if (arr->base == NULL)
sysfault("arrgrow: realloc failure -- %s\n",strerror(errno));
}
// point to current element
ptr = arrfind(arr,arr->count);
// advance count of elements
++arr->count;
return ptr;
}
// arrtrim -- trim array to actual number of elements used
void
arrtrim(dynarr_t *arr)
{
arr->base = realloc(arr->base,arr->size * arr->count);
if (arr->base == NULL)
sysfault("arrtrim: realloc failure -- %s\n",strerror(errno));
arr->max = arr->count;
}
void
validateMalloc(void *ptr)
{
if (ptr == NULL) {
perror("validateMalloc");
exit(1);
}
}
void
validateOpenFile(FILE *ptr)
{
if (ptr == NULL) {
perror("validateOpenFile");
exit(1);
}
}
// resize string from initial data buffer
char *
trimStringFromBuffer(char *dataBuffer)
{
#if 0
#if 0
char *string = calloc(1,strlen(dataBuffer));
#else
char *string = calloc(1,strlen(dataBuffer) + 1);
#endif
validateMalloc(string);
strcpy(string, dataBuffer);
#else
char *string = strdup(dataBuffer);
validateMalloc(string);
#endif
return string;
}
// read the file, pack contents into struct array
dynarr_t *
readFileContents(char *filename)
{
dynarr_t *arr;
// setup for loop
float currentStudentGpa = 0;
char studentNameBuffer[BUFFER_SIZE];
struct Student *structArray;
arr = arrnew(sizeof(*structArray),10);
FILE *pFile = fopen(filename, "r");
validateOpenFile(pFile);
// loop through, get contents, of eaach line, place them in struct
while (fscanf(pFile, "%s\t%f", studentNameBuffer, ¤tStudentGpa) > 0) {
structArray = arrgrow(arr);
structArray->name = trimStringFromBuffer(studentNameBuffer);
structArray->gpa = currentStudentGpa;
}
fclose(pFile);
arrtrim(arr);
return arr;
}
I think your issue is with the calculation of the size of the realloc. Rather than using sizeof(*newStructArray), shouldn't you really be using the size of your pointer type? I would have written this as realloc(*structArray, *maxDataSize * sizeof(struct Student *))
There's a lot of other stuff in here I would never do - passing all those variables in to checkArraySizeIncrease as pointers is generally a bad idea because it can mask the fact that things are getting changed, for instance.
There is an issue in allocation of the buffer for string
char *string = (char *) calloc(strlen(dataBuffer), sizeof(char));
it should be:
char *string = (char *) calloc(1 + strlen(dataBuffer), sizeof(char));
as C-strings require extra 0-byte at the end.
Without it, the following operation:
strcpy(string, dataBuffer);
may damage data after the buffer, likely messing malloc() metadata.
As part of a personal project, I'm trying to create a dynamic array of 2-tuples that show a) the line in a program and b) the number of bytecode tokens associated with that line. I've implemented this as a struct of arrays:
typedef struct{
int count; // Number of elements
int capacity; // total capacity of arraylist
int* lines;
int* lineCount;
}
this is based on the example from the codebase, as such:
int count;
int capacity;
uint8_t* bytes;
My problem comes from re-allocation - I have several helper functions/macros for growing and re-allocating the array lists memory - here particularly the macro GROW_ARRAY and reallocate(), as described below. When I try and re-allocate lines, it works fine, but I get a segmentation fault and realloc(): invalid old size several times when I attempt to reallocate lineCount after it
I'm using the code base from Bob Nystrom's Crafting Interpreters, especially this first part here https://craftinginterpreters.com/chunks-of-bytecode.html#challenges. Most of the code comes from there, albeit tinkered with some of having added
Mostly, I've added a lot of checks and been running this with all the debug features in gcc I can find. Notably, realloc(): invalid old size has stop appearing as I've tinkered with the code some.
EDIT: Added main function that should reproduce behavior
int main() {
LineArray lines;
// Initialize to 0 / NULL
initLineArray(&lines);
updateLineArray(&lines, 0, 1);
}
// the structure I'm using
typedef struct {
int capacity;
int count;
int* lines;
int* lineCount;
} LineArray;
/* Note LineArray has already been initialized earlier with
capacity=0;
count=0;
lines=NULL;
lineCount=NULL;
*/
void updateLineArray(LineArray* array, int line, int count) {
// IF line in `lines` -- update it
int index = containsLine(array, line);
if (index != -1) { // IF Index is not Error Code
// I think I fixed a bug here?
array->lineCount[index] += count;
return;
}
//ELSE -- add line to end (naturally appends); then increment
else {
//Check to see if array would be overgrown
if (array->capacity < array->count + 1) {
//IF yes, regrow array
int old_capacity = array->capacity;
array->capacity = GROW_CAPACITY(old_capacity);
// Reallocate arrays.
array->lines = GROW_ARRAY(array->lines, int, old_capacity,
array->capacity);
array->lineCount = GROW_ARRAY(array->lineCount, int, old_capacity,
array->capacity);
}
// Properly update the lines
array->lines[array->count] = line;
array->lineCount[array->count] = count;
array->count++;
return;
}
}
//The memory management functions/macros I'm using here
#define GROW_CAPACITY(capacity) \
((capacity) < 8 ? 8 : (capacity) * 2)
#define GROW_ARRAY(previous, type, oldCount, count) \
(type*) reallocate(previous, sizeof(type) * (oldCount), \
sizeof(type) * (count))
void* reallocate(void* previous, size_t oldSize, size_t newSize) {
// If size is null, erase it and get null_pointer
if (newSize == 0) {
free(previous);
return NULL;
}
// reallocate the data into a new size
// is Oldsize is zero :: malloc(data, newSize)
return realloc(previous, newSize);
}
Hello i'implementing a smart vector in c, and i'm having problems with the reallocation of the buffer.
this is the struct that contains the array and its infos:
struct _vector
{
item* vec;
size_t elements;
size_t size;
};
item is just a typedef that in this case happens to be int.
I made several function to manage the array, but the one that should resize it, gives me problems.
(Vector is also a typedef for struct _vector* by the way)
This is the function:
void insertVector(const Vector vec,const int pos,const item a)
{
if(vec->elements==vec->size)
{
item* temp=realloc(vec->vec,(vec->size*2)*sizeof(item));
if(temp==NULL)
{
puts("Error: space unavailable");
return;
}
//vec->vec=realloc(vec->vec,(vec->size*2)*sizeof(item));
vec->vec=temp;
vec->size*=2;
}
int size=vec->elements;
if(pos>=0&&pos<=size)
{
for(int i=size;i>pos;i--)
{
vec->vec[i]=vec->vec[i-1];
}
vec->vec[pos]=a;
vec->elements+=1;
printf("size is %lu\nelements are %lu\n",vec->size,vec->elements);
}
}
I just shift the contents to make space for the new element, and it works fine, the problem is when the array is reallocated.
when the number of valid elements is equal to the actual size of the array,
i do a realloc to double the actual size.
As soon as that if activates though the realloc makes the program crash with this error:incorrect checksum for freed object.
The problem is in the if, because it only crashes when the size and elements are equal, if i comment out that section, everything works
I don't know what could it be.
EDIT:
The functions that i used to create and the initialise the instance i'm working with are:
Vector newVector(void)
{
Vector new=malloc(sizeof(*new));
new->vec=NULL;
new->elements=0;
new->size=0;
return new;
}
and
void initVector(const Vector vec,const size_t size)
{
vec->vec=calloc(size,sizeof(item));
vec->elements=size;
vec->size=size*2;
}
Based of your comment
I created a new vector setting to zero every field, then i used this function:
void initVector(const Vector vec,const size_t size)
{
vec->vec=calloc(size,sizeof(item));
vec->elements=size;
vec->size=size*2;
}
I think you are treating the size and the number of elements incorrectly. The
initVector function just allocates memory for the vec->vec array, so
vec->elements should be 0, not size. And vec->size should be size, not
size*2. So the correct function should be
// remove the const, you are modifying the data vec is pointing to
int initVector(Vector vec, size_t size)
{
if(vec == NULL)
return 0;
vec->vec = calloc(size, sizeof *vec->vec);
if(vec->vec == NULL)
return 0;
vec->elements = 0;
vec->size = size;
return 1;
}
Now the insertVector would only allocate new space, when all allocated spaces
are used.
And I suggest you use memmove to copy the memory:
// again, remove the const here
int insertVector(Vector vec, const size_t pos, const item a)
{
if(vec == NULL)
return 0;
if(vec->elements==vec->size)
{
item* temp=realloc(vec->vec,(vec->size*2)*sizeof *temp);
if(temp==NULL)
{
fprintf(stderr, "Error: space unavailable\n");
return 0;
}
vec->vec=temp;
vec->size*=2;
}
// I use vec->elements as upper limit,
// otherwise you could have "holes" in the array and
// you wouldn't realize it.
if(pos < 0 || pos > vec->elements)
{
fprintf(stderr, "invalid position\n");
return 0;
}
memmove(vec->vec + pos + 1, vec->vec + pos, (vec->elements - pos) * sizeof *vec->vec);
vec->vec[pos] = a;
vec->elements += 1;
printf("size is %lu\nelements are %lu\n",vec->size,vec->elements);
return 1;
}
In your initVector function, you set the size incorrectly, to two times what you allocated with calloc. This memory then gets overwritten as you are adding new elements and this is the reason the free fails when you finally invoke realloc. Change initVector to:
void initVector(const Vector vec,const size_t size)
{
vec->vec=calloc(size,sizeof(item));
vec->elements=size;
vec->size=size;
}
I want to create an array of structs on the heap from another data structure. Say there are N total elements to traverse, and (N-x) pointers (computed_elements) will be added to the array.
My naive strategy for this is to create an array (temp_array) size N on the stack and traverse the data structure, keeping track of how many elements need to be added to the array, and adding them to temp_array when I encounter them. Once I've finished, I malloc(computed_elements) and populate this array with the temp_array.
This is suboptimal because the second loop is unnecessary. However, I am weighing this against the tradeoff of constantly reallocating memory every iteration. Some rough code to clarify:
void *temp_array[N];
int count = 0;
for (int i = 0; i < N; i++) {
if (check(arr[i])) {
temp_array[count] = arr[i];
count++;
}
}
void *results = malloc(count * sizeof(MyStruct));
for (int i = 0; i < count; i++) {
results[i] = temp_array[i];
}
return results;
Thoughts would be appreciated.
One common strategy is to try to estimate the number of elements you're going to need (not a close estimate, more of a "On the order of..." type estimate). Malloc that amount of memory, and when you get "close" to that limit ("close" also being up for interpretation), realloc some more. Personally, I typically double the array when I get close to filling it.
-EDIT-
Here is the "ten minute version". (I've ensured that it builds and doesn't segfault)
Obviously I've omitted things like checking for the success of malloc/realloc, zeroing memory, etc...
#include <stdlib.h>
#include <stdbool.h>
#include <string.h> /* for the "malloc only version" (see below) */
/* Assume 500 elements estimated*/
#define ESTIMATED_NUMBER_OF_RECORDS 500
/* "MAX" number of elements that the original question seems to be bound by */
#define N 10000
/* Included only to allow for test compilation */
typedef struct
{
int foo;
int bar;
} MyStruct;
/* Included only to allow for test compilation */
MyStruct arr[N] = { 0 };
/* Included only to allow for test compilation */
bool check(MyStruct valueToCheck)
{
bool baz = true;
/* ... */
return baz;
}
int main (int argc, char** argv)
{
int idx = 0;
int actualRecordCount = 0;
int allocatedSize = 0;
MyStruct *tempPointer = NULL;
MyStruct *results = malloc(ESTIMATED_NUMBER_OF_RECORDS * sizeof(MyStruct));
allocatedSize = ESTIMATED_NUMBER_OF_RECORDS;
for (idx = 0; idx < N; idx++)
{
/* Ensure that we're not about to walk off the current array */
if (actualRecordCount == (allocatedSize))
{
allocatedSize *= 2;
/* "malloc only version"
* If you want to avoid realloc and just malloc everything...
*/
/*
tempPointer = malloc(allocatedSize);
memcpy(tempPointer, results, allocatedSize);
free(results);
results = tempPointer;
*/
/* Using realloc... */
tempPointer = realloc(results, allocatedSize);
results = tempPointer;
}
/* Check validity or original array element */
if (check(arr[idx]))
{
results[actualRecordCount] = arr[idx];
actualRecordCount++;
}
}
if (results != NULL)
{
free(results);
}
return 0;
}
One possibility is malloc for the size N, then run your loop, then realloc for size N-x. Memory fragmentation may result for small x.
The best re-usable code very often is scalable. Unless obligated to use small sizes, assume code will grow in subsequent applications and need to be reasonable efficient for large N. You do want to re-use good code.
realloc() an array by a factor of 4 or so as the need arises. Arrays may also shrink - no need to have a bloated array laying around. I've used grow by factor of 4 at intervals 1,4,16,64... and shrink intervals at 2,8,32,128... By having grow/shrink intervals apart from each other, it avoid lots of actively should N waver around an interval.
Even in small ways, like using size_t vs. int. Sure, with sizes like 1000, it makes no difference, but with code re-use, an application may push the limit: size_t is better for array indexes.
void *temp_array[N];
for (int i = 0; i < N; i++) {
void *temp_array[N];
for (size_t i = 0; i < N; i++) {
gcc 4.5.1 c89
I have written this source code for my better understanding of malloc and calloc.
I understand, but just have a few questions.
dev = malloc(number * sizeof *devices);
is equal to this calloc. I am not concerned about clearing the memory.
dev = calloc(number, sizeof *devices);
What is that exactly, compared to doing this 5 times in a while loop:
dev = malloc(sizeof *devices);
I guess the first one and the second is creating a pointer to 5 struct device. And the third is creating a single pointer to a struct device?
My program illustrates this 3 different methods compiled and ran with valgrind --leak-check=full.
Many thanks for any advice.
#include <stdio.h>
#include <stdlib.h>
struct Devices {
#define MAX_NAME_SIZE 80
size_t id;
char name[MAX_NAME_SIZE];
};
struct Devices* create_device(struct Devices *dev);
void destroy_device(struct Devices *dev);
int main(void)
{
size_t num_devices = 5;
size_t i = 0;
struct Devices *device = NULL;
struct Devices *dev_malloc = NULL;
struct Devices *dev_calloc = NULL;
for(i = 0; i < num_devices; i++) {
device = create_device(device);
/* Assign values */
device->id = i + 1;
sprintf(device->name, "Device%zu", device->id);
/* Print values */
printf("ID ----- [ %zu ]\n", device->id);
printf("Name --- [ %s ]\n", device->name);
/* Test free */
destroy_device(device);
}
printf("\n");
dev_malloc = malloc(num_devices * sizeof *dev_malloc);
for(i = 0; i < num_devices; i++) {
/* Assign values */
dev_malloc->id = i + 1;
sprintf(dev_malloc->name, "dev_malloc%zu", dev_malloc->id);
/* Print values */
printf("ID ----- [ %zu ]\n", dev_malloc->id);
printf("Name --- [ %s ]\n", dev_malloc->name);
}
/* Test free */
destroy_device(dev_malloc);
printf("\n");
dev_calloc = calloc(num_devices, sizeof *dev_calloc);
for(i = 0; i < num_devices; i++) {
/* Assign values */
dev_calloc->id = i + 1;
sprintf(dev_calloc->name, "dev_calloc%zu", dev_calloc->id);
/* Print values */
printf("ID ----- [ %zu ]\n", dev_calloc->id);
printf("Name --- [ %s ]\n", dev_calloc->name);
}
/* Test free */
destroy_device(dev_calloc);
return 0;
}
struct Devices* create_device(struct Devices *dev)
{
/* Not checking for memory error - just simple test */
return dev = malloc(sizeof *dev);
}
void destroy_device(struct Devices *dev)
{
if(dev != NULL) {
free(dev);
}
}
calloc(a,b) and malloc(a*b) are equivalent except for the possibility of arithmetic overflow or type issues, and the fact that calloc ensures the memory is zero-byte-filled. Either allocated memory that can be used for an array of a elements each of size b (or vice versa). On the other hand, calling malloc(b) a times will results in a individual objects of size b which can be freed independently and which are not in an array (though you could store their addresses in an array of pointers).
Hope this helps.
malloc(n) allocates n bytes plus padding and overhead.
calloc(m, n) allocates m*n bytes plus padding and overhead, and then zero's the memory.
That's it.
edited for clarity
I guess the first one and the second is creating a pointer to 5 struct device. And the third is creating a single pointer to a struct device?
The first one malloc(number * sizeof(*devices)) would allocate enough memory to store number of Devices. As others have mentioned, you can treat this block like an array of Device. The pointer you get back will point to the beginning of the block.
int number = 5;
Device *ptr = malloc(number * sizeof(*ptr));
/* stuff */
free(ptr);
The second one that uses calloc does the same thing, while also initializing the memory to 0. Again, you can use treat the block like an array of Device.
int number = 5;
Device *ptr = calloc(number, sizeof(*ptr));
/* stuff */
free(ptr);
The third one, looping 5 times, would result in 5 different pointers to 5 different blocks large enough to store one Device each. This also means each of the 5 pointers has to be free'ed individually.
Device *ptrs[5];
for(int i = 0; i < 5; ++i)
{
ptrs[i] = malloc(sizeof(*ptrs[i]));
}
/* stuff */
for(int i = 0; i < 5; ++i)
{
free(ptrs[i]);
}
The first two create an array of 5 devices in contiguous memory. The last malloc, done five times, will create 5 individual devices which are not guaranteed to be in contiguous memory.
All three loops in your program use only one struct Devices object at a time. The later ones allocate extra memory as though they are going to use multiple objects, but then keep overwriting the beginning of that memory. If you tried to use the object with ID 1 after setting up the object with ID 2, you would find there is no longer any object with ID 1.
Instead, you could do something like this to treat the allocated memory as an array of structs:
dev_malloc = malloc(num_devices * sizeof *dev_malloc);
for (i=0; i<num_devices; i++) {
/* Assign values */
dev_malloc[i].id = i + 1;
sprintf(dev_malloc[i].name, "dev_malloc%zu", dev_malloc[i].id);
/* Print values */
printf("ID ----- [ %zu ]\n", dev_malloc[i].id);
printf("Name --- [ %s ]\n", dev_malloc[i].name);
}
free(dev_malloc);
Look at an implementation of calloc to see the differences. It's probably something like this:
// SIZE_MAX is defined in stdint.h from C99
void *calloc( size_t N, size_t S)
{
void *ret;
size_t NBYTES;
// check for overflow of size_t type
if (N > SIZE_MAX / S) return NULL;
NBYTES = N * S;
ret = malloc( NBYTES);
if (ret != NULL)
{
memset( ret, 0, NBYTES);
}
return ret;
}
As you point out, calloc zeroes out the memory is allocates, while malloc doesn't.
Your examples 1 & 2 each allocate a single contiguous block of five structs (and returns a pointer to that block), whereas example 3 allocates five separate blocks of one struct each (and gives you five pointers unrelated to one another.)