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.
Related
I read on some ways to dynamically create and use a 2D array, and I've settled on this way:
file:
5 4
+---+
|xxx|
|xxx|
+---+
main.c:
char** loadArray() {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w &h);
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose();
return buf;
}
int main() {
char** array = loadArray();
for (int i = 0; i < 4; i++) { // magic number, only because I know the size
printf("%s\n", array[i]);
}
return 0;
}
While this does compile, it gives a warning: incompatible pointer types returning 'char (*)[w]' from a function with result type 'char **', and segfaults if I try to run it.
Several questions (mainly for C, but C++ specific answers are welcome for future reference, when I get there):
What is the correct return type for a multidimensional array? The warning isn't quite helpful I think, since it offers a variable term, which I obviously don't have until I read the file.
At this point, I'm just trying to get returning 2D arrays to work, but when I do and move on, I'm going to need the dimensions of the array for proper usage later on. My first idea would be to return structs instead, where I can save the dimension and the array itself. However, after further thought, the variable size makes me think that I wouldn't be able to have a single struct template to use as the function's return type, and I would have to find some other way to get the size along with the array. Are ideas?
Thank you for your time.
Pointer to pointer and pointer to array are quite different things. You can't return the array dimension as such in the return type so you'd have to use an incomplete array:
char (*(loadArray()))[] {
...
}
Evidently this is not very readable so you'd better pass through a typedef:
typedef char line[];
line* loadArray() {
...
}
You'd also have to get your hands on the dimensions w and h, so you'd have to pass pointers to the values as arguments. But that would be another question.
What is the correct return type for a multidimensional array?
There is no "correct" type, it all depends on how you want to represent the data and what architecture you want to design.
The warning isn't quite helpful I think, since it offers a variable term
The warning is very helpful, because it indicates an error in the code - you are casting a pointer to an array to a pointer to a pointer. Ignoring that warning ultimately leads to printf("%s\n", array[i]); which is undefined behavior.
Are ideas?
You may return a pointer to a dynamically allocated array of pointers to dynamically allocated array of values.
char **loadArray(void) {
size_t w, h;
// Initialize w and h.
char **arr;
arr = malloc(w * sizeof(*arr));
if (!arr) return NULL;
for (size_t i = 0; i < w; ++i) {
arr[i] = malloc(h * sizeof(*arr[i]));
if (!arr[i]) {
for (size_t j = 0; j < i; ++j) {
free(arr[j]);
}
frer(arr);
return NULL;
}
}
// Fill arr from file. Handle errors. Handle deallocation.
return arr;
}
which is the usual way to program in C and one would expect char ** to act that way. I can thing of an example from POSIX , where scandir function takes a pointer to a double pointer struct dirent ***namelist argument which is assigned to a such dynamically allocated 2d array.
But let's take a bit over-engineered (or not) design (in mostly C-ish pseudocode):
// represents the thing
struct thething_s {
char *string;
};
int thething_print(struct thething_s *t, FILE *f) {
return fprintf(f, ....);
}
void thething_free(struct thething_s *t) {
free(t->string);
}
int thething_load_from_file(struct thething_s *t, FILE *f, size_t len) {
t->string = malloc(len);
if (!t->string) return -1;
if (scanf(....) != 1) return -2;
return 0;
}
// represents an array of things
struct thingsarr_s {
struct thethings_s *things;
size_t w;
size_t h;
};
int thigsarr_load_from_file(struct thingsarr_s *t, FILE *f) {
// Initialize t->w and t->h.
t->things = malloc(t->w * sizeof(*t->things));
if (!arr) return -1;
for (size_t i = 0; i < w; ++i) {
if (thething_load_from_file(&t->things[i], f, t->h) != 0) {
for (size_t j = 0; j < i; ++j) {
thethings_free(t->things[j]);
}
free(t->things);
return -1000 - i;
}
}
return 0;
}
const struct thething_s *thingsarr_get_thing(const struct thingsarr_s *t, size_t idx)
{
assert(idx < t->len);
return t->things[idx];
}
struct thething_s *thingsarr_get_thing_nonconst(struct thingsarr_s *t, size_t idx) {
return (struct thething_s *)thingsarr_get_thing(t, idx);
}
void thingsarr_free(struct thingsarr_s *t) {
for (.,.) {
thething_free(&t->things[i]);
}
free(t->things);
}
Which is "best" strongly depends on the context, specific needs and specific application.
The pointer types char ** and char (*)[w] are very different. There is a common misconception that arrays and pointers are the same thing in C, but that is not the case.
You want the return type of the function to be char (*)[w], but that return type is impossible to declare because w is an unknown value. Also, the caller doesn't know the width and height of the returned array, because that information is internal to the loadArray function.
Setting the return type of the loadArray function to void* allows it to just return a pointer to the array without knowing the width or height. The width and height values can be sent to the caller using pointer arguments so that the caller can reconstruct the array type.
The following modifications of the original C code implements the above change. (C++ does not support variable length array types as far as I know, so this is C only.)
#include <stdio.h>
#include <stdlib.h>
void* loadArray(int *pw, int *ph) {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w, &h);
*pw = w;
*ph = h;
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose(in);
return buf;
}
int main(void) {
int w, h;
void* larray = loadArray(&w, &h);
char(*array)[w] = larray;
for (int i = 0; i < h; i++) {
printf("%s\n", array[i]);
}
return 0;
}
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;
}
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 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);