Why does the matrix in main change? [duplicate] - c

This question already has answers here:
Passing an array as an argument to a function in C
(11 answers)
Closed 2 years ago.
I am learning C and I am confused why the matrix in main changes in the function change. I am assuming that the matrix was passed in the function change as ma[10][10] and that matrix m shouldn't change because I declared it in main, right? Can someone explain what is happening in this case? How do I fix it?
thx for help
void change(int ma[2][3]){
int l, c;
for(l=0; l<2; l++){
for(c=0; c<3; c++){
ma[l][c]=1;
}
}
}
int main()
{
int m[2][3], l, c;
for(l=0; l<2; l++){
for(c=0; c<3; c++){
m[l][c]=0;
}
}
change(m);
for(l=0; l<2; l++){
for(c=0; c<3; c++){
printf("%d", m[l][c]);
}
printf("\n");
}
return 0;
}
I was expecting to see this:
000
000
What i get:
111
111

void change(int ma[2][3]){ ...
......
int m[2][3];
change(m);
"Why does the matrix in main change?"
You pass the array m by reference to the function change.
The parameter int ma[2][3] is in fact not an array, it is a pointer of type int (*)[3] and will point to the address of the first element of m in main().
That is why m in main got changed.
"How do I fix it?"
C does not allow to pass or return arrays by value to or from functions.
However, there are workarounds. You can f.e. wrap the array into a structure and then access the array inside of the structure. The structure you can pass and return by value.
#include <stdio.h>
#define ROWS 2
#define COLS 3
struct x {
int m[ROWS][COLS];
};
static void no_change (struct x b)
{
int l, c;
for ( l = 0; l < ROWS; l++) {
for ( c = 0; c < COLS; c++ ) {
b.m[l][c] = 1;
}
}
}
int main (void)
{
int l, c;
struct x a;
for ( l = 0; l < ROWS; l++ ) {
for ( c = 0; c < COLS; c++ ) {
a.m[l][c] = 0;
}
}
no_change(a);
for ( l = 0; l < ROWS; l++ ) {
for ( c = 0; c < COLS; c++ ) {
printf("%d", a.m[l][c]);
}
printf("\n");
}
return 0;
}
Output:
000
000

Because the arrays are passed by the pointer not the value.
So you work on the same array.
In C only scalar types, structs and unions are passed by value
How can I fix it?
You can't fix it. If you really want to pass the array by value, you need to wrap it into the struct
typedef struct
{
int arr[2][3]
}ARR_WRAP;
void change(ARR_WRAP ma)
{
int l, c;
for(l=0; l<2; l++)
{
for(c=0; c<3; c++)
{
ma.arr[l][c]=1;
}
}
}
int main()
{
ARR_WRAP m;
for(int l=0; l<2; l++)
{
for(int c=0; c<3; c++)
{
m.arr[l][c]=0;
}
}
change(m);
for(int l=0; l<2; l++)
{
for(int c=0; c<3; c++)
{
printf("%d", m.arr[l][c]);
}
printf("\n");
}
return 0;
}

Related

how to remove segmentation fault in below program

I am a beginner in programming. What is a segmentation fault and how to remove that on the following program?
The following is a compare the triplets problem asked in hackerrank. I receive a segmentation fault when attempting to run the program.
int main() {
int a, b, c;
c = points(a, b);
printf("%d", c);
return 0;
}
int points(int a[10], int b[10]) {
int p = 0, q = 0;
for (int i = 0; i < 3; i++) {
printf("%d", a[i]);
scanf("%d", & a[i]);
}
for (int j = 0; j < 3; j++) {
printf("%d", b[j]);
scanf("%d", & b[j]);
}
for (int k = 0; k < 3; k++) {
if (a[k] > b[k]) {
++p;
return p;
} else {
if (a[k] = b[k])
++q;
return q;
}
}
return 0;
}
int a,b,c;
c=points(a,b);
You are passing arguments to function without setting theirs value. Remember that in C, you are passing arguments to function by value.
int points(int a[10],int b[10])
This function expects two arrays of ten integers. You are passing only one integer for each.
You should also read about passing array arguments to function (if that was your intention). In C, You can't pass whole array to function unless it is wraped into a struct. You should only pass address of the first array element and in some way define size. For example:
#define ARRAY_SIZE 10
int foo(int tab[])
{
int i;
for (i = 0; i < ARRAY_SIZE; i++)
tab[i] = do_stuff();
}
int main(void)
{
int tab[ARRAY_SIZE];
foo(tab);
}
You can also not define ARRAY_SIZE macro, but pass another argument to a function which will define the size of passed array.

how do returns a matrix in C (include code)

i defined a matrix into a function. how do i return that matrix for print it when i call it with another function. i mean...
#include<stdio.h>
#include<conio.h>
#include<time.h>
void main() {
int m,n;
printf("type 2 numbers:");
scanf("%i %i",&m,&n);
declaration(m,n);\\HERE IS THE PROBLEM
printing(matrix,m,n);
getch();
}
void declaration(int a,int b) {
srand(time(NULL));
int i,j,matrix[a][b];
for(i=0;i<a;i++){
for(j=0;j<b;j++){
matrix[i][j]=1+rand()%7;
}
}
}
void printing(int c[100][100],int a,int b) {
int i,j;
for(i=0;i<a;i++){
for(j=0;j<b;j++){
printf("%i\t",c[i][j]);
}
printf("\n");
}
}
Define it like:
typedef struct {
int rows;
int cols;
int *data;
} int_matrix_entity, *int_matrix;
int_matrix int_matrix_create(int rows, int cols, bool rand)
{
int_matrix mt;
int i;
if ((mt = malloc(sizeof(int_matrix_entity))) == NULL)
{
return NULL;
}
if ((mt->data = malloc(sizeof(int) * cols * rows)) == NULL)
{
free(mt);
return NULL;
}
if (rand)
{
srand(time(NULL));
for (i = 0; i < cols * rows; i++)
{
mt->data[i] = 1 + rand() % 7;
}
}
else
{
memset(mt->data, 0, sizeof(int) * cols * rows);
}
return mt;
}
void int_matrix_printf(int_matrix mt)
{
int i;
int j;
for (i = 0; i < mt->rows; i++)
{
for (j = 0; j < mt->cols; j++)
{
printf("%5d ", mt[i * cols + j]);
}
printf("\n");
}
}
You have a few points that require a bit more attention;
1 ) read warning and error messages given by your compiler
2 ) again, read warning messages given by your compiler
3 ) use indentation to make your code more readable.
4 ) Always return from main(), that's a good practice
The code below does what you want to achieve; have a look at it and keep on reading...
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
// You either have to declare your functions
// or implement them before main()
void declaration(int a,int b, int m[a][b]);
void printing(int a,int b, int m[a][b]);
int main(){ // always return from main()
int m,n;
printf("type 2 numbers:");
scanf("%i %i",&m,&n);
int matrix[m][n];
declaration(m, n, matrix);
printing(m, n, matrix);
return 0;
}
void declaration(int a,int b, int m[a][b]){
srand(time(NULL));
int i,j;
for(i=0;i<a;i++){
for(j=0;j<b;j++){
m[i][j]=1+rand()%7;
}
}
}
void printing(int a,int b, int m[a][b]){
int i,j;
for(i=0;i<a;i++){
for(j=0;j<b;j++){
printf("%i\t",m[i][j]);
}
printf("\n");
}
}
You need a way to transfer data from one function to another. You cannot simply declare an auto variable in one function and pass it to another as you did in the code below
declaration(m,n);
printing(matrix,m,n); /* where does matrix[][] come from? */
remember, C is a strongly typed language which means you have to declare your variables before using them. This applies to your functions as well. You either have to give your function declarations before main() (or more specifically, before using them), or implement them.
Look into your header files (i.e. .h files) and you will see lots of function declarations.
Since you use variable length arrays, make sure your compiler is at least capable of compiling code confirming C99 standard.
Some extras;
Normally, C passes arguments by value and you have to use a pointer if you want the value of your variable get changed within the function. If you have a close look at the code snippet I gave, I simply used an int m[a][b].In C, the name of an array is a pointer to its first element, hence you can change the value of array elements when actually array's name is passed to your function as an argument.
For further reading, you may want to look at
variable scope
global variables (you can define matrix[][] as a global variable and change the value of matrix elements)
declaration vs definition in C
Another simple way to do it is use double pointer to create 2-dimensional array. Keep it simple.
#include <stdio.h>
#include <stdlib.h>
int** create_matrix(int rows, int cols) {
int **matrix = malloc(rows*(sizeof(int *)));
for(int i = 0; i < rows; i++) {
matrix[i] = malloc(cols*sizeof(int));
}
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
matrix[i][j] = 1 + rand()%7;
}
}
return matrix;
}
void printing(int** matrix, int rows, int cols) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main(void) {
int rows, cols;
rows = 3, cols = 3;
int** matrix = create_matrix(rows, cols);
printing(matrix, rows, cols);
free(matrix);
return 0;
}

