I would like to create a function that will reallocate 2D array of typedef struct
typedef struct hero_data{
char name[254];
char title[254];
int encoding;
int startstr;
double incstr;
int startdex;
double incdex;
int startintel;
double incintel;
int basemindmg,basemaxdmg;
double bat;
double basearmor;
struct hero_data *next;
struct hero_data *Class;
}hero;
typedef struct parameters{
int toughtotal;
int nimbletotal;
int smarttotal;
int skeptictotal;
int mystictotal;
int cursedtotal;
int brutetotal;
int shreddertotal;
int vanillatotal;
int typetotal;
int typenum;
hero **smart[];
hero **nimble[];
hero **tough[];
hero **type[][];
hero **skeptic[][];
hero **mystic[][];
hero **cursed[][];
hero **brute[][];
hero **shredder[][];
hero **vanilla[][];
}Parameters;
void reallocation(Parameters *p, int typenum,int typetotal)
{
int i;
p = realloc(p,sizeof(Parameters *) * typenum);
for ( i = 0; i < typenum; i++)
{
p[i] = realloc(p[i],sizeof(Parameters) * typetotal);
}
}
The function above shall be called like: void reallocation(p->type,p->typenum,p->typetotal);
So, by substituting the parameters of the function correctly, I expect the function to look like:
void reallocation(Parameters *p, int typenum,int typetotal)
{
int i;
p->type = realloc(p->type,sizeof(Parameters *) * p->typenum);
for ( i = 0; i < p->typenum; i++)
{
p->type[i] = realloc(p->type[i],sizeof(Parameters) * p->typetotal);
}
}
The typedef struct named Parameters contains int typenum, int typetotal, and the 2D arrays that shall be initialized through realloc().
When I try to compile, I am getting an error in Tiny C (Windows): *The file is in C.
Error: cannot cast 'struct parameters' to 'void *'
(This apeears in the 'p[i] = realloc(p[i],sizeof(Parameters) * typetotal')
Can anyone help me re-write this function so that I will be able to realloc the 2D arrays within the Parameter *p?
I tried changing void reallocation(Parameters *p, ...) into void reallocation(Parameters *p[], ...) and the Error # 2 becomes the same message as Error #1 and it appears in the = of p[i] = realloc (...);
A large problem with your code is that you are assigning inequal types to each other, and you are also not checking the result of realloc. If this call were to fail, you will leak the memory allocated initially.
Assuming that your struct looks like
typedef struct {
int typenum;
int typetotal;
} Parameters;
Parameters *p;
p = malloc(10 * sizeof(*p));
if (p == NULL)
printf("Allocatation of memory failed!\n");
To properly reallocate to say 20, you could do something like this
reallocate_p(&p, 20);
Where the function is defined as
void reallocate_p(Parameters **p, int new_size)
{
Parameters *temp;
temp = realloc(*p, sizeof(*temp) * new_size);
if (temp==NULL) {
printf("Reallocatation of memory failed!\n");
// Handle error
}
*p = temp;
return;
}
Also note that we don't cast the return value of malloc() and realloc().
As to why, see this reference
OP is coding in C, but using a using a C++ compiler.
Code in C++
// C
// p = realloc(p,sizeof(Parameters *) * typenum);
// C++
p = (Parameters *) realloc(p,sizeof(Parameters *) * typenum);
OR
VS2012: set properties for each C file to use C compiler
How to compile C in visual studio 2010?
OP code has a memory leak when scaling down the pointer array table. The pointers in the table that are about to be loss due to realloc() need to be freed first.
for (i=old_typenum; i<typenum; i++) free(p[i]);
p = realloc(p,sizeof(Parameters *) * typenum);
Related
So when I pass a data type like a struct to assign some memory to it I find that the pointer doesn't change within the main scope. This further becomes a problem when I try to free the memory but obviously if its using the original pointer it will be pointing at the stack address.
void allocate(int *value){
value = malloc(10 * sizeof(int));
}
int main(){
int val2;
allocate(&val2);
free(&val2);
return 0;
}
I can fix this by using a double pointer to be passed into the allocate function but some course work I'm doing requires to only pass a pointer and I cant get it to update the pointer when it returns to main. I have looked around for a while but cant find a straight forward answer, I feel like my coursework is wrong but that might be my lack of understanding.
The requirement to "only pass a pointer" seems contrived, and you could argue that a pointer to pointer (not a "double pointer") is a pointer, but perhaps you could use void * to punch a hole in the type system. Or use a struct:
#include <stdlib.h>
#include <stdio.h>
struct intbuffer {
int *d;
size_t cap;
};
void *
xmalloc(size_t s)
{
void *r = malloc(s);
if( r == NULL ){
perror("malloc");
exit(1);
}
return r;
}
void
allocate(void *p, size_t s)
{
*(int **)p = xmalloc(s * sizeof(int));
}
void
allocate2(struct intbuffer *p)
{
p->d = xmalloc(p->cap * sizeof *p->d);
}
int
main(void)
{
int *val2;
struct intbuffer v;
allocate(&val2, 10);
free(val2);
v.cap = 10; /* Horrible api!! */
allocate2(&v);
free(v.d);
return 0;
}
Note that setting the capacity in the struct prior to making the call to allocate is a violation of many principles of software design, but this whole thing is absurdly contrived due to the bizarre artificial limitations.
There are not enough *'s in each place, but you will have to figure out what that means.
void allocate(int** value){
*value = malloc(10 * sizeof(int));
}
int main(){
int* val2;
allocate(&val2);
free(val2);
return 0;
}
I'm pretty bad at remembering C rules with structs. Basically, I have a struct like this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Where the char* ptr will only be one character max.
In my program, I have to allocate and free memory to a fake disk (declared globally as char disk[100];) using my own functions:
char disk[100];
void disk_init() {
for(int i = 0; i < 100; ++i) {
disk[i] = memory[i] = 0;
}
}
struct Xalloc_struct* Xalloc(int size) {
// error checking
// ...
// run an algorithm to get a char* ptr back to a part of the global disk
// array, where index i is the index where content at disk[i] starts
char* ptr = &disk[i];
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
ret->size = size;
ret->ptr = malloc(sizeof(char));
ret->ptr = ptr;
return ret;
}
int Xfree(void* ptr) {
struct Xalloc_struct* p = (struct Xalloc_struct*) ptr;
int size = p->size;
int index = *(p->ptr);
// .. more stuff here that uses the index of where p->ptr points to
free(p->ptr);
free(p);
return 0;
}
int main() {
disk_init();
struct Xalloc_struct* x = Xalloc(5);
Xfree(x);
return 0;
}
When this compiles I get quite a few errors:
error: invalid application of ‘sizeof’ to incomplete type ‘struct Xalloc_struct’
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
^
error: dereferencing pointer to incomplete type
ret->size = size;
^
error: dereferencing pointer to incomplete type
free(x->ptr);
^
error: dereferencing pointer to incomplete type
int size = cast_ptr->size;
^
error: dereferencing pointer to incomplete type
int free_ptr = *(cast_ptr->ptr);
^
So, how should I be allocating and deallocating these structs? And how can I modify / edit what they contain?
First problem is Xalloc_struct is a type, not the name of a struct. You declared that type with this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
typedef is of the form typedef <type name or struct definition> <name of the type>. So you declared the type Xalloc_struct to be struct { char *ptr; int size; }.
That means you use it like any other type name: Xalloc_struct somevar = ...;.
Had you declared the struct with a name...
struct Xalloc_struct {
char* ptr;
int size;
};
Then it would be struct Xalloc_struct somevar = ...; as you have.
The rule of thumb when allocating memory for an array (and a char * is an array of characters) is you allocate sizeof(type) * number_of_items. Character arrays are terminated with a null byte, so for them you need one more character.
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = malloc(sizeof(char) * num_characters+1);
But if you're only storing one character, there's no need for an array of characters. Just store one character.
typedef struct {
char letter;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->letter = 'q'; /* or whatever */
But what I think you're really doing is storing a pointer to a spot in the disk array. In that case, you don't malloc at all. You just store the pointer like any other pointer.
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = &disk[i];
Then you can read that character with ret->ptr[0].
Since you didn't allocate ret->ptr do not free it! That will cause a crash because disk is in stack memory and cannot be free'd. If it were in heap memory (ie. malloc) it would probably also crash because it would try to free in the middle of an allocated block.
void Xalloc_destroy(Xalloc_struct *xa) {
free(xa);
}
Here's how I'd do it.
#include <stdio.h>
#include <stdlib.h>
char disk[100] = {0};
typedef struct {
char *ptr;
int idx;
} Disk_Handle_T;
static Disk_Handle_T* Disk_Handle_New(char *disk, int idx) {
Disk_Handle_T *dh = malloc(sizeof(Disk_Handle_T));
dh->idx = idx;
dh->ptr = &disk[idx];
return dh;
}
static void Disk_Handle_Destroy( Disk_Handle_T *dh ) {
free(dh);
}
int main() {
Disk_Handle_T *dh = Disk_Handle_New(disk, 1);
printf("%c\n", dh->ptr[0]); /* null */
disk[1] = 'c';
printf("%c\n", dh->ptr[0]); /* c */
Disk_Handle_Destroy(dh);
}
What you are attempting to accomplish is a bit bewildering, but from a syntax standpoint, your primary problems are treating a typedef as if it were a formal struct declaration, not providing index information to your Xalloc function, and allocating ret->ptr where you already have a pointer and storage in disk.
First, an aside, when you are specifying a pointer, the dereference operator '*' goes with the variable, not with the type. e.g.
Xalloc_struct *Xalloc (...)
not
Xalloc_struct* Xalloc (...)
Why? To avoid the improper appearance of declaring something with a pointer type, (where there is no pointer type just type) e.g.:
int* a, b, c;
b and c above are most certainly NOT pointer types, but by attaching the '*' to the type it appears as if you are trying to declare variables of int* (which is incorrect).
int *a, b, c;
makes it much more clear you intend to declare a pointer to type int in a and two integers b and c.
Next, in Xfree, you can, but generally do not want to, assign a pointer type as an int (storage size issues, etc.) (e.g. int index = *(p->ptr);) If you need a reference to a pointer, use a pointer. If you want the address of the pointer itself, make sure you are using a type large enough for the pointer size on your hardware.
Why are you allocating storage for ret->ptr = malloc(sizeof(char));? You already have storage in char disk[100]; You get no benefit from the allocation. Just assign the address of the element in disk to ptr (a pointer can hold a pointer without further allocation) You only need to allocate storage for ret->ptr if you intend to use the memory you allocate, such as copying a string or multiple character to the block of memory allocated to ret->ptr. ret->ptr can store the address of an element in data without further allocation. (it's unclear exactly what you intend here)
You are free to use a typedef, in fact it is good practice, but when you specify a typedef as you have, it is not equivalent to, and cannot be used, as a named struct. That is where your incomplete type issue arises.
All in all, it looks like you were trying to do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
char disk[100] = "";
Xalloc_struct *Xalloc (int size, int i) {
char *ptr = &disk[i];
Xalloc_struct *ret = malloc (sizeof *ret);
ret->size = size;
// ret->ptr = malloc (sizeof *(ret->ptr)); /* you have a pointer */
ret->ptr = ptr;
return ret;
}
int Xfree (void *ptr) {
Xalloc_struct *p = (Xalloc_struct *) ptr;
// int size = p->size; /* unused */
// int index = *(p->ptr); /* what is this ?? */
// .. more stuff here that uses the index of where p->ptr points to
// free (p->ptr);
free (p);
return 0;
}
int main (void) {
int i = 0;
Xalloc_struct *x = Xalloc (5, i++);
Xfree(x);
return 0;
}
Look at the difference in how the typedef is used and let me know if you have any questions.
i want to build a structure which can hold simple datatypes like integers or arrays of that structure.
the structure looks like that:
typedef struct data_s {
size_t size; // size of memory data is pointing to
void * data; // pointer to data (array of data_t or simple type)
} data_t;
i have simplified it, normally there are more informations stored in the structure.
i wrote functions to set and get integer values, they work!
now i tried to write functions for creating an array and seting and getting the values, they don't work.
i used gdb to find where it fails. it shows me that my dereferencing doesnt work as i expect. i use following:
((data_t**)(data->data))[i]
and there i got a access violation.
i t would be great if somebody could show me my mistake. here is a working codeexample, i have minimized the code, that you dont have the overhead of my programm (also errorhandling is removed).
the code compiles without any error using gcc -g main.c -o test with gcc 4.8.1 on xubuntu 13.10 with 3.11 kernel
#include <stdio.h>
#include <stdlib.h>
typedef struct data_s {
size_t size;
void * data;
} data_t;
void set_integer(data_t *data, int value){
data->size = sizeof(int);
data->data = malloc(data->size);
*((int*)(data->data)) = value;
}
void get_integer(data_t *data, int *value){
(*value) = *((int*)(data->data));
}
void create_array(data_t *data, size_t len){
data->size = sizeof(data_t) * len;
data->data = malloc(data->size);
int i;
for(i=0; i<data->size; i++){ //initialize array
((data_t**)(data->data))[i]->data = NULL;
((data_t**)(data->data))[i]->size = 0;
}
}
void set_array(data_t *data, int index, data_t *value){
((data_t**)(data->data))[index]->data = value->data;
((data_t**)(data->data))[index]->size = value->size;
}
void get_array(data_t *data, int index, data_t *value){
value->data = ((data_t**)(data->data))[index]->data;
value->size = ((data_t**)(data->data))[index]->size;
}
void free_data(data_t *data, int is_array){
if(is_array){
int i;
for(i=0; i<(data->size / sizeof(data_t)); i++)
free(((data_t**)(data->data))[i]->data);
}
free(data->data);
}
int main(int argc, char**argv){
data_t data;
set_integer(&data, 42);
int val;
get_integer(&data, &val);
printf("expect 42; has: %d\n", val);
free_data(&data, 0);
data_t element;
create_array(&data, 3);
int i;
for(i=0; i<3; i++){
set_integer(&element, i*2);
set_array(&data, i, &element);
}
for(i=0; i<3; i++){
get_array(&data, i, &element);
get_integer(&element, &val);
printf("index: %d; value: %d\n", i, val);
}
free_data(&data, 1);
return 0;
}
((data_t**)(data->data))[i] is used when data->data is an array of pointers, try
((data_t*)(data->data))[i]
EDIT: to access the members, use something like
((data_t*)data->data)[i].data = NULL;
((data_t*)data->data)[i].size = 0;
What does data->data point to? Well, the line data->data = malloc(data->size); tells you: it points to a slap of uninitialized memory.
The problem is, that you don't store anything in that memory before trying to dereference a pointer you read from this memory. I. e. (data_t**)data->data is fine, ((data_t**)data->data)[index] yields a data_t* of undefined value, and because that value is undefined, dereferencing the pointer with ((data_t**)data->data)[index]->data is undefined behavior.
If you want to create an array of data_t objects, one indirection suffices, i. e. use
void create_array(data_t *data, size_t len){
data->size = sizeof(data_t) * len;
data->data = malloc(data->size);
int i;
for(i=0; i<data->size; i++){ //initialize array
((data_t*)(data->data))[i].data = NULL;
((data_t*)(data->data))[i].size = 0;
}
}
((data_t**)(data->data))[i];
In the above statement, data->data evaluates to data member of structure variable data (you should use different identifiers) which is of type void *. Now, you want to point data->data to a buffer which is an array of objects of type data_t. This means you must cast data->data to type data_t *, and not data_t **. Therefore, you should change the above statement to
((data_t *)(data->data))[i];
everywhere in your code. Also, note that free takes an argument of type void * and therefore you don't need to cast your pointer before passing it to free.
I have a struct that contains an int pointer
struct mystruct {
int *myarray;
};
I want to make a function that mallocates for mystruct and also initializes myarray. But, when I try to access an element of myarray, I get a seg. fault
void myfunction(struct mystruct *s, int len) {
s = malloc(sizeof(mystruct));
s->myarray = malloc(sizeof(int) * len);
int i;
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
}
main() {
struct mystruct *m;
myfunction(m, 10);
printf("%d", m->myarray[2]); ////produces a segfault
}
However, mallocating m in main seemed to solve my problem.
Revised Code:
void myfunction(struct mystruct *s, int len) {
int i;
s->myarray = malloc(sizeof(int) * len);
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
}
main() {
struct mystruct *m = malloc(sizeof(mystruct)); //this was in myfunction
myfunction(m,10);
printf("%d", m->myarray[2]); ///Prints out 1 like I wanted
}
Why did the 2nd attempt work and why did the first attempt not work?
The problem is that the first version assigns the result of malloc to a parameter, which effectively a local variable; the assigned value vanishes when the function returns
So, an alternative is to pass to the function a pointer to the location where you want to store the result of malloc. This is named pps in the code below. At the beginning of the function we do the malloc and assign to a local variable s. Then we do things with s. Then, just before the function exits, we assign the local variable s to the location pointed to by the parameter pps. *pps = s;
void myfunction(struct mystruct **pps, int len) { // note double "**"
struct mystruct *s = malloc(sizeof(mystruct);
s->myarray = malloc(sizeof(int) * len);
int i;
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
*pps = s; // now pass the alloc'ed struct back to main through parameter pps
}
Now, back in main we pass &m to the function. This passes a pointer to m to the function. When the function returns, the local variable m holds the value returned by malloc and passed through the parameter pps.
main() {
struct mystruct *m;
myfunction(&m, 10); // PASS THE ADDRESS OF m, not m itself
printf("%d", m->myarray[2]); // this will work now
}
I need to allocate arrays of structures in a bunch of different places in my program, thus putting the work inside a function (VS 2010). Compiler gives warning about uninitialized variable used. So how do I pass it, and how to declare it in the function. I've tried many variations of "&" and "*", to no avail.
(I apologize in advance if my code causes any form of nausea...I'm an English major.)
struct s_stream {
int blah;
};
void xxyz(void)
{
struct s_stream **StreamBuild;
char *memBlock_1;
xalloc(StreamBuild, memBlock_1, 20);
}
void xalloc(struct s_stream **StreamStruct, char *memBlock, int structCount)
{
int i = sizeof(struct s_stream *);
if ((StreamStruct=(struct s_stream **) malloc(structCount * i)) == NULL)
fatal("failed struct pointer alloc");
int blockSize = structCount * sizeof(struct s_stream);
if ((memBlock = (char *) malloc(blockSize)) == NULL)
fatal("failed struct memBlock alloc");
// initialize all structure elements to 0 (including booleans)
memset(memBlock, 0, blockSize);
for (int i = 0; i < structCount; ++i)
StreamStruct[i]=(struct s_stream *) &memBlock[i*sizeof(struct s_stream) ];
}
I'm not exactly sure I understand your question, but it seems like you want a function that will create a dynamically allocated array of struct s_stream objects and return them to the caller. If that's the case, it's pretty easy:
void easiest(void)
{
struct s_stream *array = malloc(20 * sizeof(struct s_stream));
}
You could move the malloc() off into its own function and return the pointer:
void caller(void)
{
struct s_stream *array = create_array(20);
}
struct s_stream *create_array(int count)
{
return malloc(count * sizeof(struct s_stream));
}
Or if you insist on passing the array as a parameter:
void caller(void)
{
struct s_stream *array;
create_array(&array, 20);
}
void create_array(struct s_stream **array, int count)
{
*array = malloc(count * sizeof(struct s_stream));
}
You are passing a copy of the pointer memBlock_1 to xalloc, so the address returned by malloc is written to the copy and never reaches the calling function. Since you presumably want the address to be available to xxyz in memBlock_1, you have to pass a pointer-to-pointer-to-char as the second argument,
void xalloc(..., char **memBlock, ...)
and call it with xalloc(..., &memBlock_1, ...);. In the body of xalloc, replace all occurrences of memBlock with *memblock, e.g. (*memblock = malloc(blockSize)) == NULL (no need to cast).
Analogously, the StreamStruct parameter of xalloc never changes the StreamBuild pointer-to-pointer-to-struct s_stream in xxyz. If I interpret your intentions correctly, you would also have to add a pointer layer to that parameter, void xalloc(struct s_stream ***StreamStruct, ..., ...), pass the address of StreamBuild in the call, xalloc(&StreamBuild, ..., ...) and dereference the pointer in the function body, e.g. (*StreamStruct = malloc(structCount * i)) == NULL.
Is there any reason you're not using a regular array? For example;
struct s_stream* streamArray = malloc(sizeof(s_stream*structCount));
Then you have an array of s_stream you can just access with streamArray[0] to streamArray[structCount-1] without dereferencing any extra pointers.