Syntax for VLAs as a function parameter - c

I wrote the naivest matrix multiplication code to complete my understanding to C99 VLAs. What confuses me a bit is when I declare a pointer to a VLA in the argument list at function definition.
For example, in fill_matrix_randomly, the argument m declared as double (*m)[n_cols] compiles fine as it should. double (*m)[*] is a compile error because [*] can only appear in the declaration. double (*m)[] is also an error because I cannot access an array of incomplete type. Nothing weird until now, but. double (*m)[n_rows] compiles fine and even runs fine? double (*m)[1] or double (*m)[2] works too, and I got really confused here. Help me be less confused.
#include <stdio.h>
#include <stdlib.h>
static void fill_matrix_randomly(int, int, double (*)[*]);
static void print_matrix(int, int, double (*)[*]);
static void multiply_matrices(int, int, int, double (*restrict)[*],
double (*restrict)[*], double (*restrict)[*]);
int main(void) {
const int a = 1, b = 3, c = 5;
double m[a][c], m2[a][b], m3[b][c];
fill_matrix_randomly(a, b, m2);
fill_matrix_randomly(b, c, m3);
multiply_matrices(a, b, c, m, m2, m3);
print_matrix(a, b, m2);
print_matrix(b, c, m3);
print_matrix(a, c, m);
}
static void fill_matrix_randomly
(int n_rows, int n_cols, double (*m)[n_cols]) {
for (int i = 0; i < n_rows; ++i) {
for (int j = 0; j < n_cols; ++j) {
m[i][j] = (double)rand() / RAND_MAX + 1;
}
}
}
static void print_matrix(int n_rows, int n_cols, double (*m)[n_cols]) {
for (int i = 0; i < n_rows; ++i) {
printf("[ ");
for (int j = 0; j < n_cols; ++j) {
printf("%.3f", m[i][j]);
if (j != n_cols - 1) {
printf(", ");
} else {
printf(" ]\n");
}
}
}
putchar('\n');
}
static void multiply_matrices
(int n, int m, int p, double (*restrict r)[p],
double (*restrict a)[m], double (*restrict b)[p]) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < p; ++j) {
double sum = 0;
for (int k = 0; k < m; ++k) {
sum += a[i][k] * b[k][j];
}
r[i][j] = sum;
}
}
}

double (*m)[n_rows] compiles fine and even runs fine
If you declared your function parameter with type double (*)[n_rows], but passed an argument of type double (*)[n_columns], and n_rows is different from n_columns, then the behavior is undefined.
The same applies to double (*m)[1] and double (*m)[2] variants.
Parameter passing requires parameter type to be compatible with argument type. In case of pointers to arrays, the pointers have to point to compatible array types. In your case the following applies
6.7.5.2 Array declarators
6 For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are
integer constant expressions, then both size specifiers shall have the
same constant value. If the two array types are used in a context
which requires them to be compatible, it is undefined behavior if the
two size specifiers evaluate to unequal values.
Obviously, nobody can reasonably expect such violations to be caught at compile time, since the compiler generally cannot predict and enforce run-time relationships (VLA sizes) at compile time.
After committing this violation (which by itself is sufficient to trigger UB), you proceed to commit another one by performing out of bounds access to your array inside fill_matrix_randomly.
As for running it... where you got the idea that the code with double (*m)[n_rows] "runs fine" is not clear to me. A quick experiment shows that lying like that to the compiler results in either improperly filled array, if you are lucky
http://coliru.stacked-crooked.com/a/6032864f2baa2eae
or a crash if you are not so lucky
http://coliru.stacked-crooked.com/a/7ba1002e3150bd1c

The definition:
static void print_matrix(int n_rows, int n_cols, double (*m)[n_cols]) {
…
}
says that m is a pointer to an array where each element of the array has n_cols columns. This is perfectly kosher.
The options with a constant row size (double (*m)[1] or double (*m)[2]) work as well as the one with variable row size.
You might also care to note that this minor variant on your code also compiles and runs and (because there is no seeding of the random number generator) produces the same answer:
#include <stdio.h>
#include <stdlib.h>
static void fill_matrix_randomly(int, int, double[*][*]);
static void print_matrix(int, int, double[*][*]);
static void multiply_matrices(int, int, int, double[*][*],
double[*][*], double[*][*]);
int main(void)
{
const int a = 1, b = 3, c = 5;
double m[a][c], m2[a][b], m3[b][c];
fill_matrix_randomly(a, b, m2);
fill_matrix_randomly(b, c, m3);
multiply_matrices(a, b, c, m, m2, m3);
print_matrix(a, b, m2);
print_matrix(b, c, m3);
print_matrix(a, c, m);
}
static void fill_matrix_randomly(int n_rows, int n_cols, double m[n_rows][n_cols])
{
for (int i = 0; i < n_rows; ++i)
{
for (int j = 0; j < n_cols; ++j)
m[i][j] = (double)rand() / RAND_MAX + 1;
}
}
static void print_matrix(int n_rows, int n_cols, double m[n_rows][n_cols])
{
for (int i = 0; i < n_rows; ++i)
{
printf("[ ");
for (int j = 0; j < n_cols; ++j)
{
printf("%.3f", m[i][j]);
if (j != n_cols - 1)
printf(", ");
else
printf(" ]\n");
}
}
putchar('\n');
}
static void multiply_matrices(int n, int m, int p, double r[n][p],
double a[n][m], double b[m][p])
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < p; ++j)
{
double sum = 0;
for (int k = 0; k < m; ++k)
sum += a[i][k] * b[k][j];
r[i][j] = sum;
}
}
}

