This question already has answers here:
How to pass a 2D array by pointer in C?
(5 answers)
Closed 4 months ago.
#include <stdio.h>
void triU(double **U, double *b, int n)
{
n--;
b[n] /= U[n][n];
for(int i = n - 1; i >= 0; i--)
{
double aux_sum = 0;
for(int j = i + 1; j <= n; j++)
aux_sum += (U[i][j] * b[j]);
b[i] = (b[i] - aux_sum) / U[i][i];
}
}
int main()
{
int n = 3;
double U[][n] = {{5, -5, 10}, {0, 2, 4}, {0, 0, -1}};
double b[] = {25, 16, -2};
triU(U, b, n);
for(int i = 0; i < n; i++)
printf("%le \n", b[i]);
return 0;
}
This is the code for what I am trying to do. I am supposed to make a method with the parameters written in that way to pass the two matrices.
However I keep getting the following error.
triU.c: In function ‘int main()’:
triU.c:21:10: error: cannot convert ‘double (*)[n]’ to ‘double**’
21 | triU(U, b, n);
| ^
| |
| double (*)[n]
triU.c:3:20: note: initializing argument 1 of ‘void triU(double**, double*, int)’
3 | void triU(double **U, double *b, int n)
| ~~~~~~~~~^
I would appreciate any help on how I am supposed to pass arrays by pointers in C.
Thank you very much.
In this call of the function triU:
triU(U, b, n);
the two-dimensional array U is implicitly converted to pointer to its first element of the type double ( * )[3]. But the corresponding function parameter has the type double ** and there is no implicit conversion between the pointer types. So the compiler issues a message.
If your compiler supports variable length arrays (and your compiler support VLAs) then declare the function like:
void triU( size_t n, double ( *U )[n], double *b );
or:
void triU( size_t n, double U[][n], double *b );
and call it like:
triU( n, U, b );
Otherwise declare the function like:
void triU( double ( *U )[3], double *b, size_t n );
or:
void triU( double U[][3], double *b, size_t n );
and call it like:
triU( U, b, n );
Pay attention to that this for loop:
for(int j = i + 1; j <= n; j++)
aux_sum += (U[i][j] * b[j]);
can invoke undefined behavior when j is equal to n because the valid range of indices is [0, n).
Also bear in mind that the length modifier in the format string in this call:
printf("%le \n", b[i]);
is redundant and has no effect. You may write:
printf("%e \n", b[i]);
Related
This is what I have currently, and I have no idea what to do to make it run:
void avg_sum(double a[], int n, double *avg, double *sum) {
int i;
*sum = 0.0;
for (i = 0; i < n; i++)
*sum += a[i];
*avg = *sum / n;
}
int main () {
int array[5] = {1, 2, 3, 4, 5};
int avg = 3;
int sum = 2;
avg_sum(array, 5, avg, sum);
}
I tried manipulating the arguments for running the function, but I can't figure out how to make it work. It can be simple, I just have to write a program to test the avg_sum function. That portion must remain the same.
You want this:
int main () {
double array[5] = {1, 2, 3, 4, 5}; // use double
double avg = 3;
double sum = 2;
avg_sum(array, 5, &avg, &sum); // call with &
}
avg_sum operates on doubles, therefore you need to provide doubles.
parametrers 3 and 4 must be pointers to double, therefore you need to use the address operator &.
All this is covered in the first chapters of your beginner's C txt book.
For starters these initializations
int avg = 3;
int sum = 2;
does not make a sense.
At least it will be more meaningfully to initialize these variables by zero
int avg = 0;
int sum = 0;
The function avg_sum expects that the third and fourth arguments will be accepted by reference through pointers to them.
void avg_sum(double a[], int n, double *avg, double *sum) {
So the function must be called like
avg_sum(array, 5, &avg, &sum);
Also the function expects that the first, third and fourth arguments declared with the type specifier double but you are passing arguments declared with the type specifier int.
The function itself should be declared and defined the following way
void avg_sum( const int a[], size_t n, double *avg, int *sum )
{
*sum = 0;
for ( size_t i = 0; i < n; i++ )
{
*sum += a[i];
}
*avg = n == 0 ? 0.0 : *sum / n;
}
So within main the variables avg and sum have to be declared like
double avg = 0.0;
int sum = 0;
Also after the call of the function
avg_sum(array, 5, &avg, &sum);
it seems you should output the obtained values like for example
printf( "sum = %d, average = %.2f\n", sum, avg );
#define N 5
#define Nv 2
float Cities[N][Nv]={ {0,1}, {3,4}, {1,2}, {5,1} ,{8,9}};
void PrintVec2(float *a, int n) {
int i;
for (i = 0; i < (n / 2); i++) printf("\n%f %f", a[2 * i], a[2 * i + 1]);
printf("\n");
}
//somewhere I call this
PrintVec2(Cities,N*Nv);
New*Nv is a number, integer. How to fix this warning?
The prototype:
void PrintVec2(float *a, int n)
Does not match the input parameter:
PrintVec2(Cities,N*Nv);
The function prototype is looking for the address of the array. Change it to send &Cities[0][0]:
PrintVec2(&Cities[0][0],N*Nv);
First of all: yes, I know this is a common topic and I've tried several proposed solutions. Nothing worked for me (at least nothing with "nice" code), I finally tried the way described here (2nd variant in jxh's solution):
2D array passing to a function
#include<stdio.h>
typedef double real32;
void Multiply_Matrix_Vector38(int n, int m, real32 A[n][m], real32 B[m], real32 Result[n]);
int main()
{
real32 A[3][8];
real32 B[8];
real32 Result[3][3];
int i;
for(i = 0; i < 8; i++) {
A[0][i] = i;
A[1][i] = i+1;
A[2][i] = i+2;
B[i] = i;
B[i] = i;
B[i] = i;
}
Multiply_Matrix_Vector(3, 8, A[3][8], B[8], Result[3]);
return 0;
}
void Multiply_Matrix_Vector(int n, int m, real32 A[n][m], real32 B[m], real32 Result[n])
{
uint8 i, j;
real32 sum;
sum = 0;
for(i = 0; i < n; i++ {
for(j = 0; j < m; j++) {
sum = sum + A[i][j] * B[j];
printf("A %f\n", A[i][j]);
}
Result[i] = sum;
sum = 0;
}
}
I still get incompatible type errors - how can this be fixed?
As arrays decays to pointers when being passed to a function, what's really passed is real32 (*)[8] and real32 *.
You can modify the function appropriately:
void Multiply_Matrix_Vector38(int n, int m, real32 (*A)[m], real32 *B, real32 *Result);
You also calling the function with the wrong arguments. You're calling it with a single value in the arrays, and not the arrays themselves. And remembering that array indexes goes from zero to size minus one, you're also out of bounds.
Instead do just
Multiply_Matrix_Vector(3, 8, A, B, Result);
Oh, and do you really want Result to be an array of arrays too?
Your are not passing the arrays when you do Multiply_Matrix_Vector(3, 8, A[3][8], B[8], Result[3]);
Rather, you are passing the element of A at (3,8), the 9th element of B.
Your call should be the following : Multiply_Matrix_Vector(3, 8, A, B, Result[0]);
The error should have helped you with that : your are passing doubles instead of arrays of doubles.
Result is n array of 3 arrays of size 3, thus Result[0], Result[1], and Result[2] have the correct types. Result[3] is out of bounds however.
Finally your function prototype should be void Multiply_Matrix_Vector(...) not void Multiply_Matrix_Vector38(...)
You missed a couple of things, like the ) in.
for(j = 0; j < m; j++)
Also you should have called
Multiply_Matrix_Vector(3, 8, A, B, Result[3])
Instead of.
Multiply_Matrix_Vector(3, 8, A[3][8], B[8], Result[3])
Because your arguments A[3][8] and B[8] are real32 variables (you are accesing to an element of the matrix and an element of the vector), instead of that you have to use A and B.
And finally, you have to declare.
void Multiply_Matrix_Vector(int n, int m, real32 A[n][m], real32 B[m], real32 Result[n]);
Above the main function to use it there.
Note: Result should be an array, because if multiply A (3x8) with B (8x1), the result should be an array with dimensions 3x1.
I have the following code shown below
To call the function the code looks similar to the following:
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[N][1];
int main(void)
{
matrix_multiply((float*) m1, (float*) m2, N, N, 1, (float*) result);
}
void matrix_multiply(float* input_matrix1, float* input_matrix2, int m, int p, int n, float* output_matrix)
{
// Matrix Multiplication Routine
// input_matrix1= input matrix (m x p)
// input_matrix2 = input matrix (p x n)
// m = number of rows in input_matrix1
// p = number of columns in input_matrix1 which should equal the number of rows in input_matrix2
// n = number of columns in input_matrix2
// output_matrix = output matrix = input_matrix1*input_matrix2 (m x n)
//.....Code that does matrix multiplication
}
I haven't come across the (float*) being used when calling a function. Can someone describe it in detail.
The notation (float *)X is a cast. The cast is necessary if the matrix multiply function is declared (or defined) before it is used, as it should be, because the types being passed to the function are not float * as the function expects but float (*)[2] (which is a pointer to an array). The casts tell the compiler 'we know more about this C than you do', even though that is a very debatable proposition.
Here is a mildly modified version of the code in the question:
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[1][N];
void matrix_multiply(float *input_matrix1, float *input_matrix2, int m, int p, int n, float *output_matrix);
int main(void)
{
matrix_multiply( m1, m2, N, N, 1, result);
matrix_multiply(&m1[0][0], &m2[0][0], N, N, 1, &result[0][0]);
matrix_multiply((float*) m1, (float*) m2, N, N, 1, (float*) result);
}
void matrix_multiply(float *input_matrix1, float *input_matrix2, int m, int p, int n, float *output_matrix)
{
// Matrix Multiplication Routine
// input_matrix1 = input matrix (m x p)
// input_matrix2 = input matrix (p x n)
// m = number of rows in input_matrix1
// p = number of columns in input_matrix1 and the number of rows in input_matrix2
// n = number of columns in input_matrix2
// output_matrix = output matrix = input_matrix1*input_matrix2 (m x n)
//.....Code that does matrix multiplication
}
When compiled with GCC 4.7.1 on Mac OS X 10.8.4, the output is:
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -c matmul89.c
matmul89.c: In function ‘main’:
matmul89.c:10:5: warning: passing argument 1 of ‘matrix_multiply’ from incompatible pointer type [enabled by default]
matmul89.c:6:6: note: expected ‘float *’ but argument is of type ‘float (*)[2]’
matmul89.c:10:5: warning: passing argument 2 of ‘matrix_multiply’ from incompatible pointer type [enabled by default]
matmul89.c:6:6: note: expected ‘float *’ but argument is of type ‘float (*)[1]’
matmul89.c:10:5: warning: passing argument 6 of ‘matrix_multiply’ from incompatible pointer type [enabled by default]
matmul89.c:6:6: note: expected ‘float *’ but argument is of type ‘float (*)[2]’
matmul89.c: In function ‘matrix_multiply’:
matmul89.c:17:29: warning: unused parameter ‘input_matrix1’ [-Wunused-parameter]
matmul89.c:17:51: warning: unused parameter ‘input_matrix2’ [-Wunused-parameter]
matmul89.c:17:70: warning: unused parameter ‘m’ [-Wunused-parameter]
matmul89.c:17:77: warning: unused parameter ‘p’ [-Wunused-parameter]
matmul89.c:17:84: warning: unused parameter ‘n’ [-Wunused-parameter]
matmul89.c:17:94: warning: unused parameter ‘output_matrix’ [-Wunused-parameter]
$
The unused parameter warnings are reasonable; the function is still a dummy with no code. Line 10 is the call to matrix_multiply() without the casts. As you can see, GCC diagnoses that the types of the matrix arguments are not float * but are pointers arrays. The second call is the way I'd write it, avoiding any need for casts. The third call bludgeons the compiler into accepting the code with the casts, and it will in fact work correctly, but there is really no need to do the bludgeoning.
Working C99 code
If you've got C99 available, you can make use of VLAs — variable length arrays — to write the code neatly:
#include <stdio.h>
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[1][N];
void matrix_multiply(int m, int p, int n, float matrix1[m][p], float matrix2[p][n], float output[m][n]);
void matrix_print(const char *tag, int m, int n, float matrix[m][n]);
int main(void)
{
matrix_multiply(N, N, 1, m1, m2, result);
matrix_print("m1", N, N, m1);
matrix_print("m2", N, 1, m2);
matrix_print("m3", 1, N, result);
}
void matrix_multiply(int m, int p, int n, float matrix1[m][p], float matrix2[p][n], float output[m][n])
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
output[i][j] = 0.0;
for (int i = 0; i < m; i++)
for (int j = 0; j < p; j++)
for (int k = 0; k < n; k++)
output[i][k] += matrix1[i][j] * matrix2[j][k];
}
void matrix_print(const char *tag, int m, int n, float matrix[m][n])
{
printf("%s (%d x %d):\n", tag, m, n);
for (int i = 0; i < m; i++)
{
char *pad = "[";
for (int j = 0; j < n; j++)
{
printf("%s%6.3f", pad, matrix[i][j]);
pad = ", ";
}
printf("%s", " ]\n");
}
}
This compiles without warnings and produces the plausible-looking output:
m1 (2 x 2):
[ 1.000, -0.020 ]
[ 0.000, 1.000 ]
m2 (2 x 1):
[ 1.500 ]
[ 1.500 ]
m3 (1 x 2):
[ 1.470, 1.500 ]
Writing the code to simulate the address arithmetic using C89 is fiddly — far from impossible, but fiddly.
Working C89 code
#include <stdio.h>
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[1][N];
void matrix_multiply(float *matrix1, float *matrix2, int m, int p, int n, float *output);
void matrix_print(const char *tag, int m, int n, float *matrix);
int main(void)
{
matrix_multiply(&m1[0][0], &m2[0][0], N, N, 1, &result[0][0]);
matrix_print("m1", N, N, &m1[0][0]);
matrix_print("m2", N, 1, &m2[0][0]);
matrix_print("m3", 1, N, &result[0][0]);
return 0;
}
/*
** Matrix Multiplication Routine
** matrix1 = input matrix (m x p)
** matrix2 = input matrix (p x n)
** m = number of rows in matrix1
** p = number of columns in matrix1 and number of rows in matrix2
** n = number of columns in matrix2
** output = output matrix = matrix1 * matrix2 (m x n)
*/
void matrix_multiply(float *matrix1, float *matrix2, int m, int p, int n, float *output)
{
int i, j, k;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
output[i*n+j] = 0.0;
for (i = 0; i < m; i++)
for (j = 0; j < p; j++)
for (k = 0; k < n; k++)
output[i*n+k] += matrix1[i*p+j] * matrix2[j*n+k];
}
void matrix_print(const char *tag, int m, int n, float *matrix)
{
int i, j;
printf("%s (%d x %d):\n", tag, m, n);
for (i = 0; i < m; i++)
{
char *pad = "[";
for (j = 0; j < n; j++)
{
printf("%s%6.3f", pad, matrix[i*n+j]);
pad = ", ";
}
printf("%s", " ]\n");
}
}
The output for the C89 and C99 code is the same.
I have the following warnings during the compilation:
solver.c:24: warning: passing argument 2 of ‘mtrx_multiple’ from incompatible pointer type
mat.h:5: note: expected ‘double *’ but argument is of type ‘double **’
solver.c:30: warning: assignment makes pointer from integer without a cast
solver.c:39: warning: assignment makes pointer from integer without a cast
/tmp/ccmU9zRf.o: In function `vec_norm':
math.c:(.text+0x331): undefined reference to `sqrt'
collect2: ld returned 1 exit status
the lines are:
solver.c
double *cg_solve( sparse_mat_t A, double *b, double *x ) {
double *a;
double **r;
double *be;
double **p;
double **x0;
x0[0] = vec_copy(x, size);
...
line 24: r[0] = vec_subtraction( b, mtrx_multiple(A, x0), size );
line 30: x0[k+1] = vec_addition( x0[k], vec_numb_multiple(a[k], p[k], size), size );
line 39: p[k+1] = vec_addition( r[k+1], vec_numb_multiple(be[k], p[k], size), size );
}
math.h
line 5: double *mtrx_multiple (sparse_mat_t A, double *c);
The function that are used there: (math.c)
double *vec_subtraction (double *a, double *b, int n) {
double *result = malloc(sizeof(double)*n);
int i;
for(i=0; i<n; i++)
result[i] = a[i]-b[i];
return result;
}
double *vec_addition (double *a, double *b, int n) {
double *result = malloc(sizeof(double)*n);
int i;
for(i=0; i<n; i++)
result[i] = a[i]+b[i];
return result;
}
double *vec_numb_multiple (double a, double *b, int n) {
double *result = malloc(sizeof(double)*n);
int i;
for(i=0; i<n; i++)
result[i] = a*b[i];
return result;
}
double *mtrx_multiple (sparse_mat_t A, double *c) {
double *result;
int i, j;
result = malloc((A.size) * sizeof *result);
printf("c.n: %d \n", A.size);
for (i = 0; i < A.size; i++) {
int v = 0;
for (j = A.ia[i]; j < A.ia[i + 1]; j++) {
v += A.a[j] * c[A.ja[j]];
}
result[i] = v;
}
return result;
}
double vec_norm (double *a, int n){
double result;
int i;
for(i=0; i<n; i++)
result = result + ( a[i] * a[i] );
result = sqrt(result);
return result;
}
double *vec_copy (double *a, int n) {
double *result;
int i;
for(i=0; i<n; i++)
result[i] = a[i];
return result;
}
I will be grateful for any help.
EDIT
I found the solution to the x0 problem, thanks Ben. Now what left is:
solver.c:30: warning: assignment makes pointer from integer without a cast
solver.c:39: warning: assignment makes pointer from integer without a cast
/tmp/ccL4uSoH.o: In function 'vec_norm':
math.c:(.text+0x331): undefined reference to 'sqrt'
collect2: ld returned 1 exit status
Based on what you've posted, I'm going to guess that you don't have a declaration for vec_numb_multiple in scope before you call it, and the compiler is implicitly typing it to return int; that would lead to the warnings on lines 30 and 39.
The undefined reference to sqrt() means you aren't linking in the standard math library; I'm assuming you're using gcc, so you would need to add -lm to the command line.
It's a really bad idea to use a standard library file name for your own code (math.h, math.c).
replace (line 24)
r[0] = vec_subtraction( b, mtrx_multiple(A, x0), size );
with
r[0] = vec_subtraction( b, mtrx_multiple(A, x0[0]), size );
You said you whant to multiply a matrix (A I guess) with a vector, so the second argument must be a vector. x0 is a pointer to pointers which can be see as a 2D array of doubles, it means a single cell of x0 is an array of doubles (ie. what you could call a vector). This is why you want to pass x0[0], not just x0 which is : many arrays.
see John's aswer for the rest.