I am currently in the process of building a somewhat complex tool for data analysis in C (speed purposes mainly). I have to therefore look at multiple, different arrays (1D & 2D) in the process of bugfixing.
I am currently in the process of trying to build a function which allows me to do this with ease, by printing the data of an array with labels.
Below my improvement wishes, I have added my current code with which I am not content.
In a perfect world:
- I would not have to differentiate between 1D & 2D Arrays,
- (hence) I would not have to input the dimensions of the arrays (this would be done automatically through a e.g. sizeof() function - I have faced the issue that one dimension (columns) has to be defined in the function header (is there a workaround for this?),
- the name of the array to be printed (which will be entered as
data[][]
, see below) is printed above the data, so I know which array is which.
Code:
void print2d(int num_row, int num_col, double data[num_row][num_col])
{
printf("-----------------------------\n");
printf("Rows: %i, Cols: %i\n", num_row, num_col);
for (int r = 0; r <num_row; r )
{
for(int c=0; c<num_col; c )
{
printf("%lf ", data[r][c]);
}
printf("\n");
}
printf("-----------------------------\n");
return;
}
void print1d(int num_row, double data[num_row])
{
printf("-----------------------------\n");
printf("Rows: %i\n", num_row);
for (int r = 0; r <num_row; r )
printf("%lf\n", data[r]);
printf("-----------------------------\n");
return;
}
I would be more than deligted to recieve help or guidance on this question!
Thank you very much in advance!!
CodePudding user response:
As @AllanWind wrote, a 1D array is a 2D array with only one column.
And, for instance, a 4x5 array can be accessed as if it were a 20x1 array.
You don't need two... This single print function would serve...
void printArr( int num_row, int num_col, double *data ) {
char *bars = "-----------------------------\n";
puts( bars );
printf( "Rows: %i, Cols: %i\n", num_row, num_col );
for( int r = 0; r < num_row; r ) {
for( int c = 0; c < num_col; c )
printf( "%lf ", *data );
printf("\n");
}
puts( bars );
}
If it helps, imagine numbering the squares of a chess board from 0 to 63...
Closer to living in a perfect world
CodePudding user response:
You can use a macro to preprocess the array to pass its dimension(s) and name to a function. This will work only with an actual array argument to the macro, not a pointer:
#include <stddef.h>
#include <stdio.h>
static void PrintArray(
size_t N0, const double Array[N0], const char *Name)
{
printf("%s is:\n", Name);
for (size_t n0 = 0; n0 < N0; n0)
printf(" %7g", Array[n0]);
putchar('\n');
}
static void PrintMatrix(
size_t N0, size_t N1, const double Matrix[N0][N1], const char *Name)
{
printf("%s is:\n", Name);
for (size_t n0 = 0; n0 < N0; n0, putchar('\n'))
for (size_t n1 = 0; n1 < N1; n1)
printf(" %7g", Matrix[n0][n1]);
}
#define PrintMatrix(Matrix) \
PrintMatrix( \
sizeof (Matrix) / sizeof *(Matrix), \
sizeof *(Matrix) / sizeof **(Matrix), \
(Matrix), \
#Matrix)
#define PrintArray(Array) \
PrintArray( \
sizeof (Array) / sizeof *(Array), \
(Array), \
#Array)
int main(void)
{
double MyArray[] = { 1, 2, 3, 4, 5 };
double MyMatrix[3][4] =
{
{ 11, 12, 13, 14 },
{ 21, 22, 23, 24 },
{ 31, 32, 33, 34 },
};
PrintArray(MyArray);
PrintMatrix(MyMatrix);
}
Sample output:
MyArray is: 1 2 3 4 5 MyMatrix is: 11 12 13 14 21 22 23 24 31 32 33 34
Here is a messy way to write a macro that will accept either an array or a matrix.
#include <stddef.h>
#include <stdio.h>
static void PrintArray(
size_t N0, const double Array[N0], const char *Name)
{
printf("%s is:\n", Name);
for (size_t n0 = 0; n0 < N0; n0)
printf(" %7g", Array[n0]);
putchar('\n');
}
static void PrintMatrix(
size_t N0, size_t N1, const double Matrix[N0][N1], const char *Name)
{
printf("%s is:\n", Name);
for (size_t n0 = 0; n0 < N0; n0, putchar('\n'))
for (size_t n1 = 0; n1 < N1; n1)
printf(" %7g", Matrix[n0][n1]);
}
// Compute the number of elements in an array.
#define NumberOf(X) (sizeof (X) / sizeof *(X))
/* If X is an array (converted to a pointer), produce a matrix ("double
[1][1]") so that the use of NumberOf will work. Otherwise, it should be
a matrix, and we can just produce it.
*/
#define Proxy(X) _Generic((X), double *: (double [][1]) {{0}}, default: (X))
/* If X is an array (converted to a pointer), call PrintArray, passing it the
number of elements, the array, and the name of the array.
Otherwise, X should be a matrix, and we pass it to PrintMatrix, passing it
the number of elements in the first dimension, the number of elements in
the second dimension, the array, and the name of the array.
The arrays are converted to "const void *" to avoid warnings due to passing
an array for a matrix and vice-versa. Although the _Generic selects one
of the expressions, both must satisfy the compiler, and, without the
conversion, the argument type will not match the parameter type in the
unselected expression.
*/
#define Print(X) \
_Generic((X), \
double *: PrintArray(NumberOf(X), (const void *) (X), #X), \
default: PrintMatrix(NumberOf(X), NumberOf(*Proxy(X)), (const void *) (X), #X))
int main(void)
{
double MyArray[] = { 1, 2, 3, 4, 5 };
double MyMatrix[3][4] =
{
{ 11, 12, 13, 14 },
{ 21, 22, 23, 24 },
{ 31, 32, 33, 34 },
};
Print(MyArray);
Print(MyMatrix);
}