Alex Alex - 19 days ago 5
C Question

Creating, returning, and casting a struct with a char pointer in C

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?

Answer

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.