Passing a 2d array to a function if I don't know the dimensions

I am trying to write a C function to add two arrays. The function should work with any array sizes and it should receive a reference to both arrays and the number of rows and the number of columns and it should return a pointer to the first element of the resulting array.
How would I do that? When I try to pass a two dimensional array to a function I get an error?
#include<stdio.h>
void function(int r, int c,int a[][]){
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
{
printf("%d, ",a[i][j]);
}
printf("\n");
}
}
int main(){
int array[2][2] = {{1,2},{4,5}};
function(2,2,array);
return 0;
}
Assuming C99, or C11 with an implementation that doesn't define __STDC_NO_VLA__, you could use the variable length array (VLA) notation and could write:
void function(int r, int c, int a[r][c])
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
printf("%d, ", a[i][j]);
putchar('\n');
}
}
Or something equivalent to that. The dimensions must be defined before they're used in the array specification.
If you don't have access to even a C99 compiler but only a C90 compiler, then you have to pass a pointer to the first element of the array and the sizes and you perform the array index calculation explicitly.
void function(int r, int c, int *a)
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
printf("%d, ", a[i * c + j]);
putchar('\n');
}
}
Now you call the function like this:
int main(void)
{
int array[2][2] = { { 1, 2 }, { 4, 5 } };
function(2, 2, &array[0][0]);
return 0;
}