You are required to specify the sizes of all but the first dimension. This is because multidimensional arrays are stored in contiguous memory locations, so the dimensions are needed to compute the actual offset from the starting address to find each element in the first dimension.
Your two-dimensional array has rows and columns (in a high-level sense). It might look like this in memory:
Row 0 | 1 | 2 ...
+----+----+----|----+----+----|----+----+
| | | | | | | | | ...
+----+----+----|----+----+----|----+----+
Col 0 1 2 | 0 1 2 | 0 1
An array access in the form of array[i][j] is equivalent to an addition and dereference of the pointer array: *(*(array + i) + j).
array + i is used to offset you to row number i (and dereferenced to give you the array held there), and j is used to take you a bit further to the jth element in that row. It is clear that to get you the correct row offset, the compiler has to know the size of each row.
In the example above, for instance, the compiler needs to know to skip 3 memory locations/units of data to advance from row to row.
The more complete formula is as follows (note that the compiler does this expansion automatically):
*((array + (i * #cols/row * sizeof(array elem))
+ (j * sizeof(array elem)))
It's clear to see that what needs to be known ahead of time is sizeof(array elem) and #cols/row.
The sizeof(array elem) is known since you specify the base type being stored in your multidimensional array (in your case, double). But the #cols/row has to be specified by the programmer in order for the compiler to compute offsets correctly.
In all your examples of working code, you are giving it a concrete value of columns contained in each row. However, in all of them, you will get unexpected behavior, because your array of a specific size is being treated as an array of a different size. By specifying incorrect or mismatched sizes, you are invoking undefined behavior since there is fundamentally a mismatch of type in the parameter and the argument provided. You declared the 2D array with x columns but are passing it as an array with y columns.
Declaring an array whose second dimension is 3 and passing it to a function that accepts an array with second dimension 2 looks like this, where the same memory is interpreted in two different ways:
Row 0 | 1 | 2 ...
+----+----+----|----+----+----|----+----+
| | | | | | | | | ...
+----+----+----|----+----+----|----+----+
Col 0 1 2 | 0 1 2 | 0 1
Row 0 | 1 | 2 | 3 ...
+----+----|----+----|----+----|----+----+
| | | | | | | | | ...
+----+----|----+----|----+----|----+----+
Col 0 1 | 0 1 | 0 1 | 0 1
You can see that accessing array[1][0] gives you two completely different results, the first being the expected result and the second being the result rendered due to type mismatch.

Related

How many pointers are in an array of pointers

I dynamically allocated memory for 3D array of pointers. My question is how many pointers do I have? I mean, do I have X·Y number of pointers pointing to an array of double or X·Y·Z pointers pointing to a double element or is there another variant?
double*** arr;
arr = (double***)calloc(X, sizeof(double));
for (int i = 0; i < X; ++i) {
*(arr + i) = (double**)calloc(Y, sizeof(double));
for (int k = 0; k < Y; ++k) {
*(*(arr+i) + k) = (double*)calloc(Z, sizeof(double));
}
}
The code you apparently intended to write would start:
double ***arr = calloc(X, sizeof *arr);
Notes:
Here we define one pointer, arr, and set it to point to memory provided by calloc.
Using sizeof (double) with this is wrong; arr is going to point to things of type double **, so we want the size of that. The sizeof operator accepts either types in parentheses or objects. So we can write sizeof *arr to mean “the size of a thing that arr will point to”. This always gets the right size for whatever arr points to; we never have to figure out the type.
There is no need to use calloc if we are going to assign values to all of the elements. We can use just double ***arr = malloc(X * sizeof *arr);.
In C, there is no need to cast the return value of calloc or malloc. Its type is void *, and the compiler will automatically convert that to whatever pointer type we assign it to. If the compiler complains, you are probably using a C++ compiler, not a C compiler, and the rules are different.
You should check the return value from calloc or malloc in case not enough memory was available. For brevity, I omit showing the code for that.
Then the code would continue:
for (ptrdiff_t i = 0; i < X; ++i)
{
arr[i] = calloc(Y, sizeof *arr[i]);
…
}
Notes:
Here we assign values to the X pointers that arr points to.
ptrdiff_t is defined in stddef.h. You should generally use it for array indices, unless there is a reason to use another type.
arr[i] is equivalent to *(arr + i) but is generally easier for humans to read and think about.
As before sizeof *arr[i] automatically gives us the right size for the pointer we are setting, arr[i].
Finally, the … in there is:
for (ptrdiff_t k = 0; k < Y; ++k)
arr[i][k] = calloc(Z, sizeof *arr[i][k]);
Notes:
Here we assign values to the Y pointers that arr[i] points to, and this loop is inside the loop on i that executes X times, so this code assigns XY pointers in total.
So the answer to your question is we have 1 + X + XY pointers.
Nobody producing good commercial code uses this. Using pointers-to-pointers-to-pointers is bad for the hardware (meaning inefficient in performance) because the processor generally cannot predict where a pointer points to until it fetches it. Accessing some member of your array, arr[i][j][k], requires loading three pointers from memory.
In most C implementations, you can simply allocate a three-dimensional array:
double (*arr)[Y][Z] = calloc(X, sizeof *arr);
With this, when you access arr[i][j][k], the compiler will calculate the address (as, in effect, arr + (i*Y + j)*Z + k). Although that involves several multiplications and additions, they are fairly simple for modern processors and are likely as fast or faster than fetching pointers from memory and they leave the processor’s load-store unit free to fetch the actual array data. Also, when you are using the same i and/or j repeatedly, the compiler likely generates code that keeps i*Y and/or (i*Y + j)*Z around for multiple uses without recalculating them.
Well, short answer is: it is not known.
As a classic example, keep in mind the main() prototype
int main( int argc, char** argv);
argc keeps the number of pointers. Without it we do not know how many they are. The system builds the array argv, gently updates argc with the value and then launches the program.
Back to your array
double*** arr;
All you know is that
arr is a pointer.
*arr is double**, also a pointer
**arr is double*, also a pointer
***arr is a double.
What you will get in code depends on how you build this. A common way if you need an array of arrays and things like that is to mimic the system and use a few unsigned and wrap them all with the pointers into a struct like
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
A CSV file for example is char ** **, a sheet workbook is char ** ** ** and it is a bit scary, but works. For each ** a counter is needed, as said above about main()
A C example
The code below uses arr, declared as double***, to
store a pointer to a pointer to a pointer to a double
prints the value using the 3 pointers
then uses arr again to build a cube of X*Y*Z doubles, using a bit of math to set values to 9XY9.Z9
the program uses 2, 3 and 4 for a total of 24 values
lists the full array
list the first and the very last element, arr[0][0][0] and arr[X-1][Y-1][Z-1]
frees the whole thing in reverse order
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
int print_array(double***, int, int, int);
int main(void)
{
double sample = 20.21;
double* pDouble = &sample;
double** ppDouble = &pDouble;
double*** arr = &ppDouble;
printf("***arr is %.2ff\n", ***arr);
printf("original double is %.2ff\n", sample);
printf("*pDouble is %.2ff\n", *pDouble);
printf("**ppDouble is %.2ff\n", **ppDouble);
// but we can build a cube of XxYxZ doubles for arr
int X = 2;
int Y = 3;
int Z = 4; // 24 elements
arr = (double***)malloc(X * sizeof(double**));
// now each arr[i] must point to an array of double**
for (int i = 0; i < X; i += 1)
{
arr[i] = (double**)malloc(Y * sizeof(double*));
for (int j = 0; j < Y; j += 1)
{
arr[i][j] = (double*)malloc(Z * sizeof(double));
for (int k = 0; k < Z; k += 1)
{
arr[i][j][k] = (100. * i) + (10. * j) + (.1 * k) + 9009.09;
}
}
}
print_array(arr, X, Y, Z);
printf("\n\
Test: first element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n\
last element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n",
0, 0, 0, arr[0][0][0],
(X-1), (Y-1), (Z-1), arr[X-1][Y-1][Z-1]
);
// now to free this monster
for (int x = 0; x < X; x += 1)
{
for (int y = 0; y < Y; y += 1)
{
free(arr[x][y]); // the Z rows
}
free(arr[x]); // the plane Y
}
free(arr); // the initial pointer;
return 0;
}; // main()
int print_array(double*** block, int I, int J, int K)
{
for (int a = 0; a < I; a += 1)
{
printf("\nPlane %d\n\n", a);
for (int b = 0; b < J; b += 1)
{
for (int c = 0; c < K; c += 1)
{
printf("%6.2f ", block[a][b][c]);
}
printf("\n");
}
}
return 0;
}; // print_array()
The output
***arr is 20.21f
original double is 20.21f
*pDouble is 20.21f
**ppDouble is 20.21f
Plane 0
9009.09 9009.19 9009.29 9009.39
9019.09 9019.19 9019.29 9019.39
9029.09 9029.19 9029.29 9029.39
Plane 1
9109.09 9109.19 9109.29 9109.39
9119.09 9119.19 9119.29 9119.39
9129.09 9129.19 9129.29 9129.39
Test: first element is arr[0][0[0] = 9009.09 (9XY9.Z9)
last element is arr[1][2[3] = 9129.39 (9XY9.Z9)

Passing arrays to functions without using pointers

C allows passing arrays to functions using the array name directly. Since the array name is the starting address of the array (address of element [0]) - this is passing by reference - hence even local array can be passed this way - and the changes of either function will be visible to the other without any need of explicit return.
What I understand so far is -
The function call just needs to include the name of the array which provides the starting address - and the integer size of each dimension as separate int arguments - this way any function other than the function that contains array definition - has all the information of arrays location and size (array size as well as size of each dimension) and can operate on any element. Once again, since this is pass by reference, any such change will be visible to all such functions including and from the one containing array definition (it will need to pass the same information as arguments to each function - the array name for starting address and each dimension size) , without any return required specifically for these changes to be visible to all functions including the calling function.
The array argument in the function prototype and function definition specifies the array with a pair of square braces for each dimension + in the same argument - the largest ? value for each dimension except the most significant one (rows in a 2-D array) is also specified eg -
//Prototype
return_type function_name ( array_name[][MAX_COLS], int rows, int cols);
// Function call somewhere
function_name (array_name, num_rows, num_columns); /* array name refers
to starting address */
Also for the dimensions for which the largest ? value is specified in prototype and definition (MAX_COLS for our example), the actual value during call, specified as a separate argument (cols), may and will mostly be different.
I do not know why the size is required for other dimensions (MAX_COLS) and it will be very kind of someone to explain. Also please correct, confirm, improve everything as necessary.
Example Code with 1-D array of pointers to model a 2-D array -
#define MAX_ROWS 20
extern void modify( int rows, int cols, int *a[]);
extern void input_2d_array(int rows, int cols, int *a[]);
extern void output_2d_array(int rows, int cols, int *a[]);
int main()
{
int rows = 4, cols = 3;
int* a[MAX_ROWS], i;
for (i=0; i<rows; i++)
a[i] = (int*) malloc ( cols*sizeof(int) );
input_2d_array(rows, cols, a);
printf("Initially in main array = \n");
output_2d_array(rows, cols, a);
modify(rows, cols, a);
printf("Finally in main array = \n");
output_2d_array(rows, cols, a);
_getch();
return 0;
}
void input_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
{
printf("Please enter the elements for row %d and column %d of a \n", i + 1, j + 1);
scanf_s(" %d", (a+(i*cols)+j) );
}
return;
}
void output_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
printf(" %d", *(a + (i*cols) + j) );
}
printf("\n");
}
return;
}
void modify(int rows, int cols, int *a[])
{
int i, j;
printf("Initally in modify array = \n");
output_2d_array(rows, cols, a);
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
*(a + (i*cols) + j) = (*(a + (i*cols) + j)) + 2;
// *(*(a + i) + j) += 2; // Gives exception
// *(a[i]+j) += 10; // Gives exception
}
}
printf("Finally in modify array = \n");
output_2d_array(rows, cols, a);
return;
}
There are some misunderstandings. It is going to take time to explain them.
Fixed width arrays
Your example prototype is (more or less):
//Prototype
ReturnType function_name(ArrayType array_name[][MAX_COLS], int rows, int cols);
Somewhere, you have a constant definition for MAX_COLS; for sake of argument, it can be:
enum { MAX_COLS = 64 };
This function only accepts arrays that have MAX_COLS columns, though the arrays can have any number of rows. The int cols argument is immaterial to this array's definition. In the calling code, the array must be defined with MAX_COLS (or its equivalent) as the second dimension.
Inside the function, the compiler will interpret a reference array_name[i][j] (i and j being integer types) as:
*(array_name + (i * MAX_COLS + j))
It will never use cols in that calculation. An attempt to pass an array with a different row width to the function leads to — I'm going to call it 'undefined behaviour', though there might strictly be a different interpretation for which sort of undesirable and incompletely specified behaviour is applicable. The result is not going to be what you expect. If you pass a narrower array, you may well index out of bounds of the actual array; if you pass a wider array, you probably won't run out of bounds, but (as when accessing out of bounds), you won't be accessing the elements you expect to access because the computation will be based on MAX_COLS, not the function argument cols.
Variable length arrays
Using a variable length array (VLA), you could revise your function to:
ReturnType function_name(int rows, int cols, ArrayType array_name[rows][cols]);
Note that the size variables must be defined before they are used; the size parameters must precede their use in an array definition.
Now, inside the function, the compiler will interpret array_name[i][j] (as before) as:
*(array_name + (i * cols + j))
You can pass any shape of array as long as you get the rows and cols parameters correct.
There are a variety of other notations that could be used in the prototype for the function taking a VLA, including these:
ReturnType function_name(int rows, int cols, ArrayType array_name[*][*]);
ReturnType function_name(int rows, int cols, ArrayType array_name[][*]);
However, the function definition would need to have cols appear before the array definition:
ReturnType function_name(int rows, int cols, ArrayType array_name[rows][cols]) { … }
ReturnType function_name(int rows, int cols, ArrayType array_name[][cols]) { … }
And with the 'unsized' leading dimension, you could (if you were perverse enough) write:
ReturnType function_name(int cols, ArrayType array_name[][*], int rows);
ReturnType function_name(int cols, ArrayType array_name[][cols], int rows) { … }
My own view is that it is simpler to maintain the code if the function prototype declaration exactly matches the function definition line, so I'd not use the notations with * in the prototypes. I'd also use the explicit ArrayType array_name[rows][cols] notation, indicating which parameter specifies each size. This matters if you do a matrix multiplication function, for example:
void MatrixMultiply(int r1, int c1, int c2,
Data m1[r1][c1], Data m2[c1][c2], Data result[r1][c2]);
Whether the compiler will report problems with matrix size mismatches is open to debate, but the opportunity is there. If you prefer, you could have a redundant r2 parameter to specify the row size of the m2 matrix, but then you've got problems if r2 != c1, and it is harder for the compiler to help — you're reduced to assertions or other error reporting mechanisms to indicate that nothing useful was done to the result because the matrix sizes were not compatible for multiplication.
I'm not sure whether I've deconstructed all the misunderstandings in your question; I suspect not.
Arrays of pointers vs 2D arrays
From a comment:
If my function signature is void modify(int rows, int cols, int *a[]) then how do I access a[i][j] and &a[i][j] in the called function?
This requires an array of pointers to int, so you have to set up the array differently from before (in the calling code). However, inside the function,
you simply write:
int x = a[i][j];
int *y = &a[i][j];
int *z = a[i] + j;
The expressions for y and z are equivalent; I'd probably use the former.
Note that the 'behind the scenes' calculation for x is different here from the formula used for a[i][j] when passing an array:
int x = *(*(a + i) + j);
There are two memory references, the first to read the pointer a[i], and the second to read a[i][j] (with two explicit additions but no explicit multiplication, though the subscript additions have to be scaled by the size of int * and int), whereas with the array notation, there was only one memory reference (with two explicit additions and one explicit multiplication — and only one scaling operation by the size of int).
The same comment also says:
I tried a[i]+j and (a[i]+j) combination as well as *(a+(i*cols)+j) and (a+(i*cols)+j) and none is working.
There's a good chance I've not managed to add * symbols in the right places, especially in the 'as well as' portion of the sentence. Please provide the correct notation in a new extra (or replacement) comment, and I can dissect what you actually typed rather than what I'm guessing you typed.
The value of a[i] + j should give you a pointer to the jth integer in the ith row of the data. You'd have to wrap that as *(a[i] + j) to get the int value. The parenthesized version also gives you the pointer to element a[i][j]; you need a * in front to get the value.
The variations like *(a+(i*cols)+j) are wrong because in this context, you do not need to multiply by the number of columns. There's no requirement the consecutive rows pointed at by a[i] and a[i+1] are contiguous in memory; they could be located in multiple disjoint blocks of memory (and in fact there could be multiple pointers to a single block of memory, too). Within a row, the elements must be contiguous, of course.
It's roughly the difference between int a[][4]:
+---+---+---+---+
| 2 | 3 | 5 | 7 |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
| 7 | 5 | 3 | 2 |
+---+---+---+---+
| 9 | 8 | 7 | 6 |
+---+---+---+---+
and int *a[]:
+------------+ +---+---+---+---+
| 0x010C0304 |------>| 2 | 3 | 5 | 7 |
+------------+ +---+---+---+---+
| 0x020D0408 |------>| 1 | 2 | 3 | 4 |
+------------+ +---+---+---+---+
| 0x030E050C |------>| 7 | 5 | 3 | 2 |
+------------+ +---+---+---+---+
| 0x040F0600 |------>| 9 | 8 | 7 | 6 |
+------------+ +---+---+---+---+
Note that more storage is required to hold the int *a[] data than int a[][4].
Also note that I've made the 4 arrays of numbers in the int *a[] non-contiguous. Also, the rows in the int *a[] example could be of different lengths, provided you know how to access the length (or the lengths are all at least 4 and you don't go beyond the fourth element).
Adapting the MCVE from the question
As I said in the previous section, when you are using an 'array of pointers' notation, using cols in the subscript calculation is wrong. Here's an adaptation of your code — I've had to remove the Windows-specific features such as _getch() and scanf_s() (using 'nothing' and scanf() instead). I've also shown some alternatives; the printing shows some of the alternatives.
#include <stdio.h>
#include <stdlib.h>
#define MAX_ROWS 20
extern void modify(int rows, int cols, int *a[]);
extern void input_2d_array(int rows, int cols, int *a[]);
extern void output_2d_array(int rows, int cols, int *a[]);
int main(void)
{
int rows = 4, cols = 3;
int *a[MAX_ROWS], i;
for (i = 0; i < rows; i++)
a[i] = (int *)malloc(cols * sizeof(int));
input_2d_array(rows, cols, a);
printf("Initially in main array =\n");
output_2d_array(rows, cols, a);
modify(rows, cols, a);
printf("Finally in main array =\n");
output_2d_array(rows, cols, a);
//_getch();
return 0;
}
void input_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
printf("Please enter the elements for row %d and column %d of a\n", i + 1, j + 1);
//scanf_s(" %d", (a + (i * cols) + j));
//scanf(" %d", (a + (i * cols) + j));
scanf(" %d", &a[i][j]);
//scanf(" %d", a[i] + j);
//scanf(" %d", *(a + i) + j);
}
}
}
void output_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
//printf(" %d", *(a + (i * cols) + j));
printf(" %d", a[i][j]);
printf(" (%d)", *(*(a + i) + j));
}
printf("\n");
}
}
void modify(int rows, int cols, int *a[])
{
int i, j;
printf("Initally in modify array =\n");
output_2d_array(rows, cols, a);
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
a[i][j] = a[i][j] + 2;
*(a[i] + j) = *(*(a + i) + j) + 2;
//*(a + (i * cols) + j) = (*(a + (i * cols) + j)) + 2;
// *(*(a + i) + j) += 2; // Gives exception
// *(a[i]+j) += 10; // Gives exception
}
}
printf("Finally in modify array =\n");
output_2d_array(rows, cols, a);
}
Example run (program mda17):
$ mda17
Please enter the elements for row 1 and column 1 of a
23
Please enter the elements for row 1 and column 2 of a
24
Please enter the elements for row 1 and column 3 of a
25
Please enter the elements for row 2 and column 1 of a
26
Please enter the elements for row 2 and column 2 of a
27
Please enter the elements for row 2 and column 3 of a
28
Please enter the elements for row 3 and column 1 of a
99
Please enter the elements for row 3 and column 2 of a
98
Please enter the elements for row 3 and column 3 of a
97
Please enter the elements for row 4 and column 1 of a
96
Please enter the elements for row 4 and column 2 of a
95
Please enter the elements for row 4 and column 3 of a
94
Initially in main array =
23 (23) 24 (24) 25 (25)
26 (26) 27 (27) 28 (28)
99 (99) 98 (98) 97 (97)
96 (96) 95 (95) 94 (94)
Initally in modify array =
23 (23) 24 (24) 25 (25)
26 (26) 27 (27) 28 (28)
99 (99) 98 (98) 97 (97)
96 (96) 95 (95) 94 (94)
Finally in modify array =
27 (27) 28 (28) 29 (29)
30 (30) 31 (31) 32 (32)
103 (103) 102 (102) 101 (101)
100 (100) 99 (99) 98 (98)
Finally in main array =
27 (27) 28 (28) 29 (29)
30 (30) 31 (31) 32 (32)
103 (103) 102 (102) 101 (101)
100 (100) 99 (99) 98 (98)
$
Check this and try to find if array is passed as an array or a pointer to some function:
char arr[]={'a','b','c'};
int sizeOfArr = sizeof(arr)/sizeof(arr[0]);
in both the function find size of array using above method where arr[] has been created and where it has been passed - the sizeOfArr will decipher things. This perhaps would clear why size/dimensions have been passed explicitly - this is all I can make out of your entire statement. Correct me if I am wrong.
To not use pointers - wrap the array into the struct. Then the entire struct (including the array) will be passed to the function.

