Change array size inside a struct - c

I'm trying to simulate a stack (pushing and poping values into the top of the stack) using structs and dynamic memory allocation in C and I have this struct:
...
#define max 5
typedef struct stack
{
int stk[max];
int top;
}STACK;
...
I successfully simulated the stack, but when it reaches its maximum size (stack is full) I want to change the value of max in order to keep adding (push) values to the top of the stack. In other words, i just want to reallocate the max value in the stk field of the struct, if that is possible.
Any suggestion is appreciated.

Using int stk[max]; is not dynamic memory allocation.
You need to have pointer int * stk; and initialize it with malloc. Then realloc when more memory is needed. And when stack is no longer needed, release it with free.

As #user694733 as pointed out you must use dynamic memory. An other example can be:
typedef struct stack
{
int top;
int max;
int stk[];
}STACK;
STACK *init_stack(int m){
STACK *st = (STACK *)malloc(sizeof(STACK)+m*sizeof(int));
st->top = 0;
st->max = m;
return st;
}
STACK *resize_stack(STACK *st, int m){
if (m<=st->max){
return st; /* Take sure do not kill old values */
}
STACK *st = (STACK *)realloc(sizeof(STACK)+m*sizeof(int));
st->max = m;
return st;
}
Now you can use that function in your program like:
void main(void){
STACK *st = init_stack(5);
.... do something bu you need more room....
st = resize_stack(st,100);
..... Now is small again .....
st = resize_stack(st,5);
}
Take care that every realloc call have a linear cost and so you cannot use it to add just a constant number of elements: better use a geometric expansion. Take a look to http://en.wikipedia.org/wiki/Dynamic_array as a start point for dynamic array.

Try it like this:
typedef struct stack
{
int *stk;
int top;
}
signed int array_resize(stack *s, size_t size)
{
if(!s) return -1;
s->stk = realloc(s->stk, size * sizeof(int));
return 0;
}
This reallocates the space for the array of integers. I don't know how else to make this work.

Related

How to avoid valgrind (or other memcheck tools) misreporting when I initialize a struct which contain a dynamic array?

I want to initialize a struct which contains a dynamic array, I wrote all this stuff in a function. And there is another function for cleaning this struct, theoretically, there will be no memory leaks. However, when I run the program with valgrind, it report that there was memory leaks when at the entry or init function.
Firstly, I wrote this init function with malloc to allocate memory for this struct. It report memory leak.
Then, I change malloc to realloc(NULL, ...) to avoid this misreport but I failed.
I don't know what the standard way in C is to implement this function.
#include <stdlib.h>
typedef enum
{
RUN_SUCCESS,
/*Failure*/
RUN_FAILURE
} RunStat;
typedef struct
{
char *elements;
size_t top;
size_t size;
} Stack;
RunStat init_stack(Stack *stack)
{
stack->elements = (char *)realloc(NULL, 100 * sizeof(char));
stack->size = 100;
stack->top = 0;
return RUN_SUCCESS;
}
RunStat free_stack(Stack *stack)
{
free(stack->elements);
stack->elements = NULL;
stack->size = 0;
stack->top = 0;
return RUN_SUCCESS;
}
int main ()
{
Stack stack;
init_stack(&stack);
free_stack(&stack);
return EXIT_SUCCESS;
}
Every memory here is under my control, I want to make this struct initialized without any memory leak warning. And I want to know the standard way to do that.

how can i solve this when i try to return a 2d struct from a function

