Initialize a 2D array of unknown size using macros in C - c

I was working on a small macro project that requires me to pass a 2 dimensional array literal to one of my macros like so: myMacro({{0, 1, 2}, {2, 1, 0}}). Without having to pass the size of the array literal to the macro, is there a way to have it expand to the following: int[2][3] = { {0, 1, 2}, {2, 1, 0} } or something equivalent (any initialization that preserves the shape of the array will work)? Thanks in advance for any help

#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define VA(...) __VA_ARGS__
#define TRANS(r, data, elem) { VA elem},
#define myMacro(name, arg)\
int name[BOOST_PP_TUPLE_SIZE(arg)][BOOST_PP_TUPLE_SIZE(BOOST_PP_TUPLE_ELEM(0,arg))] = \
{ BOOST_PP_SEQ_FOR_EACH(TRANS, , BOOST_PP_VARIADIC_TO_SEQ arg)}
int main(){
myMacro(a, ((1,2,3),(4,5,6)) );//=>int a[2][3] = { { 1,2,3}, { 4,5,6}, };
return 0;
}

If you have an upper limit for the second dimension then you could use sentinel values such as:
#include <stdio.h>
#define MAXCOLUMNS 20
#define VALUE {{0,1,2,-1},{2,3,4,-1},{0,0,0,0,1,-1},{-1}}
int main()
{
int v[][MAXCOLUMNS] = VALUE;
int x, y;
for (y = 0; v[y][0] != -1; y++)
for (x = 0; v[y][x] != -1; x++)
printf("[%d,%d] = %d\n", x, y, v[y][x]);
return 0;
}
This will print out the values without knowing the exact dimensions beforehand. Is this something you are trying to achieve?
Edit: #BLUEPIXYs solution doesn't require knowing or guessing maximum dimensions, on the other hand this works with older C versions (not a big concern, though).

Related

struct and typedef initialization

I am not sure why I am not getting a display on the console for the value of maxProd. I think I am declaring the arr_integer array variable wrong in main?
I ran a couple tests and the program looks like it does not even get to call solution().
Any help would be greatly appreciated. I am trying to get this to work and get rid of the following warnings;
Adjacent_Element_Product.c:31:40: note: (near initialization for 'array')
Adjacent_Element_Product.c:31:43: warning: excess elements in struct initializer
#include <stdio.h>
typedef struct arr_integer {
int size;
int *arr;
} arr_integer;
arr_integer alloc_arr_integer(int len) {
arr_integer a = {len, len > 0 ? malloc(sizeof(int) * len) : NULL};
return a;
}
int solution(arr_integer inputArray) {
int maxProd = inputArray.arr[0] * inputArray.arr[1];
for (int i = 1; i < inputArray.size - 1; i++)
{
int product = inputArray.arr[i] * inputArray.arr[i + 1]; //multiple next door neighbours.
if (product > maxProd)
maxProd = product;
}
return printf("maxProd: %d\n", maxProd);
}
int main()
{
arr_integer array = {3, 6, -2, -5, 7, 3};
solution(array);
return 0;
}
The problem is that you don't allocate memory for the array and that it then tries to use the list of integers as an int*.
A possible remedy:
#define Size(x) (sizeof (x) / sizeof *(x))
int main() {
int ints[] = {3, 6, -2, -5, 7, 3};
arr_integer array = {.size = Size(ints), .arr = ints};
solution(array);
}
Here are the relevant changes:
added <stdlib.h> for malloc
eliminated alloc_arr_integer() which was not used
maxProd is initialized to INT_MIN and tweaked initial loop condition to reduce duplication
to make the solution a little smaller passing the value inline to solution (#TedLyngmo probably gave you a better solution)
Not fixed:
arr_integer doesn't seem to add any value so maybe just pass size and array to solution(). You could create a macro to initialize it using the approach #TedLyngmo shared with you. It has to be a macro as int [] degrades to int * in a function call, and the latter (silently?) gives you the wrong result which makes it error prune.
Does negative size make sense? If not then use an unsigned type.
What is the solution if size < 2?
solution() returns the value from printf() which is strange. You might want to return maxProd and have main() print out the value. This makes your function testable
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct arr_integer {
int size;
int *arr;
} arr_integer;
int solution(arr_integer inputArray) {
int maxProd = INT_MIN; // what is answer if size < 2? error?
for (int i = 0; i < inputArray.size - 1; i++) {
int product = inputArray.arr[i] * inputArray.arr[i + 1]; //multiple next door neighbours.
if (product > maxProd)
maxProd = product;
}
return printf("maxProd: %d\n", maxProd);
}
int main() {
solution((arr_integer) {
6,
(int []) { 3, 6, -2, -5, 7, 3 }
});
return 0;
}
and the output is:
maxProd: 21

Getting the size of varargs in C?

I am trying to convert some Java code into C. The Java code goes like this:
public static int minimum( int... minimum ) {
assert( minimum.length > 0 );
if ( minimum.length > 0 )
.... // some code that i am able to translate to C without any hassle
}
Now I understand how to have varargs in C by using the stdarg.h header and using the macros provided. However I am stuck doing the minimum.length part.
I have tried strlen but the terminal is giving me an incompatible integer to pointer conversion warning. Is there any way in C where I can replicate the same thing that Java does?
Not directly, as pointed out by #MichaelBurr, you need to pass the number of elements or use a sentinel.
An indirect way to do this is using compound literals:
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define minimum(...) fnminimum(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__)
static int fnminimum(int n, ...)
{
int num, min = INT_MAX;
va_list ap;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
if (num < min) {
min = num;
}
}
va_end(ap);
return min;
}
int main(void)
{
int a = 1;
printf("%d\n", minimum(2, 30, 7, a++, 4));
return 0;
}
Another (ugly) method using NARGS macros (limited to N args):
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define minimum(...) fnminimum(NARGS(__VA_ARGS__), __VA_ARGS__)
static int fnminimum(int n, ...)
{
int num, min = INT_MAX;
va_list ap;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
if (num < min) {
min = num;
}
}
va_end(ap);
return min;
}
int main(void)
{
printf("%d\n", minimum(2, 30, 7, 1, 4));
return 0;
}
Output:
1
There is no built-in way to get the number of vararg arguments passed in C.
You need to do one of the following:
pass in a count explicitly,
pass in a count implicitly (as printf() does via the number of conversion specifiers)
or use a sentinel value (such as NULL or 0) to indicate the end of the vararg list
I have seen schemes that use macros and the __VA_ARGS__ identifier to automatically place a sentinel at the end of the varargs list when calling a function.

