Protecting dynamic array member of const struct - c

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

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().

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;
}

C - emulate 'mutable' from C++

I have a C structure like this:
struct my_struct {
int i;
double d;
struct expensive_type * t;
};
An instance of this structure is created and initialized as:
struct my_struct * my_new( int i , double d)
{
struct my_struct * s = malloc( sizeof * s);
s->i = i;
s->d = d;
s->t = NULL;
return s;
}
Calculating the struct expensive_type * t member is quite expensive, and might not be needed - it is therefor just initialized to NULL - and later calculated on demand:
const struct expensive_type * my_get_expensive( const struct my_struct * s)
{
if (!s->t)
s->t = my_expensive_alloc( s->i , s->d );
return s->t;
}
In C++ I would have used mutable on the struct expensive_type *member, is it possible to achieve something similar in C, i.e. casting away the const locally:
{
struct my_struct * mutable_s = (struct my_struct*) s;
mutable_s->t = ...;
  }
Or is removing const in the signature my only standard-compliant alternative?
You could(1) restructure your code and add a layer of indirection:
struct expensive; // Forward declaration, ignore
// One could also use a struct expensive * (a pointer) instead
// of this structure. IMO giving it a name is the better option.
struct expensive_handle {
struct expensive * target;
};
// Store the simple data members as usual, store a pointer to a
// handle (pointer) to the expensive ones
struct my_struct {
int simple;
struct expensive_handle * handle;
};
struct expensive {
int content; // whatever
};
Creating a my_struct must create the additional pointer/handle used for the indirection:
struct my_struct * new() {
struct my_struct * data = malloc(sizeof(*data));
// Error handling please
// Set simple data members
data->handle = malloc(sizeof(*(data->handle)));
// Error handling please
data->handle->target = NULL;
return data;
}
The target member (which will point to the expensive data once it is computed) is set to NULL initially.
Accessing (and thus possibly lazy computation of) the expensive data members is then possible even with a const qualified my_struct, because no data member of that my_struct is changed:
int get_expensive(struct my_struct const * ptr) {
if (ptr->handle->target == NULL) {
ptr->handle->target = malloc(sizeof(struct expensive));
// Error handling please
puts("A hell of a computation just happened!");
ptr->handle->target->content = 42; // WOO
}
return ptr->handle->target->content;
}
The only thing that changes is the data member of *(ptr->handle), a struct expensive_handle. Which is not const qualified (only the pointer to it named handle is).
Test (Live on ideone):
int main(void) {
struct my_struct * p = new();
printf("%d\n", get_expensive(p));
printf("%d\n", get_expensive(p));
}
(1) Whether this is reasonable or a complete waste of resources (both programmer and computation) cannot be decided from your dummy example, though.

Forward declare to an array of pointers to structs screwing things up?

I have a struct named S and an array of pointers to structs S named A. My function T takes a pointer to struct S as an argument.
struct S *A; //forward declare array A of (pointers to) structs
...
void T(struct S *s){//function that accepts pointer to struct S
...
}
void otherFunction(){
...
T(A[i-1]); //Yields error Incompatible type for argument 1
}
int main(){
A = malloc(100 * sizeof(struct S*)); //initialize array
int i;
for(i = 0; i < NumBowls; i++){
A[i] = malloc(100 * sizeof(struct S));//initialize structs in array
}
otherFunction();
}
With a print statement, I was able to see that A[i-1] is of type struct S, but not pointer to S which is what I wanted. Could this because I forward declared A?
struct S *A; // this is a pointer of struct S type.
You need to declare
struct S **A; // pointer to pointer
or
struct S *A[MAX_SIZE]; //array of pointers
struct S *A;
to declare array of pointers you need to
struct S *A[10];
A[i] = malloc(sizeof(S));

c struct pointer issues

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.

Resources