I'm working on a project (written in C) involving matrix factorization and I need some help.
My objective is to allocate memory for an upper triangular matrix and I want to access it via algebraic row and column notation (i.e. i,j in {1,2,...,n} instead of i,j in {0,1,...,n-1}).
For example, in a 5x5 matrix I should be able to access the [3][4] element if I input matrix[3][4].
My code for a non-algebraic index upper triangular matrix looks like this:
double** malloc_sup_matrix (int n)
{
double** L;
int i;
L = (double**)malloc((n)*sizeof(double*));
if(L == NULL)
printerror("allocating space for the matrix (rows).");
for(i = 0; i < n; i++)
{
L[i] = (double*)malloc((n-i)*sizeof(double));
if(L[i] == NULL)
printerror("allocating space for the matrix (cols).");
L[i]-=i;
}
return L;
}
My code for the algebraic index one (I'm not checking if the allocated space is null yet, I'll do it when I stop messing around with this):
int** m;
int i, n;
n = 10;
m = (int**)malloc((n+1)*sizeof(int*));
for(i = 0; i < n; i++)
{
m[i] = (int*)calloc((n+1)-(i),sizeof(int));
m[i] -= i;
}
m--;
for(i = 0; i < n; i++)
{
m[i]--;
}
It works just the way I want it, but I have issues when freeing the space I've used. This is the way I'm doing it:
for(i = 1; i <= n; i++)
{
m[i]++;
}
for(i = 0; i < n; i++)
{
m[i] += (i);
free(m[i]);
}
m++;
free(m);
Do you guys have any suggestions? Thank you so much in advance ^^.
There's a problem on this line:
m--;
for(i = 0; i < n; i++)
{
m[i]--;
}
You're decrementing m, but then go ahead and index it from 0 ... I guess you may end up messing up the heap structures.
I managed to have your code valgrind error-free like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int** m;
int i, j, n;
n = 10;
m = (int**)malloc((n+1)*sizeof(int*));
for(i = 0; i < n; i++)
{
m[i] = (int*)calloc((n+1)-(i), sizeof(int));
m[i] -= i;
}
for(i = 0; i < n; i++)
{
m[i]--;
}
m--;
/* Access it like m[1][1] ... m[n][n], m[i][j] (with i <= j) */
/*
for (i = 1; i <= n; i++) {
for (j = i; j <= n; j++) {
m[i][j] = i+j;
}
}
*/
m++;
for(i = 0; i < n; i++)
{
m[i]++;
}
for(i = 0; i < n; i++)
{
m[i] += (i);
free(m[i]);
}
free(m);
return 0;
}
Related
Im trying to sort a matrix by the sum of its row's digits, from highest to lowest. I dont know if i explained that correctly so here's some photos explaining it.
This is what my code outputs. Basically, it asks you for m and n, which are the dimensions of the matrix. In this example it's a 3x4, 3 rows and 4 columns. Then, the matrix should be sorted by rows, by the sum of row's digits. Which means, instead of what's being outputted in the picture above, the correct result should be this:
I have no idea how to sort this from highest to lowest, i have been trying for hours to no avail.
Here's my code:
#include <stdio.h>
#define N 30
void main(){
double a[N][N], s[N], p;
int i, j, m, n, max;
while(1){
printf("\nm, n? ");
scanf("%d%d", &m, &n);
if(m <= 0 || m > N || n <=0 || n > N)
break;
for(i = 0; i < m; i++){
printf("%2d. row? ", i+1);
for(j = 0; j < n; scanf("%lf", &a[i][j++]));
}
for(i = 0; i < m; i++)
for(s[i] = j = 0; j < n; s[i] += a[i][j++]);
for(j = 0; j < n - 1; j++){
for(max = i, j = i+1; j < n; j++)
if(s[j] > s[max])
max = i;
if(max != j){
p = s[j];
s[j] = s[max];
s[max] = p;
for(j = 0; j < m; j++){
p = a[j][i];
a[j][i] = a[j][max];
a[j][max] = p;
}
}
}
printf("New matrix: \n");
for(i = 0; i < m; i++){
for(j = 0; j < n; printf("%8.2lf", a[i][j++]));
printf("\n");
}
for(j = 0; j < m; j++)
printf("-------------");
printf("\n");
for(j = 0; j < m; printf("%8.2f \n", s[j++]));
printf("\n");
}
}
You can sort the rows of the matrix from highest to lowest, using a simple bubble sort algorithm.Your code modified below:
int main() {
double a[N][N], s[N], p;
int i, j, m, n, max;
while (1) {
printf("\nm, n? ");
scanf("%d%d", & m, & n);
if (m <= 0 || m > N || n <= 0 || n > N)
break;
for (i = 0; i < m; i++) {
printf("%2d. row? ", i + 1);
for (j = 0; j < n; scanf("%lf", & a[i][j++]));
}
for (i = 0; i < m; i++)
for (s[i] = j = 0; j < n; s[i] += a[i][j++]);
for (i = 0; i < m - 1; i++) { // modified here
for (j = i + 1; j < m; j++) { // modified here
if (s[j] > s[i]) { // modified here
p = s[i];
s[i] = s[j];
s[j] = p;
for (int k = 0; k < n; k++) {
p = a[i][k];
a[i][k] = a[j][k];
a[j][k] = p;
}
}
}
}
printf("New matrix: \n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; printf("%8.2lf", a[i][j++]));
printf("\n");
}
for (j = 0; j < m; j++)
printf("-------------");
printf("\n");
for (j = 0; j < m; printf("%8.2f \n", s[j++]));
printf("\n");
}
return 0;
}
Here's how i modified your code to achieve that:
Initialize a loop variable i to 0.
In the outer loop, run the inner loop j from i+1 to m-1.
In the inner loop, compare the sum of the row i with the sum of row
j. If the sum of row j is greater than the sum of row i, swap the
rows using a temporary variable.
After the inner loop finishes, increment the value of i by 1. Repeat
the outer loop until i becomes equal to m-1.
Output:
You can just use qsort to let it handle the sorting and item swapping. Then you only need to write the code for comparing two rows with each other.
Given something like this:
int matrix[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,1,2,3},
};
You'd call qsort as:
qsort(matrix, 3, sizeof(int[4]), compare);
The only complexity is implementing the comparison callback function. There's two things to consider there:
We've told qsort that we have an array of 3 items, each of type int[4]. So the void pointers it passes along to us will actually be pointers to type int[4]. That is: int(*)[4].
qsort sorts in ascending order by default, where the item considered "less" ends up first. So we need to tweak that to get the largest item first.
Example:
int compare (const void* obj1, const void* obj2)
{
const int (*ptr1)[4] = obj1;
const int (*ptr2)[4] = obj2;
size_t sum1=0;
size_t sum2=0;
for(size_t i=0; i<4; i++)
{
sum1 += (*ptr1)[i];
sum2 += (*ptr2)[i];
}
if(sum1 > sum2) // largest sum considered "less" for qsort
return -1;
else
return 1;
return 0;
}
sum1 < sum2 would have placed the smallest row first.
Full example:
#include <stdio.h>
#include <stdlib.h>
int compare (const void* obj1, const void* obj2)
{
const int (*ptr1)[4] = obj1;
const int (*ptr2)[4] = obj2;
size_t sum1=0;
size_t sum2=0;
for(size_t i=0; i<4; i++)
{
sum1 += (*ptr1)[i];
sum2 += (*ptr2)[i];
}
if(sum1 > sum2) // largest sum considered "less" for qsort
return -1;
else
return 1;
return 0;
}
void print_matrix(size_t col, size_t row, int matrix[col][row])
{
for(size_t i=0; i<col; i++)
{
for(size_t j=0; j<row; j++)
{
printf("%d,", matrix[i][j]);
}
puts("");
}
}
int main (void)
{
int matrix[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,1,2,3},
};
print_matrix(3,4,matrix);
puts("");
qsort(matrix, 3, sizeof(int[4]), compare);
print_matrix(3,4,matrix);
}
#define N 3
int subMatrix(int a[][N]) {
int i, j;
int sum = 0;
int arr[N];
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
sum += a[i][j];
sum -= a[j][i];
}
arr[i] = sum;
sum = 0;
}
return *arr;
}
void main() {
int a[N][N] = {
{9,2,4},
{3,7,11},
{3,1,2}
};
for (int i = 0; i < N; i++) {
printf("%5d", subMatrix(a[i]));
}
}
The function works fine, the problem is when I'm returning the new array and loop over it in the main function I get the first element of the array and the other elements are addresses.
i did it before with another array with size of doubles and it worked.
There is something i miss?
double avgMatrix(int a[][C]) {
int i, j, sum=0;
double M[R];
for (i = 0; i < R; i++) {
for (j = 0; j < C; j++) {
sum += a[i][j];
}
M[i] = (double)sum / C;
sum = 0;
}
return *M;
}
void main() {
int a[R][C] = {
{9,2,4},
{3,8,11},
{3,1,2}
};
for (int i = 0; i < R; i++)
printf("%5.2lf", avgMatrix(a[i]));
}
this code works. what can be the difference?
I do not really understand what your function subMatrix does.
Your code needs a few modifications to be able to compile.
First, include the necessary header #include <stdio.h>, because your code needs printf.
Second, make sure the passed parameter and the attribute be the same type.
Third, if you would like to return an array from a function, you should use dynamic allocation function to help you do that. malloc
/* At least, make sure to include necessary head files
* #include <stdio.h>
*/
#define N 3
int subMatrix(int a[][N]) {
int i, j;
int sum = 0;
int arr[N];
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
/* Because the passed parameter is one dimensional
* so the following code does not make sense.
*/
sum += a[i][j];
sum -= a[j][i];
}
arr[i] = sum;
sum = 0;
}
/* arr is a local variable. It is actually a pointer
* It should never be returned.
* In fact, *arr is only the first element of the array of arr.
* At least, you should return the address of the first element.
* Considering your purpose, to use dynamic allocation is proper.
*/
return *arr;
}
/* 'void main()' is not right.
* 'int main(void)' is the right way.
*/
void main() {
int a[N][N] = {
{9,2,4},
{3,7,11},
{3,1,2}
};
for (int i = 0; i < N; i++) {
/* a[i] is a one-dimensional array,
* but subMatrix needs a two dimensional one.
*/
printf("%5d", subMatrix(a[i]));
}
}
A possible working code:
#include <stdio.h>
#include <stdlib.h>
#define N 3
int *subMatrix(int a[N][N]) {
int sum = 0;
int *arr = (int *)malloc(N*sizeof(int));
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
sum += a[i][j];
sum -= a[j][i];
}
arr[i] = sum;
sum = 0;
}
return arr;
}
int main(void) {
int a[N][N] = {
{9,2,4},
{3,7,11},
{3,1,2}
};
int *arr = subMatrix(a);
for (int i = 0; i < N; i++)
printf("arr[%d] : %d\n", i, arr[i]);
free(arr);
}
Is this what you want? Try it.
How do I get to write to 2D pointers where I have pnumber[2%4][2%4] and how can I get pnumber with more than 3 ciphers to be displayed?
I'm making a program to write pascals triangle in C.
When the pointer pnumbers[i][j] have both i and j = 2 mod 4, except for when i and j = 2, then my program won't write to the address and give the error message:
pascals triangle: malloc.c:2406: sysmalloc: Assertion '{old_top == initial_top (av) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int factorial(int p) {
if (p>=1) {
return p*factorial(p-1);
}
else {
return 1;
}
}
int NchooseM(int n, int m) {
return factorial(n)/(factorial(n-m)*factorial(m));
}
int main() {
int n =7;
int x = n-2;
int i, j, k;
/*
printf("How many rows of Pascals triangle do you want to write?\n");
scanf("%d", &n);
*/
int **pnumbers;
pnumbers = (int **) malloc(n *sizeof(int *));
/* Allocate memory for storing the individual elements in a row */
for (i = 0; i < n; i++) {
pnumbers[i] = (int *) malloc(i * sizeof(int));
}
pnumbers[0][1] = 1;
/* Calculating the value of pnumbers[k][l] */
for (i = 0; i < n; i++) {
for (j = 0; j <= i; j++) {
pnumbers[i][j] = NchooseM(i,j);
}
/*
if (!(i % 4 == 2 && i != 2))
for (j = 0; j <= i; j++) {
pnumbers[i][j] = NchooseM(i,j);
} else if (i > 2) {
for (j = 0; j <= i-1; j++) {
pnumbers[i][j] = NchooseM(i,j);
}
}
*/
}
/* Writing out the triangle */
for (i = 0; i < n; i++) {
for (k = 0; k <= x; k++){
printf(" ");
}
for (j = 0; j <= i; j++) {
printf("%d ", pnumbers[i][j]);
}
x = x-1;
printf("\n");
}
for (i = 0; i < n; i++) {
free(pnumbers[i]);
}
free(pnumbers);
return 0;
}
When I avoid writing to these addresses and just print them out I get some seemingly random integer at these memory addresses.
Also when avoid these addresses and just print out so many rows that I get some spots with a higher integer with more than 3 siphers, it seems to overflow - and I don't see the logic behind it.
The result of running the second code
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int factorial(int p) {
if (p>=1) {
return p*factorial(p-1);
}
else {
return 1;
}
}
int NchooseM(int n, int m) {
return factorial(n)/(factorial(n-m)*factorial(m));
}
int main() {
int n =20;
int x = n-2;
int i, j, k;
/*
printf("How many rows of Pascals triangle do you want to write?\n");
scanf("%d", &n);
*/
int **pnumbers;
pnumbers = (int **) malloc(n *sizeof(int *));
/* Allocate memory for storing the individual elements in a row */
for (i = 0; i < n; i++) {
pnumbers[i] = (int *) malloc(i * sizeof(int));
}
pnumbers[0][1] = 1;
/* Calculating the value of pnumbers[k][l] */
for (i = 0; i < n; i++) {
/*
for (j = 0; j <= i; j++) {
pnumbers[i][j] = NchooseM(i,j);
}
*/
if (!(i % 4 == 2 && i != 2))
for (j = 0; j <= i; j++) {
pnumbers[i][j] = NchooseM(i,j);
} else if (i > 2) {
for (j = 0; j <= i-1; j++) {
pnumbers[i][j] = NchooseM(i,j);
}
}
}
/* Writing out the triangle */
for (i = 0; i < n; i++) {
for (k = 0; k <= x; k++){
printf(" ");
}
for (j = 0; j <= i; j++) {
printf("%d ", pnumbers[i][j]);
}
x = x-1;
printf("\n");
}
for (i = 0; i < n; i++) {
free(pnumbers[i]);
}
free(pnumbers);
return 0;
}
But row number 13 is still quite messed up.
Code is experiencing int overflow and thus undefined behavior (UB).
With 32-bit int and int factorial(int p), p > 12 oveflows the int range.
Code could use a wider integer type (long long works up to p==20), but improvements can be made at NchooseM() to avoid overflow for higher values.
Something like the below. Works up to int n = 30;
int NchooseM(int n, int m) {
// return factorial(n)/(factorial(n-m)*factorial(m));
int nm = 1;
int den = 1;
for (int i = m+1; i <= n; i++) {
assert(INT_MAX/i >= nm);
nm *= i;
assert(nm % den == 0);
nm /= den++;
}
return nm;
}
Tried unsigned long long and works up to int n = 62;
Edit: Another bug:
I "fixed" by initializing all to 1, yet I suspect something remains amiss in /* Calculating the value of pnumbers[k][l] */ for (i = 0; i < n; i++) { code.
pnumbers[i] = malloc((i + 1) * sizeof pnumbers[i][0]);
for (int j = 0; j < i + 1; j++) {
pnumbers[i][j] = 1;
}
Aside: rather than pnumbers[i] = (int *) malloc((i+1) * sizeof(int));, consider below with no unneeded cast nor trying to match the right type.
pnumbers[i] = malloc(sizeof pnumbers[i][0] * (i+1));
i have this small piece of code which i cant get to work.
I am kinda new and i just cant find a mistake i did. Thanks
int main (void)
{
int **array;
int i,j, m;
scanf("%d", &m);
array = malloc(sizeof(int) * (m*m));
for (i = 0; i < m; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &array[i][j]);
}
}
for (i = 0; i < m; i++)
{
for (j = 0; j < m; j++)
{
printf("%d", array[i][j]);
}
}
return 0;
}
What you are allocating is an one dimensional array of size m*m but you are using it as if you have allocated a jagged array where each row contains m elements.
You can allocate a bit different way than what you did
array = malloc(sizeof *array * m);
if( array == NULL)
{
// error in malloc
}
for(size_t i =0; i<m; i++)
{
array[i]= malloc(sizeof *array[i] * m);
if( array[i] == NULL)
{
// error
}
}
...
for(size_t i = 0; i<m ; i++)
free(array[i]);
free(array);
Alternatively you can put all the elements in a linear manner using i and j.
int *array;
...
for (i = 0; i < m; i++)
{
for (j = 0; j < m; j++)
{
if( scanf("%d", &array[i*m+j]) != 1){
// error in getting input.
}
}
}
...
free(array);
Same goes with printf also.
Also don't forget to free the memory you have allocated dynamically after you are done working with it.
int main()
{
double *array;
long int n;
n=10000000;//10^7
array = (double *) malloc(n*sizeof(double));
return 0;
}
basically, I want to use this code for a really big aray into a 2 dimensional array, which will have dimensions [very large][4].
If you want a 2D array, then allocate a 2D array. It's that simple.
double (*pArr)[4] = malloc(10000000 * sizeof pArr[0]);
Notes:
do not cast the return value of malloc().
use sizeof pArr[0] instead of sizeof(TheDataType) for defensive programming reasons.
This seems working on Wandbox.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
double (* array)[4];
long int n;
int i, j;
n=10000000;//10^7
array = (double (*)[4]) malloc(n*sizeof(double[4]));
printf("%u\n",(unsigned int)sizeof(array[0]));
printf("%u\n",(unsigned int)sizeof(double[4]));
for (i = 0; i <n; i++) {
for (j = 0; j < 4; j++) array[i][j] = (double)i * j;
}
for (i = 0; i < 10; i++) {
for (j = 0; j < 4; j++) printf("%f ", array[i][j]);
putchar('\n');
}
for (i = n - 10; i < n; i++) {
for (j = 0; j < 4; j++) printf("%f ", array[i][j]);
putchar('\n');
}
free(array);
return 0;
}
int n = 100000;
double** array = malloc(sizeof(double*)*n);
for (int i = 0; i < n; ++i)
{
array[i] = malloc(4*sizeof(double));
}
Also note that we don't cast the malloc's result(Do I cast the result of malloc?).