Passing a two dimensional array to a function in C

#include <iostream>
#include <math.h>
#include <stdio.h>
#define column 3
#define row 3
#define share 3
int matrix_multiplication(int left_matrix[][column], int right_matrix[][column], int result_matrix[][column], int rows, int cols, int shared);
int A[][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
},
B[][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}, C[3][3]; //initialize "hard coded" three matrices
int main() {
matrix_multiplication(A, B, C, row, column, share); //passes address of each matrix to function
return 0;
}
int matrix_multiplication(int left_matrix[][column], int right_matrix[][column], int result_matrix[][column], int rows, int cols, int shared) {
int i, j, k;
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {//stays within first column and row through first iteration
for (k = 0; k < 3; k++)//ensures inner dimensions match with variable k i.e. ixk * kxj =ixj or A*B=C
result_matrix[i][j] += right_matrix[i][k] * left_matrix[k][j]; //C programming has ability to perform matrix multiplication
//Adds result of each operation to C matrix i.e. +=
printf("%d\t", result_matrix[i][j]); //matrix C is composed of rows(i) and columns(j)
}//new tab after each column iteration
printf("\n"); //new line for each row iteration
}
return 0;
}
This code is an good example of passing multidimensional arrays to a function using pointers and printing multidimensional arrays after mutliplication. There are multiple ways to indicate pointers to the compiler. I recommend seeing the "Correct way of passing a 2 dimensional array into a function." for example:
/*void display(int (*p)[numcols],int numRows,int numCols)//First method//
void dispaly(int *p,int numRows,int numCols) //Second Method//
void dispaly (int p[][numCols],int numRows,int numCols) //Third Method*/
Remove the column variable, and add this above the matrix_multiplication function declaration:
#define column 3
(You may also want to rename column to COLUMNS.)
In C++ you can also do this:
static const int column = 3;
or, in C++11:
constexpr int column = 3;
The idea behind all this is that all but the very first size of a multidimensional array must be known at compile time.
To fix the expected primary-expression before ']' token" error, change your inner assignment to something like this:
result_matrix[i][j] += right_matrix[i][k] * left_matrix[k][j];
Also you should initialize result_matrix with 0s first.
Also remove the * from int *result_matrix[][column].
Most modern compilers display warnings if you pass an int instead of an int*. Please enable all warnings in your compiler, recompile, fix them, and update your question stating that the example code compiles cleanly, without warnings.
To print an element of the matrix, you have to specify which element you want to print:
printf("%d\t", result_matrix[i][j]);
I can't believe that your compiler didn't display a warning when you omitted the [i][j]. Warnings are for your benefit: they indicate possible bugs in your code.

Why is this array notation illegal in C?