this is how i declare this struct
typedef struct cache{
int vaild;
char* tag;
char* data;
}cache;
this is part of my main which called this function
struct cache **cacheA = createCache(Setnum,(int)pow(2,blocksize),cachesize);
struct cache **cacheB = createCache(Setnum,(int)pow(2,blocksize),cachesize);
and now this is my called function
struct cache ** createCache(int numset, int blocksize, int cachesize){
int numcache = (int)((cachesize/blocksize)*numset);
struct cache out[numset][numcache];
int i,j;
for (i=0; i < numset; i++){
for (j=0; j < numcache; j++){
out[i][j].tag = "0";
out[i][j].vaild = 0;
out[i][j].data ="0";
}
}
return out;
}
and when i try to compile this, it tells me that
return from incompatible pointer type
function returns address of local variable
(which points to the line "return out;")
I have no idea whats wrong with my code, i mean the type of the function return is the same as how i declear "out", so what causes this problem?
You create struct cache out[numset][numcache];
within the function prototyped as: struct cache ** createCache(...).
Then attempt to return out.
It is because struct cache [][] is typed differently than struct cache ** that you are getting the return errors.
Other comments:
1) If you truly do want a pointer to pointer to struct, then malloc or calloc will need to be used at some point to allocate memory.
2) the char * members of the struct also need to be assigned memory before assigning values. For illustration below, they are changed to char []
3) assigning values to strings does not work by using = assignment operator. Use a string function such as strcpy, sprintf, etc.
4) you've named the struct with the same symbol as that of the new type you have created, i.e. cache. In this application, the name cache is not necessary. Also, purely for style, I show the new type in CAPS. This is not necessary, but just a style I use to make the new type more recognizable in code.
In consideration of the comments above, the struct could be changed to the following:
typedef struct { /// don't need name here when it in this application
int vaild;
//char *tag;
char tag[20];//for illustration, to avoid additional dynamic allocation of memory
//char* data;
char data[80];
}CACHE;//capitalization is style only, not a necessity here.
Note, there is no name, but the new type CACHE was created. Now, you can create the function createCache:
CACHE ** createCache(int ncache, int nset)//note for simplicity of freeing this
//object later, simplify number of arguments
{
CACHE **out;
out = calloc(ncache, sizeof(CACHE *));//create array of pointers to CACHE
if(!out) return NULL;
int i;
for (i=0; i < nset; i++)
{
out[i] = calloc(nset, sizeof(CACHE));//create space for each instance
//of CACHE pointed to by array pointers
}
return out;
}
Anytime memory is created on the heap, it needs to be freed. This method will free the CACHE object memory:
void freeCashe(CACHE **a, int nset)
{
int i;
for(i=0; i<nset; i++)
{
if(a[i])free(a[i]);
}
if(a)free(a);
}
Calling these functions as shown below, will create an array of pointers, each pointing to an instance of CACHE where you can use them as intended, then free all of the memory when finished:
int main(void)
{
int cachesize = 20;
int blocksize = 20;
int numset = 10;
//move the calculation out of creation function
//to simplify freeing object later.
int numcache = (int)((cachesize/blocksize)*numset);
CACHE **a = createCache(numcache, numset);
/// use a, then free a
freeCashe(a, numset);
return 0;
}
Your function needs to allocate the memory on the heap rather than the stack. You will need to allocate space on the heap for your array of pointers, and for what they point too.
struct cache ** createCache(int numset, int blocksize, int cachesize){
cache ** out;
int numcache = (int)((cachesize/blocksize)*numset);
size_t headerSize = sizeof(*out)*numset;
size_t bodySize = sizeof(**out)*numcache;
out = malloc(headerSize + (bodySize*numset));
if (out == NULL) {
/* Should probably output some message about being
* insufficient memory here. */
return NULL;
}
int i,j;
for (i=0; i < numset; i++){
/* need to assign our point */
out[i] = (cache*)(((char*)out)+(headerSize+bodySize*i));
for (j=0; j < numcache; j++){
out[i][j].tag = "0";
out[i][j].vaild = 0;
out[i][j].data ="0";
}
}
return out;
}
/* importantly, you want a way to free your allocated memory */
void destroyCache(cache ** ptr) {
free(ptr);
}
PS: You don't have to typedef your struct if you reference it with the struct keyword.
You are wanting a pointer pointer type to be returned, but in order to do that you need to dynamically allocate it. Local stack allocations (i.e. struct cache[x][y]) won't work. You will either get an error or your program will crash when attempting to use the 2D array.
The solution is to either pre-allocate space and pass it in to the function or allocate in the function itself.
Allocation In Function Example:
struct cache ** createCache(int numset, int blocksize, int cachesize){
int numcache = (int)((cachesize/blocksize)*numset);
struct cache **out = malloc(sizeof(struct cache *) * numset); // This line changed.
int i,j;
for (i=0; i < numset; i++){
out[i] = malloc(sizeof(struct cache) * numcache); // This line added.
for (j=0; j < numcache; j++){
out[i][j].tag = malloc(sizeof(char)); // This line added.
out[i][j].data = malloc(sizeof(char)); // This line added.
strcpy(out[i][j].tag, "0");
out[i][j].vaild = 0;
strcpy(out[i][j].data, "0");
}
}
return out;
}

freeing a structure array allocated with double pointer

