Why passing 2D matrix gives error in C? - c

I have written this below simple code to demonstrate passing 2D matrix in C. I have gone through most of the online articles. And this code is inaccordance with those suggested approaches. But still I am getting a compile error. Please explain.
#include <stdio.h>
int max = 0;
void maxId(int i,int j, int p[8][12]){
}
int main(){
int m = 8;
int n = 12;
int p[m][n] = {{0,1,1,0,1,0,0,0,1,1,1,0},
{0,1,1,0,1,0,0,0,1,1,1,0},
{0,0,1,0,1,0,0,0,1,1,1,0},
{0,1,0,0,1,1,1,0,1,1,1,0},
{0,0,1,0,1,0,1,0,1,1,1,0},
{0,0,1,0,1,0,1,0,1,1,1,0},
{0,1,0,0,1,1,0,0,1,1,1,0},
{0,0,1,0,1,0,0,0,1,0,1,1}};
int v[m][n];
for(int i= 0;i<m;i++)
for(int j = 0;j<n;j++){
v[i][j] = v[i][j];
}
maxId(0,0,p);
return 0;
}
Updated
The compile error shown is
29 13 C:\Users\RainDrop\Documents\devc++
projects\Untitled2.cpp [Error] cannot convert 'int ()[n]' to 'int
()[12]' for argument '3' to 'void maxId(int, int, int (*)[12])'

I see couple of problems:
A VLA, such as p, cannot be used as an argument to a function that expects a fixed size array. Imagine the problems if m is not 8 or n is not 12.
A VLA cannot be initialized using an intializer list.
You can solve both problems by making m and n macros.
#define m 8
#define n 12
If you choose to do that, replace the use of the hard coded value 8 and 12 by m and n, respectively, everywhere.
Update to point 1 above
gcc does not mind if a VLA is used an argument in a function call where the expected argument type is fixed array. i.e. it is OK using int (*)[n] when the argument type is int (*)[12]. I have not been able to find anything in the standard that indicates which compiler is correct.

To get around the issues mentioned by R Sahu's answer, you can do the following:
#include <stdio.h>
void maxId(size_t m,size_t m, int p[m][n]){
}
#define M (8)
#define N (12)
int main(void)
{
int p[M][N] =
{
{0,1,1,0,1,0,0,0,1,1,1,0},
{0,1,1,0,1,0,0,0,1,1,1,0},
{0,0,1,0,1,0,0,0,1,1,1,0},
{0,1,0,0,1,1,1,0,1,1,1,0},
{0,0,1,0,1,0,1,0,1,1,1,0},
{0,0,1,0,1,0,1,0,1,1,1,0},
{0,1,0,0,1,1,0,0,1,1,1,0},
{0,0,1,0,1,0,0,0,1,0,1,1}
};
size_t n = N;
size_t m = M;
int v[m][n];
for (size_t i = 0; i < m; i++)
{
for(size_t j = 0; j < n; j++)
{
v[i][j] = p[i][j];
}
}
maxId(m, n, v);
return 0;
}

Related

How to write a square matrix multiplication function in C? [duplicate]

