Passing arrays to functions without using pointers - c

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.

Related

Removing an array (row) from a 2d array - C Programming

Lets say I have a 2d array:
int array[3][3];
with
000
111
222
and I want to remove 000.
I wrote a function:
void remove(int (*array)[3], int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++)
{
array[i] = array[i + 1];
}
}
which receives pointer to the first element of the 2d array, index which I want to remove and a length of the array.
In the for loop, I move array at the position index to the next element.
But I receive this error message:
error: assignment to expression with array type
array[i] = array[i + 1];
Why?
How can I remove element and get the 2d array without array at the index? Should I maybe make new 2d array and return it instead of passing pointer of 2d array to the function?
You can do what you originally wanted if you use an array of structs instead of a 2D array.
The C language treats structs as value types so you can copy them with simple and safe assignment (no memcpy needed).
Here's an example with a few tweaks.
//try online here: https://rextester.com/DDHBC95444
#include <stdio.h>
//from Chromium code https://stackoverflow.com/a/1598827/7331858
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
typedef struct row_t {
int columns[3];
} row_t;
void remove_row(row_t * const rows, const size_t row_index, const size_t row_count)
{
for (size_t i = row_index; i < row_count - 1; i++) {
rows[i] = rows[i + 1];
}
}
void print_rows(row_t const * const rows, const size_t row_count)
{
const size_t column_count = COUNT_OF(rows[0].columns);
for (size_t r = 0; r < row_count; r++) {
for (size_t c = 0; c < column_count; c++) {
printf("%02i ", rows[r].columns[c]);
}
printf("\n");
}
}
int main(void)
{
row_t rows[] = { {{0,1,2}}, {{10,11,12}}, {{20,21,22}} };
print_rows(rows, COUNT_OF(rows));
printf("\n'removing' row index 1\n");
remove_row(rows, 1, COUNT_OF(rows));
print_rows(rows, COUNT_OF(rows));
return 0;
}
outputs:
00 01 02
10 11 12
20 21 22
'removing' row index 1
00 01 02
20 21 22
20 21 22
The parameter array is declared as int (*array)[3], so its type is pointer to an array of 3 ints. The type of array[i] is array of int and an array cannot be assigned to. A function to shift the rows of your matrix can be implemented like this:
void remove(int (*array)[3], int index, int array_length)
{
int i, j;
for(i = index; i < array_length - 1; i++) {
for (j = 0; j < 3; ++j)
array[i][j] = array[i + 1][j];
}
}
Note that the function does not really remove the row, just shifts the rows up. So its name is misleading. You must create a new array and copy the old array to the new array except the indicated row to really remove a row and to change the dimensions of the array.
Edit: The name of that function should be changed because the standard library already has a function named remove.
If the array is obtained like that:
int (*array)[3] = malloc(array_length * sizeof *array);
You can shrink the array by calling the realloc:
int (*p)[3] = realloc(array, (array_length - 1) * sizeof *p);
if (p != NULL)
array = p;
int (*array)[3] -> Here, array is a pointer to 3 element integer array.
error: assignment to expression with array type
This is because an array variable is not modifiable/re-assignable like a pointer. Operations that can be performed on an lvalue of array type are: sizeof, unary & and implicit conversion to pointer type.
The error is telling you that C doesn't support array assigning. Your code tries to copy the whole line i + 1 into the line i of the matrix, but C doesn't know how to operate this.
The solution is to iterate through each element of your array, copying one by one.
void remove(int (*array)[3], int index, int array_length)
{
int i, j;
for(i = index; i < array_length - 1; i++)
{
for(j = 0; j < array_length; ++)
{
array[i][j] = array[i + 1][j];
}
}
}
The code above assumes that your matrix is always squared, but you could change its dimension inside j's for loop.

How to pass a 2 Dimensional array as an argument of function in C?

Code:
#include <stdio.h>
char* input(char* arr,int N, int M){
int i, j;
for(i=0;i<N;i++){
for(j=0;j<M;j++){
scanf("%d",&arr[i][j]);
}
}
return arr;
}
int main() {
int i,N,M;
scanf("%d%d",&N,&M);
char arr[N][M];
arr=input(arr,N,M);
return 0;
}
Explanation:
The above given is a simple program where the user inputs the data into a 2-D array.
Here I have Tried to assign the value to arr pointer(That points to the base address); an address that we get from the input function, of the same array filled with elements now. We have passed the pointer to the array in input function as one argument, and the array dimensions as the other.
Majorly the problem faced here is about pointers and their application into arrays. But I am not able to figure out how I'll make the changes
There are two ways you can pass a 2D array as a function argument.
char *input (char [][m]arr, int n, int m)
You would read/write values the way you are doing in your code. Keep in mind that this is a feature introduced in C99 and won't compile with older compilers.
Another option is to pass it as a pointer:
char *input (char *arr, int n, int m)
Here you would read or write the array like so:
int i, j;
for(i=0; i<N; i++){
for(j=0; j<M; j++){
*(arr + i * n + j) = 'a';
/* OR you can also do this */
arr[i *n + j] = 'a';
}
}
Multidimensional arrays in C are stored in memory row by row. So if you allocated a 3 x 2 array, you would have 3 rows, each having 2 columns. But the memory layout would be:
0, 1 => row1
2, 3 => row2
4, 5 => row3
Here, 0,1,2,3,4,5 are the contiguous indices of the array. In order to access the 2nd column of 3rd row , given a pointer arr to the base address of the array, you would have to find the address of the correct cell in the array.
We know that each row has 2 cells so in order to jump to the 3rd row we need to add the row_id * number_of_cols_per_row to the base pointer. So to get to 3rd row, we need to do arr + 2 * 2. Once we are in the correct row we need to add the column offset of the column we want to access. So here we want to access the second column, so we add 1.
arr + 2 * 2 + 1
But this will be the address of the second column of the third row. In order to write here we need to use the * operator:
*(arr + 2 * 2 + 1) = 'a';
This is exactly what we are doing in the loop.
As an aside, in your code you are calling scanf with %d format specifier, which is for integers. But you are storing the value in a char array. This can be a potential bug, correct thing is to use %c specifier.
You can use a two-dimensional array masterpiece as an argument or a parameter, you can specify the size of all dimensions when defining the parameter group in the called function, or you can omit the size description of the first dimension, such as:
void Func(int array[3][10]);
void Func(int array[][10]);
Here is a complete solution that works:
#include <stdio.h>
void input(int N, int M, char arr[N][M]){
int i, j;
for(i=0; i<N; i++){
for(j=0; j<M; j++){
scanf("%c", &arr[i][j]);
}
}
}
int main() {
int N, M;
scanf("%d %d", &N, &M);
char arr[N][M];
input(N, M, arr);
return 0;
}