Here is basically what I'm trying to do:
free memory that was allocated in a different scope using double pointers.
The following code is incomplete but fully describes what I'm trying to perform.
so here is my function to read the buffer (C pseudo code)
char *read_buffer(char *buf, myStruct **arr, int nbElm)
{
buf = malloc(...);
...//many things done (use of the read(),close()... functions
...//but not referencing any of the buffer to my structure
...
*arr = (myStruct *) = malloc(sizeof(myStruct) * nbElm);
return (buf);
}
Here is the kind of function I use between my memory allocation and my freeing attempt:
void using_struct(myStruct *ar, int nbElm)
{
int i;
i = 0;
while (i < nbElm)
{
// Here I use my struct with no problems
// I can even retrieve its datas in the main scope
// not memory is allocated to it.
}
}
my main function :
int main(void)
{
char *buf;
myStruct *arStruct;
int nbElm = 4;
buf = read_buffer(buf, &arStruct, nbElm);
using_struct(arStruct, nbElm);
free(buf);
buf = NULL;
free(arStruct);
while(1)
{;}
return (1);
}
The only problem is either I place my while loop before or after my free function, I can't see any memory change using top
on my terminal.
Is this normal?
Thanks in advance,
You always must have exactly same number of calls to free as a calls to malloc.
myStruct **arr;
*arr = malloc(sizeof(myStruct) * nbElm);
This means you need single call to free first nbElm structs:
free(arr);

Allocating memory to my stack dynamically (only if needed)

