If you’re working from outdated teaching materials, sure. Modern (C++11 and later) materials avoid error-prone C-isms like manual memory management, raw array indexing, pointers, and pointer arithmetic.
Depends on what you’re implementing, because there’s some things C is bad at (linear algebra, string parsing/manipulation). For linear algebra on real-time embedded systems (where VLAs, alloca(), and malloc() are disallowed after startup), your options are:
- LAPACK, which is notoriously hard to use and doesn’t keep track of matrix dimensions for you.
- A custom matrix library.
// Option 1: void*, type punning shenanigans, and in/out pointer args
#define DEF_MATRIX(R, C) \
typedef struct matrix ## R ## x ## C ## d { \
uint32_t rows; \
uint32_t cols; \
double data[R * C]; \
} matrix ## R ## x ## C ## d;
#define DEF_VECTOR(R) \
DEF_MATRIX(R, 1); \
typedef matrix ## R ## x1d vector ## R ## d;
DEF_MATRIX(2, 2);
DEF_VECTOR(2);
void matrix_plus(void* out, const void* in1, const void* in2) {
uint32_t* rows = (uint32_t*) out;
uint32_t* cols = (uint32_t*) ((char*) out + sizeof(uint32_t));
double* out_data = (double*) ((char*) out + 2 * sizeof(uint32_t));
// ...
}
void matrix_mult(void* out, const void* in1, const void* in2) {
// ...
}
int main() {
matrix2x2d A = {2, 2, {}};
matrix2x2d B = {2, 2, {}};
vector2d x = {2, 1, {}};
vector2d u = {2, 1, {}};
// xₖ₊₁ = Axₖ + Buₖ
vector2d temp1 = {2, 1, {}};
vector2d temp2 = {2, 1, {}};
matrix_mult(&temp1, &A, &x);
matrix_mult(&temp2, &B, &u);
matrix_plus(&x, &temp1, &temp2);
}
// Option 2: Separate functions for every dimension combo
// (makes extra copies, which isn't ideal)
#define DEF_MATRIX(R, C) \
typedef struct matrix ## R ## x ## C ## d { \
double data[R * C]; \
} matrix ## R ## x ## C ## d;
#define DEF_VECTOR(R) \
DEF_MATRIX(R, 1); \
typedef matrix ## R ## x1d vector ## R ## d;
DEF_MATRIX(2, 2);
DEF_VECTOR(2);
matrix2x1d matrix_plus_2x1_2x1(matrix2x1d in1, matrix2x1d in2) {
matrix2x1d result = {};
return result;
}
matrix2x1d matrix_mult_2x2_2x1(matrix2x2d in1, matrix2x1d in2) {
matrix2x1d result = {};
return result;
}
int main() {
matrix2x2d A = {};
matrix2x2d B = {};
vector2d x = {};
vector2d u = {};
// xₖ₊₁ = Axₖ + Buₖ
x = matrix_plus_2x1_2x1(
matrix_mult_2x2_2x1(A, x),
matrix_mult_2x2_2x1(B, u)
);
}
Neither of these approaches scale well, and it’s hard to verify the correctness of equation transcriptions compared to C++.
#include <Eigen/Core>
int main() {
Eigen::Matrix<double, 2, 2> A;
Eigen::Matrix<double, 2, 2> B;
Eigen::Vector<double, 2> x;
Eigen::Vector<double, 2> u;
// xₖ₊₁ = Axₖ + Buₖ
x = A * x + B * u;
}
C11 got generics, but they don’t support non-type parameters.