c struct pointer issues - c

I'm trying to cast a struct into another struct but I'm having incompatible pointer issues within the cast and the malloc under some_func (structs layout are the same)
struct stu1 **some_func(struct stu1 *my_struct)
{
my_struct = (struct stu1 **)malloc(sizeof(struct stu1 *)*total_size);
for(i=0;i<20;i++){
my_struct[i] = (struct stu1 *)malloc(sizeof(struct stu1));
printf("%s",my_struct[i++]->a);
}
return my_struct;
}
int main()
{
struct stu1 **my_struct;
struct stu2 **my_struct2;
struct stu3 **my_struct3;
my_struct = some_func(my_struct);
my_struct2 = (struct stu2**)some_func((struct stu1*)my_struct2);
my_struct3 = (struct stu3**)some_func((struct stu1*)my_struct3);
}

Several problems.
Firstly, you have incompatible types all over the place. In the line
my_struct = some_func(my_struct);
my_struct has type struct stu1 **, but the definition of some_func expects a parameter of type struct stu1 *; the two types are not the same. A pointer to T is not the same type as a pointer to pointer to T.
Secondly, your casting gymnastics are not going to work as you expect. Pointer types are not automatically compatible; their base types must be compatible, and different struct types are not compatible, even if their layouts are the same, e.g.:
struct {int x, int y} foo;
struct {int x, int y} bar;
struct S {int x, int y} blurga;
struct S bletch;
foo, bar, and bletch are of different types and are not compatible, even though their layouts are the same. blurga and bletch are of the same type (struct S). If struct stu2 or struct stu3 have different sizes from struct stu1, then you won't allocate the right amount of memory for my_struct2 and my_struct3.
For the sake of clarity and your sanity, you should have different allocation functions for each type, rather than trying to force a square peg into a pentagonal hole:
struct stu1 **stu1_alloc(size_t count)
{
struct stu1 **arr = malloc(sizeof *arr * count);
if (arr)
{
size_t i;
for (i = 0; i < count; i++)
{
arr[i] = malloc(sizeof *arr[i]);
if (arr[i])
{
// initialize arr[i] as necessary
}
}
}
return arr;
}
struct stu2 **stu2_alloc(size_t count)
{
struct stu2 **arr = malloc(sizeof *arr * count);
if (arr)
{
size_t i;
for (i = 0; i < count; i++)
{
arr[i] = malloc(sizeof *arr[i]);
if (arr[i])
{
// initialize arr[i] as necessary
}
}
}
return arr;
}
struct stu3 **stu3_alloc(size_t count)
{
struct stu3 **arr = malloc(sizeof *arr * count);
if (arr)
{
size_t i;
for (i = 0; i < count; i++)
{
arr[i] = malloc(sizeof *arr[i]);
if (arr[i])
{
// initialize arr[i] as necessary
}
}
}
return arr;
}
int main(void)
{
struct stu1 **my_struct = stu1_alloc(SIZE);
struct stu2 **my_struct2 = stu2_alloc(SIZE2);
struct stu3 **my_struct3 = stu3_alloc(SIZE3);
...
}
Yes, the only thing different between the three allocation functions is the type. However, if the different struct types have different sizes or different initialization needs, then this is necessary.
Notice a couple of things. First of all, I'm not casting the result of malloc(). There are two reasons for this. One, as of C89 and later, you don't have to: malloc() returns a type of void *, which is implicitly converted to the target pointer type. Two, and more importantly, if I forget to include stdlib.h or otherwise don't have a prototype for malloc() in scope, leaving the cast off will trigger an "incompatible types" warning (since undeclared functions are assumed to return int, and you cannot implicitly convert an int value to a pointer type). If you cast the return value of malloc(), then you supress that warning and risk problems at runtime (since the value returned by malloc() will be converted from void * to int, and then from int to the target pointer type, which is not guaranteed to work).
Secondly, I'm using sizeof on the object, not the type. This has two benefits. One, the code is a little easier to read. Two, if I change the type of the object, I don't have to go back and change every call to malloc().
If you really don't want to have three separate allocation functions, you could try some macro magic like this:
#define ALLOC_STU(target, size) \
do { \
target = malloc(sizeof *target * size); \
if (target) \
{ \
size_t i; \
for (i = 0; i < size; i++) \
{ \
target[i] = malloc(sizeof *target[i]); \
} \
} \
} while(0)
int main(void)
{
struct stu1 **my_struct;
...
ALLOC_STU(my_struct, SIZE);
...
}
although I think the separate allocation functions are the safer way to go.