I need to allocate memory to an array inside my struct, this array has no defined size at the beginning when i define the struct:
typedef struct stacks {
int size; // Stores the size of my -values- array
int sp; //points to the top of the stack, my stackpointer
int *values;
} STACKS;
So, to initialize my struct i wrote this function, that allocates (using calloc?) memory to my array, and i put inside SIZE variable, the new size of my array .
#define MAXIMUM 10
int initStacks(STACKS *s){
s->values = calloc(MAXIMUM,sizeof(int));
s->size = MAXIMUM;
s->sp = 0;
return 0;
}
Now, if i want to push something to the top of the stack (LIFO) i use this:
int pushs(STACKS *s, int x){
if (s->sp==s->size) {
realloc(s->values, MAXIMUM * sizeof(int));
s->size*=2;
}
s->values[s->sp]=x;
s->sp++;
}
Is this the correct way of doing this?
Is realloc working as it should in my function?
Thank you very much for your help!
EDIT:
would this make more sense? This way, i really don't need to declare the value of the array, being that defined with #define maximum 10
typedef struct stacks {
int size; // guarda o tamanho do array valores
int sp;
int *values;
} STACKS;
int initStacks(STACKS *s){
s->values = calloc(1,sizeof(int));
s->size = 1;
s->sp = 0;
return 0;
}
int isEmptys(STACKS *s){
return((s->sp)==0);
}
int pushs(STACKS *s, int x){
s->size++;
realloc(s->values, s->size * sizeof(int));
s->values[s->sp]=x;
s->sp++;
}
Assuming you have an original size factor (the name capacity would be as-appropriate, if not more so), your original code lacks several things:
Compares the size against a constant, rather than the current sp against the stack current size.
Does not save nor test the return result of realloc
Does not actually double the allocation (you're missing the 2x in the realloc expression.
Declares an int return result, but no such return exists.
Has no way of communicating back to the caller the push result (success or not). That missing return result would be ideal for this, btw.
Addressing all of these:
int pushs(STACKS *s, int x)
{
if (s->sp == s->size)
{
void *pv = realloc(s->values, 2 * s->size * sizeof *(s->values));
if (pv != NULL)
{
s->values = pv;
s->size *= 2;
}
else
{
fprintf(stderr, "Failed to resize stack\n");
return -1;
}
}
s->values[s->sp++] = x;
return 0;
}
Untested, but hopefully close enough.
Best of luck
Although not directly an answer to the actual question, but more to the general problem, I post this as it does not fit into a comment.
If you expect excessive push/pop operations and memory usage, the following might be an alternative:
typedef struct SubStack_s {
struct SubStack_s *prev;
int data[ENTRIES_PER_SEGMENT];
} SubStack;
typedef struct {
SubStack *tos; // init to NULL
size_t sp; // init to 0
} Stack;
The basic idea is to push elements onto each substack until full (as you already do). If the current one is full, you alloc a new one, chain them (new->prev = old) and continue with the new one (storing new to Stack.tos)
Pop works similar, free'ing each substack once it is not used anymore.
That concept is called "fragmented stack". It is much more efficient than the realloc-approach (it avoids copying) and does not fragment RAM as all block are of equal size. Oh, and it allows to have pointers into the stack, which the realloc-varaint does not, because the address of the stack can change.

How to track malloc and free? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Simple C implementation to track memory malloc/free?
I need to know how much memory I have used till now in a C program and here is the pseudo code
#include <stdio.h>
int usedMemory =0;
void *MyMalloc(int size){
usedMemory = usedMemory +size ;
return malloc(size);
}
void MyFree(void *pointer){
/*****************what should i write here????*************/
}
int main(int argc, char *argv[])
{
char *temp1= (char *)MyMalloc(100);
char *temp2= (char *)MyMalloc(100);
/*......other operations.........*/
MyFree(temp1);
MyFree(temp2);
return 0;
}
Can anyone tell me what to write in the MyFree method(which decrements the amount of memory freed from usedMemory.
You could allocate few extra bytes more than asked, and store the size in the extra bytes, so that you could know the size later on, in MyFree function, with little calculation as:
unsigned long int usedMemory = 0;
void *MyMalloc(int size)
{
char *buffer = (char *) malloc(size + sizeof(int)); //allocate sizeof(int) extra bytes
if ( buffer == NULL)
return NULL; // no memory!
usedMemory += size ;
int *sizeBox = (int*)buffer;
*sizeBox = size; //store the size in first sizeof(int) bytes!
return buffer + sizeof(int); //return buffer after sizeof(int) bytes!
}
void MyFree(void *pointer)
{
if (pointer == NULL)
return; //no free
char *buffer = (char*)pointer - sizeof(int); //get the start of the buffer
int *sizeBox = (int*)buffer;
usedMemory -= *sizeBox;
free(buffer);
}
In C++, you could keep a global std::map<void*, std::size_t> around to track the size of each allocated block; your own allocator function would register the size when allocating, and the deallocation function would remove the entry. (Update: Or do as the linked question suggests and allocate a bit more memory and save the size there.)
The more fundamental problem is that this will probably only be of very limited use in a typical C++ program: Allocations there are done predominantly in two ways: 1) through explicit new expressions, which call ::operator new(), which in turn (usually) calls malloc(), and 2) through std::allocator<T>::allocate(), which on many platforms is implemented in terms of ::operator new().
The problem is that you don't have control over the specifics of your platform. You can replace the global operator-new to use your own MyMalloc(), but the default std::allocator might use malloc() directly and thus not be affected by that.
A cleaner approach for debugging purposes is to use an external tool like valgrind to track heap usage. For permanent internal use, tracking the allocation sizes is going to cause a significant performance hit, too.
You could allocate memory and store its size in the allocated block (error checking omitted for brevity):
unsigned int totalAlloc = 0;
void *MyAlloc(unsigned int size)
{
void *p;
totalAlloc += size;
p = malloc(size + sizeof(int));
*(int *) p = size;
return (void *)(((int *) p) + 1)
}
void MyFree(void *ptr)
{
ptr = (void *)(((int *) ptr) -1 );
totalAlloc -= * (int *) ptr;
free(ptr);
}
This code actually reserves more memory than requested in order to store the block's size in the (usually) first four bytes. This information can then be retrieved later on when you free the memory.
You need to manage a list of all malloc() you have done with pointer + size. Then you can search for the size in that list, and decrement it in free().
Check for example in that example how they are doing:
http://developers.sun.com/solaris/articles/lib_interposers_code.html#malloc_interposer.c
You might have other possibilities to track memory, like:
Valgrind with massif tool for tracking memory usage over time. You can even generate png output graphics
Interposed libraries. You can found some libraries that you can use by LD_PRELOAD=thelib.so ./yourprogram, and they will output some statistics like jemalloc
(A side note, please accept some answers to your question !)
you could try something like this... i'd strongly recommend to use this only for debugging purpose!
#define MAXMEMBLOCKS 10000
typedef struct {
int size;
void* ptr;
} memblock;
typedef struct {
int totalSize;
int current;
memblock memblocks[MAXMEMBLOCKS];
} currentMemory;
currentMemory mem;
void *MyMalloc(int size) {
if (mem.current < MAXMEMBLOCKS) {
mem.current += size;
mem.memblocks[mem.current].size = size;
mem.memblocks[mem.current].ptr = malloc(size);
return mem.memblocks[mem.current++].ptr;
} else {
// you needed more memblocks than estimated
return NULL;
}
};
int MyFree(void *pointer) {
int i;
for (i = 0; i < mem.current; i++) {
if (mem.memblocks[i].ptr == pointer) {
mem.totalSize -= mem.memblocks[i].size;
free(mem.memblocks[i].ptr);
mem.current--;
return 0;
}
}
// you tried to free a block wich hasn't been allocated through MyMalloc()
return -1;
}

Resources