If this is possible:
#include <stdio.h>
#include <process.h>
#define SIZE 5
void PassingArray(int arr[])
{
int i=0;
for(i=0 ; i<SIZE ; i++)
{
printf("%d, ", arr[i]);
}
printf("\n");
}
main()
{
int myIntArray[5] = {1, 2, 3, 4, 5};
PassingArray(myIntArray);
system("PAUSE");
}
Then why the following is illegal?
#include <stdio.h>
#include <process.h>
#define SIZE 5
int ReturningArray()[]
{
int myIntArray[5] = {1, 2, 3, 4, 5};
return myIntArray;
}
main()
{
int myArray[] = ReturningArray();
system("PAUSE");
}
You're not returning an int, but you're returning the array. This is the same value as &myIntArray[0]. int ReturningArray()[] is not a valid function prototype.
There's multiple reasons why this doesn't work.
The first is simply that it's prohibited by the language - the return type of a function shall not be an array (it also can't be a function).
The second is that even if you were allowed to declare ReturningArray as you do, you could never write a valid return statement in that function - an expression with array type that is not the subject of the unary & or sizeof operators evaluates to a pointer to the first element of the array, which no longer has array type. So you can't actually make return see an array.
Thirdly, even if we somehow had a function returning an array type, you couldn't use that return value as the initialiser of an array variable - the return value would again evaluate to a pointer to the first element of the array: in this case a pointer to int, and a pointer to int isn't a suitable initialiser for an array of int.
There are several problems with this code.
You are placing the brackets at the wrong place. Instead of
int ReturningArray()[]
it should be
int* ReturningArray()
You are returning a local variable. Local variables only exist during the execution of the function and will be removed afterwards.
In order to make this work you will have to malloc the int array and return the pointer to the array:
#include <stdio.h>
#include <malloc.h>
#define SIZE 5
int* ReturningArray()
{
int *myIntArray = (int *)malloc(SIZE * sizeof(int));
myIntArray[0] = 1;
myIntArray[1] = 2;
myIntArray[2] = 3;
myIntArray[3] = 4;
myIntArray[4] = 5;
return myIntArray;
}
int main(void)
{
int i;
int* myArray = ReturningArray();
for(i=0;i<SIZE;i++) {
printf("%d\n", myArray[i]);
}
free(myArray); // free the memory again
system("PAUSE");
return 0;
}
PassingArray is legal, but it does not pass an array. It passes a pointer to the first element of an array. void PassingArray(int arr[]) is a confusing synonym for void PassingArray(int *arr). You can't pass an array by value in C.
ReturningArray is not allowed, you can't return an array by value in C either. The usual workaround is to return a struct containing an array:
typedef struct ReturnArray {
int contents[5];
} ReturnArray;
ReturnArray ReturningArray()
{
ReturnArray x = {{1, 2, 3, 4, 5}};
return x;
}
Arrays are second-class citizens in C, the fact that they can't be passed or returned by value is historically related to the fact that they can't be copied by assignment. And as far as I know, the reason for that is buried in the early development of C, long before it was standardized, when it wasn't quite decided how arrays were going to work.
You can't return array from a function, but It is possible that you can declare a function returning a (reference in C++) or pointer to array as follows:
int myIntArray[] = {1, 2, 3, 4, 5};
int (*ReturningArray())[sizeof(myIntArray)/sizeof(int)] {
return &myIntArray;
}

why does GCC "expect an expression"?

#define rows 2
#define cols 2
#define NUM_CORNERS 4
int main(void) {
int i;
int the_corners[NUM_CORNERS];
int array[rows][cols] = {{1, 2}, {3, 4}};
corners(array, the_corners);
for (i = 0; i < 4; i++) printf("%d\n", the_corners[i]);
}
int corners (int array[rows][cols], int the_corners[]) {
the_corners = {
array[0][cols-1],
array[0][0],
array[rows-1][0],
array[rows-1][cols-1]
};
}
I get these weird errors and i have no idea why:
prog.c: In function ‘main’:
prog.c:10: warning: implicit declaration of function ‘corners’
prog.c: In function ‘corners’:
prog.c:15: error: expected expression before
The the_corners = { ... } syntax is an array initialization, not an assignment. I don't have a copy of the standard handy so I can't quote chapter and verse but you want to say this:
void corners (int array[rows][cols], int the_corners[]) {
the_corners[0] = array[0][cols-1];
the_corners[1] = array[0][0];
the_corners[2] = array[rows-1][0];
the_corners[3] = array[rows-1][cols-1];
}
I also took the liberty of changing int corners to void corners as you weren't returning anything. And your main also needs a return value and you forgot to #include <stdio.h>.
You're trying to use an initialiser expression as an assignment. This isn't valid, even in C99, because the type of the_corners is int*, not int[4]. In this case you would be best off assigning each element individually.
The main doesn' know about your function. Either move the function decleration above the main or prototype it before the main:
int corners (int array[rows][cols], int the_corners[NUM_CORNERS]);
Try this one:
#include <stdio.h>
#define NROWS 2
#define NCOLUMNS 2
#define NCORNERS 4
int corners(int (*arr)[NCOLUMNS], int* the_corners);
int main() {
int i;
int the_corners[NCORNERS];
int arr[NCOLUMNS][NROWS] = {{1, 2}, {3, 4}};
corners(arr, the_corners);
for (i = 0; i < NCORNERS; i++)
printf("%d\n", the_corners[i]);
return 0;
}
int corners(int (*arr)[NCOLUMNS], int* the_corners) {
the_corners[0] = arr[0][NCOLUMNS-1];
the_corners[1] = arr[0][0];
the_corners[2] = arr[NROWS-1][0];
the_corners[3] = arr[NROWS-1][NCOLUMNS-1];
return 0;
}
You can read here about passing a 2D array to a function.

Resources