This question already has answers here:
How to pass 2D array (matrix) in a function in C?
(4 answers)
Closed 1 year ago.
int Ma_Multiplication(int A[][], int B[][], int size){
int C[size][size];
for( i = 0 ; i< size ; ++i){
for( j=0 ; j< size ; ++j){
C[i][j] = 0;
for( k = 0 ; k < size; ++k)
C[i][j] = C[i][j] + (A[i][k]*B[k][j]);
printf("%d ",C[i][j]);
printf("\n");
}
}
I wrote this function to calculate multiplication of 2 matrices. But when I debugged, it told me this:
error: array type has incomplete element type 'int[]'
4 | int MATRIX(int A[][], int size){
| ^
Could anyone can explain this? Thank u so much!
C does not allow declaration of arrays with element of incomplete type. Thus int A[] is ok. However, int A[][] is not because it's element type is int[] which is incomplete.
To fix I suggest fully defining the parameters using VLA types:
int Ma_Multiplication(int size, int A[size][size], int B[size][size]) {
...
}
If you want to keep an original ordering of parameters you must use an extension (GCC and CLANG) allowing to declare the parameters.
int Ma_Multiplication(int size; int A[size][size], int B[size][size], int size)
This extension may get mainlined into upcoming C23 standard

C Segmentation Fault from function that returns the maximum of an array

I just have a function that finds out the maximum value of an array of integers, but I get a segmentation fault, which I can't find because the compiler doesn't show me the line of the error.
This is my C code:
#include <stdlib.h>
#include <stdio.h>
//Funktion ermittelt den größten Wert eines Arrays
int groesstesElement(int **arrayPointer){
int max = 0;
for (int i = 0; i < 3; i++) {
if (*arrayPointer[i]>max) {
max = *arrayPointer[i];
}
}
return max;
}
int main (int argc, char **argv) {
int array[4]={1,2,3,4};
int *ptr = array;
int z = groesstesElement(&ptr);
printf("%d\n", z);
return EXIT_SUCCESS;
}
I use macOS and VSC.
In C, array indexing [] has higher precedence than pointer de-referencing *: https://en.cppreference.com/w/c/language/operator_precedence
Some parentheses fix the segfault.
if ((*arrayPointer)[i]>max) {
max = (*arrayPointer)[i];
}
Due to the operators precedence, with
*arrayPointer[i]
you are telling your program:
Take the i-th element of the array arrayPointer and dereference it.
But arrayPointer is a pointer to int *, so all you get is the address of ptr (the int ** pointer defined from main) with an offset. When you finally dereference it you are likely accessing an invalid address, causing segmentation fault.
As already suggested by the main answer, the fix is done using parenthesis in order to apply the operators in the order you want:
(*arrayPointer)[i]
Secondary issues in the code
Even though with the correction above the program won't crash anymore, it won't work. Searching through the array with the loop
for (i = 0; i < 3; i++)
you won't include the last item in the search (index 3), skipping precisely the index that, in your example, contains the maximum value. You probably meant for (i = 0; i < 4; i++) or for (i = 0; i <= 3; i++).
Anyway, using magic numbers in the code (in this case the dimension of the array) is considered bad practice. A better solution would have been using a #define, but an even better solution would have been passing to the function the size of the array:
#include <stdlib.h>
#include <stdio.h>
#define ARR_SIZE 4
//Funktion ermittelt den größten Wert eines Arrays
int groesstesElement(int *arrayPointer, unsigned int arrSize){
int max = 0, i;
for (i = 0; i < arrSize; i++) {
if (arrayPointer[i]>max) {
max = arrayPointer[i];
}
}
return max;
}
int main (int argc, char **argv) {
int array[ARR_SIZE]={1,2,3,4};
int z = groesstesElement(array, ARR_SIZE);
printf("%d\n", z);
return EXIT_SUCCESS;
}
Please note how there's no need to use a double pointer anymore.

defining 2D array in c in VS Express 2012

#include<stdio.h>
void main()//this is the way that we pragram in c
{
int arr[][]={{1,2},{1,2},{1,3}};//in class it wasnt required to initialize both
}
the errors:
Error 1 error C2087: 'arr' : missing subscript
Error 2 error C2078: too many initializers
3 IntelliSense: an array may not have elements of this type
I am a beginner , and i saw in class that the professor did the same thing.
also i asked my instructor and he told me that it should raise this error.
can someone please addres me to where and what is the problem?
You're missing the type; all but the first dimension must be specified; and you're missing commas between the aggregate initializers. Working example:
int main(void) {
int arr[][2] = {{1,2}, {1,2}, {1,3}};
}
When you have such a declaration
int arr[][]={{1,2},{1,2},{1,3}};
then the compiler can determine the number of the elements for the left most dimension. There are three initializers so the left most dimension is equal to 3. However the compiler is unable to determine the number of elements in the right most dimension because all these declarations are valid
int arr[][2]={{1,2},{1,2},{1,3}};
int arr[][20]={{1,2},{1,2},{1,3}};
int arr[][200]={{1,2},{1,2},{1,3}};
So you need explicitly to specify the number of elements in the right most dimension of the array. As I can guess you mean the following array declaration
int arr[][2]={{1,2},{1,2},{1,3}};
that is equivalent to
int arr[3][2]={{1,2},{1,2},{1,3}};
Though the MS VS allows a declaration of main like
void main()
nevertheless according to the C Standard the function main without parameters shall be declared like
int main( void )
even if a rerun statement is absent.
You should add type to your array declaration - for example int arr[][].
If you don't want to specify size of columns and rows you have to do it dynamically. For example this way:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int r = 3, c = 4, i, j, count;
int **arr = (int **)malloc(r * sizeof(int *));
for (i=0; i<r; i++)
arr[i] = (int *)malloc(c * sizeof(int));
// Note that arr[i][j] is same as *(*(arr+i)+j)
count = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
arr[i][j] = ++count; // OR *(*(arr+i)+j) = ++count
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
printf("%d ", arr[i][j]);
/* Code for further processing and free the
dynamically allocated memory */
return 0;
}

Function passing of multidimensional array in c

#include <stdio.h>
void spiral(int a[10][10]) {
printf("%d", a[1][3]);
}
int main() {
int r, c, j, i;
scanf("%d%d", &r, &c);
int a[r][c];
for (i = 0; i < r; i++)
for (j = 0; j < c; j++) {
scanf("%d", &a[i][j]);
}
spiral(a);
return 0;
}
When I give a 3 x 6 array
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
The output is 14, while it should be 10
How to fix this issue?
If you enter 3 and 6 for r and c (respectively) then the type of a is not int[10][10] (or int(*)[10] as the spiral argument really is), it's int[3][6]. The memory layout is completely different for the arrays, leading to undefined behavior.
You can solve this by passing the size along to the function, and using it in the declaration of the array:
void spiral(const size_t r, const size_t c, int (*a)[c]) { ... }
Call it like expected:
spiral(r, c, a);
As noted using int a[r][c] as argument might be easier to read and understand, but it gives a false impression that a is actually an array. It's not. The compiler treats the argument as a pointer to an array of c integers, i.e. int (*a)[c].
This makes me a little conflicted... On the one hand I'm all for making things easier to read and understand (which means it will be easier to maintain), on the other hand newbies often get it wrong and think that one can pass an array intact when in fact it decays to a pointer which can lead to misunderstandings.
A few things are wrong: in void spiral() you ask for a 2D-array of 10*10, but you do not give that. Keep that part as a variable, so only ask the type you receive and not what you want to receive and with creating a dynamic array you should always do that with malloc or calloc and free them afterwards. This might be a bit hard at first, but when you start creating bigger programs this is a must if you have a question or do not understand the pointers in the program called (*) then ask me:
#include <stdio.h>
#include <stdlib.h>
void spiral(int **a) {
printf("%d", a[1][3]);
}
int main() {
int r, c, j, i;
scanf("%d%d", &r, &c);
int **a = malloc(r * sizeof(int*));
for (i = 0; i < r; i++) {
a[i] = malloc(c * sizeof(int));
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
scanf("%d", &a[i][j]);
}
}
spiral(a);
for (i = 0; i < r; i++) {
free(a[i]);
}
free(a);
return 0;
}

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