Understanding fractional knapsack, arrays and pointers

Just started learning C programming and decided to take a class in algorithmic Toolbox on Coursera. One of the challenges is writing a code using fractional knapsack, maximizing the value of loot and a pseudo code was given to help in coding the solution. Below are the pseudo code and the code I wrote for the pseudo code.
#include<stdio.h>
int min(int a, int b)
{
if (a < b)
return a;
else
return b;
}
int knapsack(int value[], int weight[])
{
int capacity = 100;
int val = 0;
int array[] = { 0 };
for (int i = 1; i < capacity; i++)
{
if (capacity == 0)
{
return val;
}
for (int i = 1; i < capacity; i++)
{
if (weight[i] > 0 && (value[i] / weight[i]))
{
int a = min(weight[i], capacity);
val = val + a * (value[i] / weight[i]);
weight[i] = weight[i] - a;
array[i] = array[i] + a;
capacity = capacity - a;
}
}
}
return val;
}
int main()
{
int value[100];
int weight[100];
scanf("%d", &value[100]);
scanf("%d", &weight[100]);
printf("%d", knapsack(value[100], weight[100]));
return 0;
}
pseudo code
Knapsack(W, w1,v1,......wn,vn)
A <-- [0,0,], V <-- 0;
repeat n times:
if W = 0:
return (V,A)
select i with Wi > 0 and max vi/wi
a <-- min(wi, W)
V <-- V + a(vi/wi)
wi <-- wi - a, A[i] <-- A[i] + a, W <-- W - a
return (V, A)
I am getting errors when I compile such as "passing argument 1 of 'knapsack' makes pointer from integer without a cast [-Wint-conversion]"
printf("%d", knapsack(value[100],weight[100]));
"expected int * but argument is of type 'int'"
int knapsack(int value[], int weight[])
I also want to know if it is a good practice to declare int value[], int weight[] in the function int knapsack argument and also more explanation in using arrays and pointers in situations like this.
int knapsack(int value[], int weight[])
The above statement gives the compiler the information about HOW the function should be called (type of arguments) and WHAT the function will return.
It says the function knapsack will return an integer value (the 1st int).
Its name is knapsack (case-sensitive).
It expects two arguments: an integer array (named value) and an integer array (named weight).
Points 1, 2 and 3 together make up the signature of a function.
To call the function you have to pass 2 integer arrays as its arguments.
The mistake : value[100] corresponds to an INTEGER ENTRY in the array and not the array itself.
To pass the array you should pass the array name as its argument, which your function expects.
Call the function like this: knapsack(value, weight)
value corresponds the array value and weight corresponds to the array weight
Also, passing value[100] corresponds to some garbage value that is not within the array bounds as you can only access elements ranging from value[0] to value[99] (0-based indexing).