struct stu1 **some_func(struct stu1 *my_struct)
{
my_struct = (struct stu1 **)malloc(sizeof(struct stu1 *)*total_size);
my_struct is of type struct stu1 *, but you are trying to assign a (casted) struct stu1 **

Just guessing, do you want something like this:
struct stu1 **some_func(struct stu1 ***my_struct)
{
*my_struct = (struct stu1 **)malloc(sizeof(struct stu1 *)*total_size);
for(i=0;i<20;i++){
(*my_struct)[i] = (struct stu1 *)malloc(sizeof(struct stu1));
printf("%s",(*my_struct)[i++]->a);
}
return *my_struct;
}
int main()
{
struct stu1 **my_struct;
struct stu2 **my_struct2;
struct stu3 **my_struct3;
my_struct = some_func(&my_struct);
}
But this doesn't make much sense. The return value would not be necessary.

Where to begin ...
You must match your types. some_func() expects a single pointer; in one instance you are passing a double pointer (a pointer to a pointer).
Inside some_func(), the 1st malloc() has a type-mismatch. It is attempting to set a double pointer to a single pointer.
Inside some_func(), the 2nd malloc() is has another type-mismatch. It is attempting to set a non-pointer (the structure) to a pointer.
Inside some_func(), it appears as though you may be trying to dynamically a two-dimensional array. For reference, there are two ways to do this with malloc().
Method #1. (Without error checking)
struct stu1 **some_func(int dim1, int dim2)
{
struct stu1 **my_struct;
int i;
/* Allocate space for an array of <dim1> pointers */
my_struct = (struct stu1 **) malloc(sizeof(struct stu1 *) * dim1);
/* Allocate <dim2> elements for each pointer */
for (i = 0; i < dim1; i++){
my_struct[i] = (struct stu1 *) malloc (sizeof (struct stu1) * dim2);
}
return (my_struct);
}
Method #2. (Again, without error checking)
struct stu1 **some_func(int dim1, int dim2)
{
struct stu1 **my_struct;
int i;
char *data;
/* Allocate space for everything. */
data = (char *) malloc((sizeof (struct stu1 *) * dim1) + (dim1 * dim2 * sizeof (struct stu1)));
my_struct = (struct stu1 **) data;
/* Initialize pointers to pointers. */
data = (char *) &my_struct[dim1];
for (i = 0; i < dim1; i++) {
my_struct[i] = (struct stu1 *) data;
data += sizeof (struct stu1) * dim2;
}
return (my_struct);
}
Each method has its advantages and disadvantages. Hope this helps.

Related

Casting pointers to void to pointers to pointers to type A and dereferencing vs. Casting pointers to void to type A: Why?

I am just starting to learn C. Any help is appreciated!
I have an array of pointers to a struct, and I want to use the built-in qsort function to sort the array according to values in the structs the pointers point to. I am trying to use a compare function as demonstrated in the official docs.
The following version fails:
int compare_nodes(const void* a, const void* b){
const struct ListNode * ptr1 = ((const struct ListNode *) a);
const struct ListNode * ptr2 = ((const struct ListNode *) b);
// const struct ListNode * ptr1 = *((const struct ListNode **) a);
// const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
This version succeeds:
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
I do not understand the difference between the two versions:
If casting only tells the compiler how to interpret the address the pointer points to, what is the problem in version 1? Is it not enough to tell the compiler to interpret the pointer to void as a pointer to struct ListNode? Why do I need to add a layer of indirection with casting, just to then remove one layer with dereferencing?
Does C's pass-by-value play any role here? I could not think of any reason why by myself.
I found the following resources about this question. Although they seemed to explain this problem (especially resource 6), I did not understand them:
What are the rules for casting pointers in C?
Typecasting of pointers in C
Pointer type casting and dereferencing
What are the rules for casting pointers in C?
What does a C cast really do?
https://cboard.cprogramming.com/c-programming/102056-casting-pointer-pointer.html
Here's the full code:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
struct ListNode {
int val;
struct ListNode *next;
};
int calc_list_length(struct ListNode * head){
int target = 0;
struct ListNode * tmp = head;
while (tmp)
{
target++;
tmp = tmp -> next;
}
return target;
}
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
struct ListNode* sortList(struct ListNode* head){
if(!head) return NULL;
int list_length = calc_list_length(head);
struct ListNode * tmp = head;
struct ListNode * arr[list_length];
for (int i = 0; i < list_length; i++)
{
arr[i] = tmp;
tmp = tmp -> next;
}
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
qsort(arr, list_length, sizeof(struct ListNode *), compare_nodes);
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
}
int main(){
// [2,1,4,3]
struct ListNode node4 = {.val = 3, . next = NULL};
struct ListNode * ptr4 = &node4;
struct ListNode node3 = {.val = 4, .next = ptr4};
struct ListNode * ptr3 = &node3;
struct ListNode node2 = {.val = 1, .next = ptr3};
struct ListNode * ptr2 = &node2;
struct ListNode node1 = {.val = 2, .next = ptr2};
struct ListNode * ptr1 = &node1;
sortList(ptr1);
getchar();
return 0;
}
Thanks in advance. I hope you point me in the right direction.
The qsort passes pointers to the array elements using the pointer-to operator &.
So it can pass, for example, &arr[0] and &arr[1] as arguments to your comparison function.
Since arr is an array of pointers, where every element is a pointer, then a pointer to one element must by definition be a pointer to a pointer.
So the arguments passed to your compare_nodes structure are pointers to pointers to ListNode structures.
The function qsort is declared like
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
That is the function deals with pointers of the type void *. It passes to the comparison function two pointers of the type const void * that point to elements of the underlying array.
You declared an array of pointers
struct ListNode * arr[list_length];
Its elements of the type ListNode * are passed to the comparison function by reference through pointers to them.
In fact the function passes to the comparison function pointers of the type
ListNode ** that are passed as pointers of the type const void *. You may imagine this the following way
const void *p = &arr[i];
where the expression &arr[i] has the type ListNode **.
Of course the function qsort actually does not know the actual type of elements of the array. It uses the following pointer arithmetic
const void *p = ( char * )base + i * size;
Thus within the comparison function you need to do the "reverse" casting like
const struct ListNode * ptr1 = *((const struct ListNode **) a);
where ptr1 is an element of the original array that is passed to the comparison function by reference trough a pointer to it..
The fact that the qsort() function passes pointers to the array elements to your comparator function, rather than passing the array elements directly by value, is due to how qsort() was designed, and is not required by the core C language itself.
I can easily write a sorting function that sorts an array of pointers, with the following signature:
void my_sort_pointers(const void **array, size_t nmemb,
int (*compar)(const void *, const void *));
and it accepts a comparator function that is passed the array elements (the pointers) directly. Then your comparator function would not have to dereference the argument to get the actual values to be compared.
However, my sorting function above would not be able to sort, say, an array of floats, because it would not be able to pass two float arguments to a comparator function that is supposed to take two pointers. Even if you made a comparator function that took two floats, you would not be able to pass it to the function above, because the function pointer types are incompatible, and even if you somehow casted the type, it would still not work because the C code inside the function, which thinks it is calling a function that takes two pointers, cannot call a function that actually takes two floats, because the function signatures are incompatible.
So to be able to sort arrays of different types under this design, I would have to have another sorting function that sorts an array of floats:
void my_sort_floats(float *base, size_t nmemb,
int (*compar)(float, float));
and another sorting function that sorts an array of ints, etc. And since there can be an unlimited types of structs, with different sizes, you can never make functions that can handle all of them. Even if only basic types are supported, it would require several different functions. The designers of the C standard library decided that it would be a better design to make a single sorting function that works for all types, by passing a pointer to the array element to the comparator functon instead.
This design makes a lot of sense when you understand the limitations of C. (In C++, it would be possible to use generics to write a generic sorting function that works for any type, and has a comparator that is passed the array elements by value. But C doesn't have generics.) But it is a design decision of the qsort() function API nevertheless, and sorting functions in C (at least if they only accept a particular type) do not necessarily have to work this way. So you would only know that qsort() is supposed to be used in this way by reading the specification of qsort().

C, Invalid write with valgrind and void* variable

I want to assign a variable void* to an attribut void* from a structure.
My struct :
struct data{
int n;
void * cl;
}typedef data;
Then, I have this function :
void f(void *cl, int n){
struct data *data = malloc(sizeof(data));
data->cl = cl; //"Invalid write of size 8" from valgrind
data->n = n;
}
EDIT : "void *cl" is null, I don't know why (but not data)
And I call it like this :
f(args_f(2), 1);
About args_f :
struct st_args * args_f(int n)
{
struct st_args *args = malloc(sizeof(struct st_args));
if (args == NULL)
return NULL;
args->n = n;
return args;
}
The struct st_args :
struct st_args{
int n;
}typedef st_args;
Inside my function f, when I try the assignement "data->cl = cl;", valgrind says "Invalid write of size 8" on this line. why is that ?
I see a problem here: struct st_args *args is local, and you have returned it, without allocating proper memory.
struct data *data = malloc(sizeof(data));
At this instance, data is a pointer, and malloc would have allocated 4 (or 8) bytes of memory. It should have been,
struct data *data = malloc(sizeof(struct data));
This would allocate (if available) the required memory and segfault would go away.
Additionally, you should check if data is NULL after malloc, if yes then handle the error the way you have done in args_f function.
This is the exact reason why we should be avoiding variable naming convention where user-defined data types and variable names can be same.
For that matter, when I have a typedef, I typically have _t suffix to it to avoid any confusion.
For example,
This
struct data{
int n;
void * cl;
}typedef data;
would be something like this in my code
typedef struct stData {
int32_t i_N;
void *p_cl;
} data_t;

Allocate record with variable at negative offset

When allocating memory for a pointer to a record I also need space for an integer pointer located just before the allocated record. This pointer cannot be part of the record itself and it cannot be placed after the record. My current approach is the following:
#include <stdlib.h>
static int n;
struct { int f; } *p;
p = malloc(sizeof (int *) + sizeof *p);
if (p != NULL) {
p = (void *) ((int **) p + 1);
*((int **) p - 1) = &n;
}
Are the casts well defined? If not, what should I do instead?
Edit:
What I'm trying to achieve is to implement extensible records (OOP) and the integer pointer represent a type ID. An extended record should be compatible with its base type. However, I only need type ID:s for pointer to records. Here is a complete example:
#include <assert.h>
#include <stdlib.h>
struct T0 {
int f;
};
int T0ID;
struct T1 {
struct T0 base;
int g;
};
int T1ID;
int main(void)
{
struct T0 *x;
struct T1 *y;
y = malloc(sizeof (int *) + sizeof *y);
if (y != NULL) {
*((int **) y) = &T1ID;
y = (void *) ((int **) y + 1);
((struct T0 *) y)->f = 1;
y->g = 2;
}
x = (struct T0 *) y;
assert(x->f == 1);
return 0;
}
I'm not sure your approach is good. Especially I'm worried about changing the value of p. You'll need that value later when you need to free the memory.
I would wrap the int* and the struct together in another struct. Something like:
static int n;
struct someData { int f; };
struct wrapper {int* pn; struct someData data;};
struct someData* pd; // Pointer to the data struct
struct wrapper* pw = malloc(sizeof *pw);
if (pw != NULL) {
pw->pn = &n;
pd = &pw->data;
}
Your code, in which you cast (arbitrary) memory addresses to particular object types, is might yield undefined behaviour due to incorrect alignment (cf.
C standard draft):
6.3.2.3 Pointers
(7) A pointer to an object type may be converted to a pointer to a
different object type. If the resulting pointer is not correctly
aligned for the referenced type, the behavior is undefined.
You are having a pointer declared to be of type struct{int}* pointing to a (larger memory block), and then casting the pointer and doing arithmetic operations on the (casted) pointer. As it is not guaranteed that int * and struct{int}* are aligned the same way, it is not guaranteed that the behaviour is defined.
To avoid this, encapsulate your structure and the preceeding integer in another structure, e.g. as follows:
static int n;
struct data_struct {
int f;
};
struct enclosing_struct {
int *nPtr;
struct data_struct data;
};
int main() {
struct enclosing_struct *e = malloc (sizeof(struct enclosing_struct));
e->nPtr = &n;
struct data_struct *dataPtr = &e->data;
return 0;
}

Is a loop needed to set each member of an array of structs to be on the heap?

My struct declaration:
struct tileStruct
{
SDL_Rect * tilePixel;
Uint32 * tpColor;
int * tileNum;
int * xCoord;
int * yCoord;
};
Here is my function that needs to initialize an array of tileStructs, but each member of the struct is on the heap.
void tileInit()
{
struct tileStruct * tileArr = (struct tileStruct *)malloc(NUM_TILES_IN_WINDOW * sizeof(struct tileStruct));
tileArr->tilePixel = (SDL_Rect *) malloc(tPIXELS_PER_TILE * sizeof(SDL_Rect));
tileArr->tpColor = (Uint32 *) malloc(tPIXELS_PER_TILE * sizeof(Uint32));
tileArr->xCoord = (int *) malloc(sizeof(int));
tileArr->yCoord = (int *) malloc(sizeof(int));
tileArr->tileNum = (int *) malloc(sizeof(int));
//rest of function
}
So, my question is, do I need to do this?
struct tileStruct * tileArr = (struct tileStruct *)malloc(NUM_TILES_IN_WINDOW * sizeof(struct tileStruct));
for(int i = 0; i < NUM_TILES_IN_WINDOW; i++)
{
tileArr[i].tilePixel = (SDL_Rect *) malloc(tPIXELS_PER_TILE * sizeof(SDL_Rect));
tileArr[i].tpColor = (Uint32 *) malloc(tPIXELS_PER_TILE * sizeof(Uint32));
tileArr[i].xCoord = (int *) malloc(sizeof(int));
tileArr[i].yCoord = (int *) malloc(sizeof(int));
tileArr[i].tileNum = (int *) malloc(sizeof(int));
}
Yes, you should use loop. Since you've allocated array of struct tileStruct that has NUM_TILES_IN_WINDOW elements, you need to iterate through all elements. And your former tileInit() initializes only first element.
And probably it would be better to redefine your type in next way:
struct tileStruct
{
SDL_Rect tilePixel[tPIXELS_PER_TILE];
Uint32 tpColor[tPIXELS_PER_TILE];
int tileNum;
int xCoord;
int yCoord;
};
With such definition you can avoid a bunch of auxiliary allocations. (Of course such way is acceptable only when struct tileStruct has logical ownership on each of its elements.)

Protecting dynamic array member of const struct

Consider a struct with a dynamic allocated array as a member, for example:
struct matrix {
unsigned cols;
unsigned rows;
double* data;
};
How can I write a function like print_matrix(const matrix); that guarantees the data datapoints to is not modified?
Can I define something like
struct const_matrix {
const unsigned cols;
const unsigned rows;
const double* data;
};
and then implicitly convert a struct matrix to a struct const_matrix?
Here is a small example why the first version does not work.
Yes, your intuition is correct. You can define struct const_matrix just as you have and then cast to it:
void print_matrix(struct const_matrix *m)
{
// This bad implementation tries to change data.
// It does not compile.
m->data[0] = 100;
}
To call it, cast from (struct matrix *) to (struct const_matrix *). For example:
{
struct matrix m;
m.cols = 4;
m.rows = 4;
m.data = calloc(sizeof(double), m.cols*m.rows);
...
print_matrix((struct const_matrix *)&m);
}
Note that you must cast the pointer types (i.e. cast from (struct matrix *) to (struct const_matrix *), because C will not allow you to cast one structure to another (i.e., casting from (struct matrix) to (struct const_matrix) is not allowed).
You can have another const there:
double * const data; // non constant pointer to constant data
or even
double const * const data; // constant pointer to constant data

Resources