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.
Related
I'm new to programming and to C, and I just learned about structs. I'm trying to use them to make an array which can change size as required (so, if the array gets full, it creates a new array double the size, copies the old array into the new one and deletes the old one). All I've done so far is create the struct and the functions for setting it up, and already I'm having problems. The main problem is that, sometimes when I run it it does exactly what I expect it to, which is create the struct, return a pointer to said struct, and then print all elements of the contained array. Other times when I run it, it does nothing at all! I don't get how it can work sometimes, and sometimes not! Obviously i'm doing something really wrong, but I can't work out what. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int cap;
int used;
void (*cpy) (int *, const int *, int);
//void (*append) (int);
int array[];
} dynArray;
dynArray * new_dynArray(int *, int);
void copy(int *, const int *, int);
int main(void) {
int start_arr[] = {1,2,3,4,5,6};
// create new dynArray, pass start array and number of elemnts
dynArray *arr = new_dynArray(start_arr, \
sizeof(start_arr) / sizeof(start_arr[0]));
// print all elements of dynArray
for (int i=0; i<(arr->used); i++) {
printf("%d, %d\n", arr->array[i], i);
}
free(arr);
return 0;
}
dynArray * new_dynArray(int init_arr[], int size) {
//printf("%d", size);
// if number of elements >= 4 then dynArray size is double, else 8
int init_cap = (size >= 4) ? 2 * size : 8;
// create pointer with enough space for struct and the actual array
dynArray *arr = (dynArray *) malloc(sizeof(dynArray) + init_cap );
arr->cap = init_cap;
arr->used = size;
// assign address of funciton copy to arr->cpy
arr->cpy = copy;
// call the function, to copy init_arr to arr->array
arr->cpy(arr->array, init_arr, size);
return arr;
}
void copy(int dest[], const int src[], int src_size) {
// just copy initial array to new array
int i;
memcpy(dest, src, src_size*sizeof(int));
/*
for (i=0; i<src_size; i++) {
dest[i] = src[i];
printf("%d\n", dest[i]);
}*/
}
So I call init_dynArray, sending a normal array and the number of elements in the array. init_dynArray uses malloc to create space in memory for the struct + the inintal size of the array, set up everything in the struct and copy the array, and then return a pointer to it. I don't get how it can only work some of the time. Hope yuo guys can help, thanks!
The problem in your code is on this line:
dynArray *arr = (dynArray *) malloc(sizeof(dynArray) + init_cap );
You need to multiply init_cap by sizeof(int)
dynArray *arr = (dynArray *) malloc(sizeof(dynArray) + sizeof(int)*init_cap );
You should also use size_t for the init_cap's type.
Note: Storing a pointer to the copying function inside the struct would be useful if your dynamic array consisted of opaque elements that require non-trivial copying. Since copying ints can be accomplished with a simple memcpy, there is no need to store a function pointer in dynArray.
I'm currently doing a C programme which requires the use of pointers, which I'm not great at.
I'm currently getting 4 errors which all say 'dereferencing pointer to incomplete type' and I don't know why.
Here is an example of how I set up my pointers and where I get the errors.
struct myset
{
unsigned char *vector;
int size;
int size_in_bytes;
int size_in_bits;
};
struct myset* set_new(int size)
{
int i;
struct myset* s;
s= malloc (sizeof (struct myset));
s->vector=malloc(sizeof(char)*(size/(sizeof(char)*8))+1);
for(i=0; i<size; i++)
{
s->vector[i]=0;
}
s->size_in_bits=size;
s->size_in_bytes=(size/(sizeof(char)))+1;
return s;
};
and I get an error whenever I try to reference the pointer, for example in this function.
void bitset_intersect(struct bitset * dest, struct bitset * src1, struct bitset * src2)
{
int maxSize = dest -> size_in_bits;
int i;
int j;
for(i = 0; i<maxSize; i++)
{
for(j = 0; j<maxSize; j++)
{
if(bitset_lookup(src1, i) == bitset_lookup(src2, j))
{
bitset_add(dest,i);
}
}
}
}
The error is in the line int maxSize = dest -> size_in_bits;
Any help would be appreciated, thanks.
Without the function call, its slightly hard to tell if you are passing the right values as parameters.
If you are getting an error while trying to reference the pointer, then check the function call to make sure you are passing the address correctly. Doing so would remove this error.
Both *dest and *src should have address that is being passed into it since both are from the same struct bitset.
This is in my main.c
int main(){
int size = 5;
Path Solution;
PathInit(&Solution,size);
printf("Size: %d\n",Solution.size);
printf("top: %d", Solution.top);
}
This is in my path.h
typedef struct{
int size;
int top;
int *item;
}Path;
This is in my path.c
void PathInit(Path *P, int vsize){
P = (Path *)malloc(sizeof(Path));
P->size = vsize;
P->item = (int *)malloc(sizeof(int)*vsize);
P->top = -1;
}
The expected output is
Size: 5
top: -1
However the output is something along the lines of
Size: 3412832
top: 0
Can someone explain why my struct is not initializing properly. Also this isn't my full code but ive narrowed the problem down to these sections. Any help would be great. Thanks
You are using the stack:
Path Solution;
and passing a pointer:
PathInit(&Solution,size);
so you don't need to reserve space with malloc:
void PathInit(Path *P, int vsize){
P = (Path *)malloc(sizeof(Path)); /* Remove this line */
As mentioned in the answer of #Alter Mann's, the issue is that you mess up with the stack storage, which is undefined behaviour. In case you want to use dynamic allocation, you need to pass a pointer to pointer (and btw there is no need to cast the result of malloc in C), so you can modify it in your function, like:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int size;
int top;
int *item;
} Path;
void PathInit(Path **P, int vsize) { // pass pointer to pointer so we can modify it
*P = malloc(sizeof(Path)); // No need (and not recommended) to cast malloc in C
(*P)->size = vsize;
(*P)->item = malloc(sizeof(int) * vsize);
(*P)->top = -1;
}
int main() {
int size = 5;
Path* Solution; // this is now a pointer
PathInit(&Solution, size);
printf("Size: %d\n", Solution->size);
printf("top: %d", Solution->top);
free(Solution->item);
free(Solution);
}
Otherwise you need to return the pointer from your function:
Path* PathInit(int vsize) {
Path* tmp = malloc(sizeof(Path));
tmp->size = vsize;
tmp->item = malloc(sizeof(int) * vsize);
tmp->top = -1;
return tmp;
}
and call it like
Path* Solution;
Solution = PathInit(size);
i am fairly new to c and struggling to properly use the C stdlib qsort() function.
This is relevant to education and as such i am only allowed to use C99 and standard libraries if this is important.
I have a list of items taken from a HashTable and put into a HashItem **array but then when sorting this i am struggling with the compare function, i cannot get the correct value out of the struct. I have looked around and seen a few solutions but they all seem to lead to a
[Error] dereferencing pointer to incomplete type
Here is the struct :
typedef struct {
char *word;
int occurences;
} HashItem;
And i am interested in comparing and sorting by the occurences value.
Here is the bit of code which calls the qsort:
int n = array->number_of_values;
HashItem **standard_array = array_getarray(array);
qsort(standard_array, n, sizeof(HashItem*), compare_func);
Here is the compare function:
int compare_func(const void *a, const void *b){
const struct HashItem* aa = (HashItem*)a;
const struct HashItem* bb = (HashItem*)b;
int val_1 = aa->occurencies;
int val_2 = bb->occurencies;
if(val_1 == val_2){
return 0;
}else if(val_1 > val_2){
return 1;
}else{
return -1;
}
}
Sorry for the formatting, i am new to asking questions here.
I hope you can help thankyou.
Array code :
/*DynArray is a dynamically resizing array that is used to hold values and retain size data throughout*/
typedef struct{
int number_of_values;
int capacity;
HashItem **items;
}DynArray;
/*Method to create a new dynamic array and return it */
DynArray* array_new(int file_size){
DynArray *array = malloc(sizeof(DynArray));
array->number_of_values = 0;
array->capacity = file_size / 10;
printf("capacity is %d " , array->capacity);
array->items = malloc(sizeof(HashItem*)* array->capacity);
}
/*Method used to increase the size of the array and reallocate memory*/
void array_increase_if_full(DynArray *array){
if (array->number_of_values >= array->capacity){
array->capacity *= 1.25;
array->items = realloc(array->items, sizeof(HashItem)*array->capacity);
}
}
/*Method to add a string to the dynamic array specified */
void array_append(DynArray *array, HashItem *item){
array_increase_if_full(array);
array->items[array->number_of_values] = item;
//printf("item %s added \n at position %d ", array->items[array->number_of_values]->word, array->number_of_values);
array->number_of_values++;
}
/*Method used to get value at specified position for given array*/
HashItem *array_get(DynArray *array, int position){
if(position >= array->number_of_values || position <0){
printf("Index specified out of range");
exit(1);
}
//printf("item %s at position %d retrieved", array->items[position]->word, position);
return array->items[position];
}
HashItem **array_getarray(DynArray *array){
HashItem **toreturn[array->number_of_values];
int i;
for(i = 0; i < array->number_of_values; i++){
toreturn[i] = array_get(array, i);
}
return toreturn;
}
Printing the array from the main gives the correct unsorted values of word:occurences
Edit:
Thanks to everyone that took their time to help, it is now in a working state with Michaels suggestion, i no longer use the array_getarray() method and instead use:
int n = array->number_of_values;
int i;
HashItem **standard_array = malloc(n*sizeof(HashItem*));
for(i = 0; i < n; i++){
standard_array[i] = array_get(array, i);
printf("%s : %d \n" , standard_array[i]->word, standard_array[i]->occurences);
}
You structure declaration:
typedef struct {
char *word;
int occurences;
} HashItem;
declares a typedef name for an anonymous struct. There is a HashItem type that's a structure, but there is no struct HashItem type.
So when your compare_func() has the following declarations:
const struct HashItem* aa = (HashItem*)a;
const struct HashItem* bb = (HashItem*)b;
those struct HashItem* variables are pointers to a forward declared struct HashItem that has nothign to do with the HashItem strucuture above.
Just change those variable declarations to:
const HashItem* aa = (HashItem*)a;
const HashItem* bb = (HashItem*)b;
and/or change the declaration of the structure to:
typedef struct HashItem {
char *word;
int occurences;
} HashItem;
However, there's another issue (as mentioned in other answers): you are apparently sorting an array of pointers to HashItem objects, but your compare_function() is being written as if you're sorting an array of the objects (not pointers).
To address this:
int compare_func(const void *a, const void *b)
{
// get HashItem*'s from the HashItem**'s
const HashItem* aa = *((HashItem**)a);
const HashItem* bb = *((HashItem**)b);
int val_1 = aa->occurencies;
int val_2 = bb->occurencies;
if (val_1 == val_2) {
return 0;
} else if (val_1 > val_2) {
return 1;
} else {
return -1;
}
}
Finally (for now anyway), this function is returning the address to a local array, so the data it points to is no longer valid:
HashItem **array_getarray(DynArray *array){
HashItem **toreturn[array->number_of_values];
int i;
for(i = 0; i < array->number_of_values; i++){
toreturn[i] = array_get(array, i);
}
return toreturn;
}
I think you'll need to allocate the array you're retuning using malloc() or calloc() or something. But what I really think you need to do is step back and create some drawing of your data structures and think about the lifetime of the various objects contained in them and how those lifetimes can be tracked an managed so that you don't have leaks, double frees, or pointer dereferences to no longer valid objects.
Change qsort(standard_array, n, sizeof(HashItem), compare_func); to
qsort(standard_array, n, sizeof(HashItem*), compare_func);
In function void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
the third parameter size_t size stands for:
Size in bytes of each element in the array.
It now looks to me like your problems are all springing from the first definition.
/*DynArray is a dynamically resizing array that is used to hold values and retain size data throughout*/
typedef struct{
int number_of_values;
int capacity;
HashItem **items;
}DynArray;
I see no reason for items to be a double-pointer. The comment says it should contain values, but a double-pointer pointing to an array would contain pointers, not the ultimate values. I think this initial misstep is causing you to trip everywhere else. Change it to
...
HashItem *items;
...
and the rest should flow more naturally.
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);