How to return matrix?

I'm trying to make a Cramer-linear-solving, and I wrote a function that replaces a matrix column, just like that:
void replacecol(int c, int n, float mat_in[n][n], float vect_in[n],
float mat_out[n][n])
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (j == c)
{
mat_out[i][j] = vect_in[j];
}
else
{
mat_out[i][j] = mat_in[i][j];
}
}
}
}
But it is currently void, and I want it to return the mat_out with it's values, when I call this function... How could I do that??
You can avoid to use 2 matrices for your function. You can simply:
void replacecol(int c, int n, float mat_in[n][n], float vect_in[n]))
{
int i;
for (i = 0; i < n; i++)
{
mat_in[i][c] = vect_in[i];
}
}
float mat_in[n][c] it is a pointer float(*)[] so modifications on that parameter are made on the passed matrix.

Transpose matrix function in C, with function receiving and returning a 2D array

I need to create a function that takes a matrix and returns it transpose. The only requirement is that it directly returns a matrix, not just modifies it by reference. Here's what I've done so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define ROW 100000000
#define COL 100000000
int (*(f_MatTrans)(int mat[][COL], int r, int c))[COL];
int main(void)
{
int x[2][2]={1,2,3,4};
int (*a)[2];
a=f_MatTrans(x,2,2);
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
printf("X[%d][%d]=%d\n",i,j,x[i][j]);
printf("A[%d][%d]=%d\n",i,j,a[i][j]);
}
}
return 0;
}
int (*(f_MatTrans)(int mat[][COL], int r, int c))[COL]
{
int a[c][r];
for(int i=0; i<r; i++)
{
for(int j=0; j<c; j++)
{
a[j][i]=mat[i][j];
}
}
return a;
}
The purpose of this is to include the function on a library created by myself, just in case it is useful information.
The code in the question (when I read it) doesn't compile because the array x is not compatible with the function signature.
I'm not clear what the real constraints on your problem are. The easy way to do it in C99 or C11 is with VLA notation:
#include <stdio.h>
static void MatrixTranspose(int r, int c, int src[r][c], int dst[c][r])
{
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
dst[j][i] = src[i][j];
}
int main(void)
{
int x[3][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
int y[2][3];
MatrixTranspose(3, 2, x, y);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
printf("X[%d][%d]=%d ", i, j, x[i][j]);
printf("Y[%d][%d]=%d\n", j, i, y[j][i]);
}
}
return 0;
}
Sample output:
X[0][0]=0 Y[0][0]=0
X[0][1]=1 Y[1][0]=1
X[1][0]=2 Y[0][1]=2
X[1][1]=3 Y[1][1]=3
X[2][0]=4 Y[0][2]=4
X[2][1]=5 Y[1][2]=5
My suspicion is that you are supposed to be doing something different (notationally more complex), but it is not yet clear what.
You cannot return a pointer to the local array, because that ceases to exist when the function returns. If you want your function to create the result array (not write to some other array that is passed into the function), you must use malloc() in these cases:
//The return type is actually `int (*)[r]`, but C doesn't like that.
int* f_MatTrans(int r, int c, int mat[][c]) {
int (*a)[r] = malloc(c*sizeof(*a));
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
a[j][i]=mat[i][j];
}
}
return *a;
}
Note that I changed the array types: If you declare mat as int mat[][COL], the number COL will be used to calculate the offset mat[1][0], which will be 100000000 integers after the first element in your case, while the array that you pass in only contains four integers. This is undefined behavior, and your program is allowed to format your harddrive if you do this.
Unfortunately, it is not possible for the type of the returned pointer to depend on the value of an argument to the function. That is why I changed the return type to a plain integer pointer, you must document that this is meant to be a pointer of type int (*)[r].
You would use the function above like this:
int main(void) {
int x[2][3]={1,2,3,4,5,6};
int (*a)[2] = (int (*)[2])f_MatTrans(2, 3, x);
for(int i=0; i<2; i++) {
for(int j=0; j<2; j++) {
printf("X[%d][%d]=%d\n",i,j,x[i][j]);
printf("A[%d][%d]=%d\n",i,j,a[i][j]);
}
}
free(a); //Cleanup!
return 0;
}

Resources