Nibor
Nibor

Reputation: 1258

Alternative way of using pointers to const data?

In my C99 program, I have a struct with pointers to floats (denoting a matrix). The struct goes through a set of routines, called from, say, main.

I'd like to make sure that the content of the structs (the actual values in the matrix) are unchanged by the called routines. The data should however be able to be changed from main.

I've come up with the following solution, where I define a pointer to const data:

struct math_object {
    const real_t *p_to_matrix;
};

Doing so, none of the called routines can change the underlying data pointed to by p_to_matrix.

At the very beginning of the program I allocate some memory pointed to by user_matrix, I initialize the values, and point p_to_matrix to user_matrix using this (kinda ugly) cast:

real_t *user_matrix;
... allocate memory ...
... initialize the data ...
math_object1.p_to_matrix = (const real_t *) user_matrix;

Then I only allow the user to change the values pointed to by user_matrix.

Is there a better/cleaner/safer way of passing data around that should be considered const by called routines, but where you need to change the same data now and again?

Upvotes: 0

Views: 86

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

One approach is to not let the users of your API see the structure of struct math_object at all, providing functions to interact with it instead. This way you would be able to keep the pointer non-const, and avoid casting altogether:

// This goes into the header file for your API
struct math_object; // Forward declaration
struct math_object* math_allocate(/* allocation parameters go here */);
void math_free(struct math_object* obj);
const real_t *math_get_matrix(struct math_object* obj);

You could prevent the user from seeing pointers to values, at the expense of making twice as many wrappers:

real_t math_get_matrix_val(struct math_object* obj, size_t row, size_t col);
void math_set_matrix_val(struct math_object* obj, size_t row, size_t col, real_t val);

Now you can define struct math_object inside your implementation with a non-const pointer, because the users of your API see only the header, so they have no access to the internals:

struct math_object {
    real_t *p_to_matrix;
};

I have 20+ matrices in a struct, so then the argument lists get very long.

You have two approaches to give API users access to the 20+ matrices:

  • Make 20+ API functions, one for each matrix - this approach works best when the matrices represent unrelated things, or
  • Make one function that takes matrix "number" or some other identifier - this works when matrices represent similar concepts, almost an array of matrices.

Upvotes: 1

Related Questions