qsort in C based on a column in 2d array: unexpected behavior

I am trying to sort a 2d array based on a particular column using qsort in C. I am attaching a minimal working code I am using. Essentially I am passing the pointer to the rows of the array to qsort, and based on the column number I want to sort, I modify the element to compare inside the compare function. Now, according to C convention, if I have 2 columns, I expect colnum=0 and colnum=1 to correspond to columns 1 and 2. But, in my implementation, I get the correct result if colnum=1 means column 1 and colnum=2 means column 2. I am stumped as to why this should be ? (I have also included the array allocation function I use).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "myfun.h"
static int colnum = 0;
int cmp(const void * a,const void * b);
int main(){
int i;
double **z1;
z1=matrix(5,2);
for (i=0; i<5; i++){
z1[i][1]=-i-1; z1[i][2]=16*i+10;
printf("before sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}
colnum=2;
qsort(z1,5,sizeof(double*),cmp);
for (i=0; i<5; i++){
printf("after sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}
getchar();
}
int cmp(const void * a,const void * b)
{
double** x = (double**) a;
double** y = (double**) b;
double xval, yval;
xval = *(*(x)+colnum);
yval = *(*(y)+colnum);
printf("%lf %lf \n",xval,yval);
if (xval < yval )
{
return 1;
}
else if (xval > yval)
{
return -1;
}
else
{
return 0;
}
}
double** matrix(int rows,int cols){
int k;
double **m;
m = (double **)malloc(rows * sizeof(double *));
for (k=0; k<rows; k++){
m[k] = (double *)malloc(cols * sizeof(double));
}
return m;
}
Your program has undefined behavior, because your are accessing memory beyond the boundary allocated by your inner allocation loop of matrix():
m = (double **) malloc(rows * sizeof(double *));
for (k = 0; k < rows; k++) {
m[k] = (double *) malloc(cols * sizeof(double));
}
Since cols has the value 2, malloc() only returns memory for 2 elements of type double. But, your code is initializing and reading a non-existing third element instead.
Since doing so is undefined, producing the output you expect is within the realm of possible behaviors. However, it is incorrect since you run the risk of corrupting the heap, and reading invalid data. Running your program under valgrind produces "Invalid write" and many "Invalid read" errors due to this problem in your program.
The correct approach is to store the values in their proper 0 and 1 column indexes in your initialization, set colnum to 1 to sort by the second column, and read from the proper 0 and 1 indexes when you print the array values.
z1 = matrix(5, 2);
for (i = 0; i < 5; i++) {
z1[i][0] = -i - 1;
z1[i][1] = 16 * i + 10;
printf("before sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
}
colnum = 1;
qsort(z1, 5, sizeof(double *), cmp);
for (i = 0; i < 5; i++) {
printf("after sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
}
As a side note, when I was formatting your code for this answer, I noticed that you used an old C anachronism, probably unintentionally:
z1[i][1]=-i-1; /*...*/
The =- construct was the original C's (pre C.89) way of spelling the -= operator. It is highly unlikely you will end up using a compiler that will honor that operator without a diagnostic, but you should be wary of this syntax, and separate the = and the - tokens to remove the ambiguity.
z1[i][1] = -i - 1; /*...*/

Define a matrix and pass it to a function in C

I want to create a program in which I can pass a matrix to a function using pointers.
I initialized and scanned 2 matrices in the void main() and then I tried to pass them to a void add function. I think I am going wrong in the syntax of declaration and calling of the function. I assigned a pointer to the base address of my matrix. (for eg: int *x=a[0][0], *y=b[0][0]). What is the right declaration? How can I specify the dimensions?
Given a 2D array of
T a[N][M];
a pointer to that array would look like
T (*ap)[M];
so your add function prototype should look like
void add(int (*a)[COLS], int (*b)[COLS]) {...}
and be called as
int main(void)
{
int a[ROWS][COLS];
int b[ROWS][COLS];
...
add(a, b);
However, this code highlights several problems. First is that your add function is relying on information not passed via the parameter list, but via a global variable or symbolic constant; namely, the number of rows (the number of columns is explicitly provided in the type of the parameters). This tightly couples the add function to this specific program, and makes it hard to reuse elsewhere. For your purposes this may not be a problem, but in general you only want your functions to communicate with their callers through the parameter list and return values.
The second problem is that as written, your function will only work for matrices of ROWS rows and COLS columns; if you want to add matrices of different sizes within the same program, this approach will not work. Ideally you want an add function that can deal with matrices of different sizes, meaning you need to pass the sizes in as separate parameters. It also means we must change the type of the pointer that we pass in.
One possible solution is to treat your matrices as simple pointers to int and manually compute the offsets instead of using subscripts:
void add (int *a, int *b, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
{
size_t j;
for (j = 0; j < cols; j++)
{
*(a + cols * i + j) += *(b + cols * i + j);
}
}
}
and call it like so:
int main(void)
{
int a[ROWS][COLS] = {...};
int b[ROWS][COLS] = {...};
int c[ROWS2][COLS2] = {...};
int d[ROWS2][COLS2] = {...};
...
add(a[0], b[0], ROWS, COLS);
add(c[0], d[0], ROWS2, COLS2);
...
}
The types of a[0] and b[0] are "COLS-element arrays of int"; in this context, they'll both be implicitly converted to "pointer to int". Similarly, c[0] and d[0] are also implicitly converted to int *. The offsets in the add() function work because 2D arrays are contiguous.
EDIT I just realized I was responding to caf's example, not the OP, and caf edited his response to show something very similar to my example. C'est la guerre. I'll leave my example as is just to show a slightly different approach. I also think the verbiage about passing information between functions and callers is valuable.
Something like this should do the trick.
#define COLS 3
#define ROWS 2
/* Store sum of matrix a and b in a */
void add(int a[][COLS], int b[][COLS])
{
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
a[i][j] += b[i][j];
}
int main()
{
int a[ROWS][COLS] = { { 5, 10, 5} , { 6, 4, 2 } };
int b[ROWS][COLS] = { { 2, 3, 4} , { 10, 11, 12 } };
add(a, b);
return 0;
}
EDIT: Unless you want to specify the dimensions at runtime, in which case you have to use a flat array and do the 2D array arithmetic yourself:
/* Store sum of matrix a and b in a */
void add(int rows, int cols, int a[], int b[])
{
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
a[i * cols + j] += b[i * cols + j];
}
#caf has shown a good code example.
I'd like to point out that:
I assigned a pointer to the base
address of my matrix. (for eg: int
*x=a[0][0],*y=b[0][0]).
You are not assining a pointer to the base of the matrix. What this does is assign to the value pointed by x and y, the base value in a and b respectively.
The right way would be
int (*x)[] = a;
int (*y)[] = b;
or alternatively
int *x = &a[0][0];
int *y = &b[0][0];

Resources