I'm trying to multiply two multidimensional arrays to form a matrix. I have this function. This should work in theory. However, I am just getting 0s and large/awkward numbers. Can someone help me with this?
int **matrix_mult( int **a, int **b, int nr1, int nc1, int nc2 )
{
int **c;
int i,j,k,l;
c = malloc(sizeof(int *)*nr1);
if (c == NULL){
printf("Insuff memm");
}
for(l=0;l<nr1;l++){
c[l] = malloc(sizeof(int)*nc1);
if (c[l] == NULL){
printf("Insuff memm");
}
}//for loop
for (i=0;i<nr1;i++){
for (j=0;j<nc2;j++){
for (k=0;k<nc1;k++){
c[i][j] = (a[i][k]) * (b[k][j]);
}
}
}
return( c );
}
Are you doing mathematical matrix multiplication? If so shouldn't it be:
for(i = 0; i < nr1; i++)
{
for(j = 0; j < nc1; j++)
{
c[i][k] = 0;
for(k = 0; k < nc2; k++)
{
c[i][k] += (a[i][j]) * (b[j][k]);
}
}
}
My full and final solution, tested to produce sensible results (I didn't actually do all the calculations myself manually to check them) and without any sensible niceties such as checking memory allocations work, is:
int **matrix_mult(int **a, int **b, int nr1, int nc1, int nc2)
{
int **c;
int i, j, k;
c = malloc(sizeof(int *) * nr1);
for (i = 0; i < nr1; i++)
{
c[i] = malloc(sizeof(int) * nc2);
for (k = 0; k < nc2; k++)
{
c[i][k] = 0;
for (j = 0; j < nc1; j++)
{
c[i][k] += (a[i][j]) * (b[j][k]);
}
}
}
return c;
}
There were a few typos in the core of the for loop in my original answer, mostly due to my being mislead by a different answer. These have been corrected for posterity.
If you change c[i][j] = (a[i][k]) * (b[k][j]); to c[i][j] += (a[i][k]) * (b[k][j]); in your code then it will work just fine provided that
nr1 is number of rows of matrix a
nc1 is the number of columns of the matrix a
nc2 is the number of columns of the matrix b
Just be sure that the matrix c is initiated with zeroes. You can just use calloc instead of malloc when allocating space, or memset the allocated array after a call to malloc.
One more tip is to avoid using the letter l when accessing array elements. when tired, you will have hard time noticing errors with l vs 1.
Related
I have designed the following C function in order to compute the PA = LU factorization, using only one matrix to store and compute the data:
double plupmc(int n, double **c, int *p, double tol) {
int i, j, k, pivot_ind = 0, temp_ind;
int ii, jj;
double pivot, *temp_row;
for (j = 0; j < n-1; ++j) {
pivot = 0.;
for (i = j; i < n; ++i)
if (fabs(c[i][j]) > fabs(pivot)) {
pivot = c[i][j];
pivot_ind = i;
}
temp_row = c[j];
c[j] = c[pivot_ind];
c[pivot_ind] = temp_row;
temp_ind = p[j];
p[j] = p[pivot_ind];
p[pivot_ind] = temp_ind;
for (k = j+1; k < n; ++k) {
c[k][j] /= c[j][j];
c[k][k] -= c[k][j]*c[j][k];
}
}
return 0.;
}
where n is the order of the matrix, c is a pointer to the matrix and p is a pointer to a vector storing the permutations done when partial pivoting the system. The variable tol is not relevant for now. The program works storing in c both the lower and upper triangular parts of the factorization, where U corresponds to the upper triangular part of c and L corresponds to the strictly lower triangular part of c, adding 1's in the diagonal. For what I have been able to test, the part of the program corresponding to partial pivoting is working properly, however, the algorithm used to compute the entries of the matrix is not giving the expected results, and I cannot see why. For instance, if I try to compute the LU factorization of the matrix
1. 2. 3.
4. 5. 6.
7. 8. 9.
I get
1. 0. 0. 7. 8. 9.
l : 0.143 1. 0. u : 0. 2. 1.714*
0.571 0.214* 1. 0. 0. 5.663*
the product of which does not correspond to any permutation of the matrix c. In fact, the wrong entries seem to be the ones marked with a star.
I would appreciate any suggestion to fix this problem.
I found the problem with your code, there was a little conceptual error in the way that you were normalizing the row while computing the actual decomposition:
for (k = j+1; k < n; ++k) {
c[k][j] /= c[j][j];
c[k][k] -= c[k][j]*c[j][k];
}
became:
for (k = j+1; k < n; ++k) {
temp=c[k][j]/=c[j][j];
for(int q=j+1;q<n;q++){
c[k][q] -= temp*c[j][q];
}
}
which returns the result:
7.000000 8.000000 9.000000
0.142857 0.857143 1.714286
0.571429 0.500000 -0.000000
If you have any questions I am happy to help.
Full implementation here:
#include<stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
double plupmc(int n, double **c, int *p, double tol) {
int i, j, k, pivot_ind = 0, temp_ind;
int ii, jj;
double *vv=calloc(n,sizeof(double));
double pivot, *temp_row;
double temp;
for (j = 0; j < n; ++j) {
pivot = 0;
for (i = j; i < n; ++i)
if (fabs(c[i][j]) > fabs(pivot)) {
pivot = c[i][j];
pivot_ind = i;
}
temp_row = c[j];
c[j] = c[pivot_ind];
c[pivot_ind] = temp_row;
temp_ind = p[j];
p[j] = p[pivot_ind];
p[pivot_ind] = temp_ind;
for (k = j+1; k < n; ++k) {
temp=c[k][j]/=c[j][j];
for(int q=j+1;q<n;q++){
c[k][q] -= temp*c[j][q];
}
}
for(int q=0;q<n;q++){
for(int l=0;l<n;l++){
printf("%lf ",c[q][l]);
}
printf("\n");
}
}
return 0.;
}
int main() {
double **x;
x=calloc(3,sizeof(double));
for(int i=0;i<3;i++){
x[i]=calloc(3,sizeof(double));
}
memcpy(x[0],(double[]){1,2,3},3*sizeof(double));
memcpy(x[1],(double[]){4,5,6},3*sizeof(double));
memcpy(x[2],(double[]){7,8,9},3*sizeof(double));
int *p=calloc(3,sizeof(int));
memcpy(p,(int[]){0,1,2},3*sizeof(int));
plupmc(3,x,p,1);
for(int i=0;i<3;i++){
free(x[i]);
}
free(p);
free(x);
}
I'm trying to make a code which converts some decimal numbers to bits.
There are more simple ways to reach this result but I'm poking around and joking with memory in C.
int ** decimalToBits(int *number,int size){
int **bits = (int **)malloc(sizeof(*bits)*size), i = 0;
for (int j = 0; j < size; j++) {
int * temp = (int *)malloc(sizeof(int));
while (number[j] >= 1) {
temp[i++] = number[j] % 2;
number[j] /= 2;
realloc(temp, sizeof(int));
}
printf("\n");
bits[j] = (int *) malloc(sizeof(int)*i);
for (int k = i-1; k >= 0; k--){
bits[j][k] = temp[k];
printf("%d" ,bits[j][k]);
}
i = 0;
}
return bits;
}
I'm having some allocation problems, first of all I'm going to explain the idea:
I pass to the function multiple numbers, so for example:
int numbers[2] = {23,73};
decimalToBits(numbers,2);
Each converted number will be stored in **bits double pointer, so bits[0] will contain the number 23 converted, and bits[1] will contain 73 converted as well.
The problem shows up when I do bits[j] = (int *) malloc(sizeof(int)*i); call,
because this seems to let the temp pointer to be overwritten with some random numbers. In fact if I remove the bits[j] = (int *) malloc(sizeof(int)*i); and bits[j][k] = temp[k]; lines and I replace printf("%d" ,bits[j][k]); with printf("%d" ,temp[k]);
the code seems to have a good behavior, and it gives me the correct output:
10111
1001001
I also noticed that allocating the bits[j] = (int *) malloc(sizeof(int)*8); externally from the for (int j = 0; j < size; j++) loop let the code works. So why this allocation problem occurs when declared just like the above code and what's the best way to solve it?
I'm trying to multiply two dynamic matrices by passing them through a function. I'm getting a segmentation fault during the multiplication.
The matrices are being passed through a function. The items in the arguments are correct because I had to use them for a different operation in this project. I have a feeling that I messed up with the pointers, but i'm pretty new to C and i'm not sure where I messed up.
double** multiplyMatrices(
double** a,
const uint32_t a_rows,
const uint32_t a_cols,
double** b,
const uint32_t b_cols){
uint32_t i = 0;
uint32_t j = 0;
uint32_t k = 0;
double** c;
//allocate memory to matrix c
c = (double **)malloc(sizeof(double *) * a_rows);
for (i = 0; i < a_rows; i++) {
*(c +i) = (double *)malloc(sizeof(double) * b_cols);
}
//clear matrix c
for(i = 0; i < a_rows; i++){
for(j = 0; j < a_cols; j++){
*c[j] = 0;
}
}
i = 0;
//multiplication
while(j = 0, i < a_rows ){
while(k = 0, j < b_cols){
while(k < a_cols){
//following line is where i'm getting the segmentation fault
*(*(c+(i*b_cols))+j) += (*(*(a+(i*a_cols))+k)) * (*(*(b+(k*b_cols))+j));
k++;
}
j++;
}
i++;
}
return c;
}
The obvious mistake is that you dereference c + i * b_cols while c is an array of pointers of size a_rows. So likely c + i * b_cols is outside of the area that you previously allocated with malloc().
I would suggest to simplify the matrix representation using a single array of double with the size equal to the total number of elements, i.e. rows * cols.
For example:
double *c;
c = malloc(sizeof(double) * a_rows * b_cols);
This not only has better overall performance, but simplifies the code. You would then have to "linearise" the offset inside your unidimensional array to convert from bi-dimensional matrix coordinates. For example:
c[i * b_cols + j] = ...
Of course, the other two matrices need to be allocated, filled and accessed in a similar manner.
For code clarity, I would also replace the while statements by for statements with the actual variable that they loop on. For example:
for (i = 0; i < a_rows; i++)
for (j = 0; j < b_cols; j++)
for (k = 0; k < a_cols; k++)
You can (ab)use the C language in many ways, but the trick is to make it more clear for you in the first place.
I'm trying to create a 3D array of ints initialized to zeros each of fixed size denoted as "dim".
For example, for dim=3, it will have 27 cells for ints.
I tried this:
int ***board;
int **rows;
int *tried;
board = calloc(dim,sizeof(int**));
rows = calloc(dim*dim, sizeof(int*));
tried = calloc(dim*dim*dim, sizeof(int));
int i;
int j;
int k;
for (i=0 ; i<dim ; i++) {
board[i] = rows + i*dim*dim;
for (j=0 ; j<dim ; j++) {
board[i][j] = tried + j*dim + i*dim*dim;
}
}
for (i=0 ; i<dim ; i++) {
for (j=0 ; j<dim ; j++) {
for (k=0 ; k<dim ; k++) {
board[i][j][k] = 0;
}
}
}
Trying to debug it, I found that it works until:
board[1][1][0] = 0
And then the program gets stuck and i just can't find the reason.
Can someone explain this please?
Thanks!
First about the error in your code. Compare this:
rows = calloc(dim*dim, sizeof(int*));
to this:
for (i=0 ; i<dim ; i++) {
board[i] = rows + i*dim*dim;
The entire size of the array allocated to rows is dim*dim elements. So, already in the second iteration of this loop, you access it out of bounds. You probably meant:
for (i=0 ; i<dim ; i++) {
board[i] = rows + i*dim;
As I already mentioned in the comment, this is not a 3D array. It mimics the usage in code by using pointers and you're using a kind-of clever trick here, so you only need 3 allocations in total. This might be a good idea under the following conditions:
your dim is variable at runtime, so you can't know it in advance, and
you have to write code for compilers that don't support VLAs1) (variable-length-arrays).
If one of this conditions is not true, it's much better to use a real 3D array. If the array doesn't have to live after leaving your function and the size isn't huge, just use a simple variable with automatic storage duration like
int board[3][3][3] = { 0 }; // possibly #define the dimension
or, for a variable dim, requiring a compiler supporting VLAs
int board[dim][dim][dim] = { 0 };
If on the other hand, the array will be huge and/or you need to return it from your function, you indeed have to allocate it dynamically. Then just use the following:
int (*board)[3][3] = calloc(3, sizeof *board); // static size
int (*board)[dim][dim] = calloc(dim, sizeof *board); // dynamic case, with VLA suppport
Also note that calloc() already sets your allocated memory to 0, so no need for looping all over it.
Side notes:
with sizeof, prefer the expression form, so instead of writing
int *a = calloc(5, sizeof(int));
better write
int *a = calloc(5, sizeof *a);
this avoids errors when you later change the type of a.
always check the return value of malloc() and friends -- they might return a null pointer (e.g. when you're running out of memory).
1) VLAs don't exist in the oldest standards C89/C90 -- they were introduced in C99 as a mandatory feature, but later made optional in C11. This allows C11 compilers to omit them, which might make sense when e.g. targeting embedded systems. In practice, you can safely assume a C11 compliant compiler supports them if it isn't special purpose.
I rewrote your code to show how allocation of a 3D array could look like. And as pointed out in the comments, there's no need to initialize the array to 0 since calloc does that for you. Had you used malloc the array would not have been initialized.
#include <stdlib.h>
#include <stdio.h>
#define dim (3u)
int main() {
int x;
int y;
int z;
int ***cube;
cube = calloc(dim, sizeof(int**));
for (z = 0; z < dim; z++) {
cube[z] = calloc(dim, sizeof(int*));
for (y = 0; y < dim; y++) {
cube[z][y] = calloc(dim, sizeof(int));
}
}
for (z = 0; z < dim; z++) {
for (y = 0; y < dim; y++) {
for (x = 0; x < dim; x++) {
cube[z][y][x] = z + y + x;
}
}
}
for (z = 0; z < dim; z++) {
for (y = 0; y < dim; y++) {
for (x = 0; x < dim; x++) {
printf("%d ", cube[z][y][x]);
}
printf("\n");
}
printf("\n");
}
return 0;
}
What you want to store in it is up to you, in my example I wrote the sum of the counter to each index.
Code below is Unlicense.
I will suggest something different. Just create a 1D array and set some boundaries to interpret it as 3D. I added some test cases for you to better visualize how it works. Do not forget to look at how easy 'calloc' call is. Here is the code:
#include <stdlib.h>
#include <stdio.h>
int getindex(int dim, int x, int y, int z) {
return z * dim * dim + y * dim + x;
}
void printarray(int* tdarray, int dim) {
printf("[\n");
for (int i = 0; i < dim; i++) {
printf("\t[\n");
for (int j = 0; j < dim; j++) {
printf("\t\t[");
for (int k = 0; k < dim; k++) {
if (k == 0) printf("%d", *(tdarray + getindex(dim, k, j, i)));
else printf(",\t %d", *(tdarray + getindex(dim, k, j, i)));
}
printf("]\n");
}
printf("\n\t]\n");
}
printf("]\n");
}
int main() {
int dim = 10;
size_t arraysize = sizeof (int) * dim * dim * dim;
int lookupindex = getindex(dim, 7, 5, 4); /* Numbers picked randomly */
int* tdarray = (int*) malloc(arraysize);
calloc(*tdarray, arraysize);
/* Below is test code and visualizations, all magic happens above.*/
if (*(tdarray + lookupindex) == 0) *(tdarray + lookupindex) = 7;
printf("tdarray[x:%d, y:%d, z:%d]:\t%d\n\n", 7, 5, 4, *(tdarray + lookupindex));
printarray(tdarray, dim);
printf("\n\n\n\n\n\n\n\n\n\n");
for (int i = 0; i < getindex(dim, 9, 9, 9) + 1; i++) *(tdarray + i) = i;
printarray(tdarray, dim);
free(tdarray);
}
I have been looking for a way to swap the names between two matrices in C. I have 2 square size x size matrices. I make some operation to the one of them, I put the result in a cell in the other matrix, then I swap their names and I repeat.
Below I am giving my code
int main(void){
int const size = 1000;
int const steps = 10;
float A[size][size], B[size][size];
int i,j,k;
int t = 0;
double sum = 0;
double sum1 = 0;
int const ed = size - 1;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){// initialize the matrices
A[i][j] = i+j;
B[i][j] = 0;
}
}
for(i = 0; i < size; ++i){//find the sum of the values in the first matrix
for(j = 0; j < size; ++j){
sum = sum + A[i][j];
}
}
printf("The total sum of the matrix 1 is %lf \n",sum);
for(k = 0; k < steps; ++k){//for each cell of the matrix A calculate the average of the values' of the cell and its surroundings and put it in the coresponding place in the matrix B and then copy matrix B to matrix A and repeat. There are special cases for the cells who are at the edges and the last or first row/column.
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
if(i==0){
if(j==0)
B[i][j]=(A[0][0]+A[0][1]+A[0][ed]+A[1][0]+A[ed][0])/5.0;
else if(j==ed)
B[i][j]=(A[0][ed]+A[0][0]+A[0][ed-1]+A[1][ed]+A[ed][ed])/5.0;
else
B[i][j]=(A[0][j]+A[0][j+1]+A[0][j-1]+A[1][j]+A[ed][j])/5.0;
}else if(i==ed){
if(j==0)
B[i][j]=(A[ed][0]+A[ed][1]+A[ed][ed]+A[0][0]+A[ed-1][0])/5.0;
else if(j==ed)
B[i][j]=(A[ed][ed]+A[ed][0]+A[ed][ed-1]+A[0][ed]+A[ed-1][ed])/5.0;
else
B[i][j]=(A[ed][j]+A[ed][j+1]+A[ed][j-1]+A[0][j]+A[ed-1][j])/5.0;
}else{
if(j==0)
B[i][j]=(A[i][0]+A[i][1]+A[i][ed]+A[i+1][0]+A[i-1][0])/5.0;
else if(j==ed)
B[i][j]=(A[i][ed]+A[i][0]+A[i][ed-1]+A[i+1][ed]+A[i-1][ed])/5.0;
else
B[i][j]=(A[i][j]+A[i][j+1]+A[i][j-1]+A[i+1][j]+A[i-1][j])/5.0;
}
}
}
sum1 = 0;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
sum1 = sum1 + B[i][j];
}
}
t=t+1;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
A[i][j] = B[i][j];
}
}
printf("%lf \n",sum1-sum);
}
printf("The total sum of the matrix 2 is %lf \n",sum1);
printf("Number of steps completed: %i \n",t);
printf("Number of steps failed to complete: %i \n", steps-t);
return 0;
}
I have used the method of copying each time the one matrix to the other, but this is not efficient.
I have a hint that I should use pointers but I can not figure it out. Any help will be much appreciated.
You can swap the values of any two variables of the same type by assigning the value of the first to a temporary variable then assigning the value of the second to the first, then assigning the value of the temporary variable to the second:
int a = 2, b = 3, tmp;
tmp = a;
a = b;
b = tmp;
In particular, it works exactly the same when the variables are of pointer type, so
/* The matrices */
double one[3][3], another[3][3];
/* pointers to the matrices */
double (*matrix1p)[3] = one;
double (*matrix2p)[3] = another;
double (*tmp)[3];
/* ... perform matrix operations using matrix1p and matrix2p ... */
/* swap labels (pointers): */
tmp = matrix1p;
matrix1p = matrix2p;
matrix2p = tmp;
/* ... perform more matrix operations using matrix1p and matrix2p ... */
Updated to clarify:
matrix1p is initially an alias for one, and matrix2p is initially an alias for another. After the swap, matrix1p is an alias for another, whereas matrix2p is an alias for one. Of course, you can perform such a swap as many times as you want. You cannot, however, swap one and another themselves, except via an element-by-element swap.
Note that this yields improved efficiency because pointers are quite small relative to the matrices themselves. You don't have to move the elements of the matrices, but only to change which matrix each pointer refers to.
Yes, you should definitely use pointers, for example:
void swap (int*** m1, int*** m2)
{
int** temp;
temp = *m1;
*m1 = *m2;
*m2 = temp;
}
And then invoke:
int m1[5][5] = 0;
int m2[5][5] = 0;
swap (&m1, &m2);