Using pointers to matrices in a scanf function

I was playing around with pointers when inputing a matrix with scanf and for some reason, when I run this code, only the first element of every row gets stored correctly.
#include "stdio.h"
void main()
{
int i, j, n, A[10][10];
scanf("%d", &n);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", A + j + i*10);
}
This is what I get after inputing 1,2,3,4,5,6,7,9 into a 3x3 matrix and printing it:
1 -858993460 -858993460
2 -858993460 -858993460
3 -858993460 -858993460
According to my understanding of how matrices are stored, this should work. Can anyone point out whats wrong with my code?
You declare A as
int A[10][10];
that is, an array of 10 arrays of 10 ints each. Thus, when A decays to a pointer to its first element, the type of that pointer is int (*)[10]. That's a pointer to an array of 10 ints, not a pointer to a single int. Among the differences is their interaction with pointer arithmetic. Because pointer arithmetic is defined in terms of the size of the pointed-to type, whenever i is nonzero, the expression A + j + i*10 produces a pointer (to array of 10 ints) outside the bounds of array A.
The most type-safe way of doing what you want would be to use array syntax to select array elements:
&A[i][j]
. Type-correct alternatives that use pointer arithmetic include
&(*(A + i))[j]
and
*(A + i) + j
These latter two both rely on the fact that the expression A + i is a pointer to an array of int; dereferencing that pointer produces an array, which can be the operand of the [] operator (and the address of the result then taken). Alternatively, the array designated by *(A + i) decays to a pointer to its first element (i.e. decays to an int *) when it appears as an operand of the + operator, and adding j to that yields a pointer to the jth element of array *(A + i) (which is the same array designated by A[i]).
Bad pointer math.
A + j + i * 10
When A is used in A + j + i*10, it becomes the pointer to its first element, which is an array of 10 int. Every 1 added to A offsets its address by 40 bytes.
Recommend to use &A[i][j] instead.
Code re-worked to show addresses used.
#include "stdio.h"
int main() {
int i, j, n, A[10][10];
n = 3;
char *base = (char*) A;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
char *offset0 = (char*) (&A[i][j]);
char *offset1 = (char *) (A + j + i * 10);
printf("%d %d %3td %3td\n", i, j, offset0 - base, offset1 - base);
}
}
Output
0 0 0 0
0 1 4 40
0 2 8 80
1 0 40 400
1 1 44 440
1 2 48 480
2 0 80 800
2 1 84 840
2 2 88 880

Syntax for VLAs as a function parameter

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.

malloc a char[][]

I am trying to malloc a char to have rows and columns with one letter in each cell. Something similar to int x[i][j] where I have i*rows and j*columns. Basically I want to make this:
|
1
222
33333
4444444
I tried with this code but it gives me an error: assignment makes an integer from pointer without a cast
A=(char**) malloc (5*sizeof(char*));
for(i=0;i<N+2;i++)`{
A[i]=(char*) malloc(7*sizeof(char));
}
for(i=0;i<3;i++){
for(j=0;j<7;j++){
left=3;
right=3;
if((j>=left)&&(j<=right)){
A[i][j]=i;
}
}
left--;
right++;
}
I would go with different approach:
#define STEPS 5
#define ARRAY_SIZE STEPS*STEPS
The size of the array in your case can be easily calculated by the formula above.
Now, you just need to allocate fixed size of bytes, and fill it. That's it. Even more, the version below will simply out-beat your version in simplicity and performance.
int i, j;
char *array;
array = malloc(ARRAY_SIZE);
for (i = 0; i < STEPS; i++)
for (j = 0; j < (i * 2 + 1); j++)
*(array + i * STEPS + j) = i + 1;
Proof.
This compiles fine for me, as long as I add this around your code snippet; note that "A" was declared as being of type "char **". It won't work if you write, say "char A[][]".
#include <stdlib.h>
int main() {
const int N = 10;
int i, j, left, right;
char **A;
/* your code */
return 0;
}

Resources