I have two functions that I am working with, and I am attempting to make them run as much as 4x faster.
void get_each_fifth(const matrix_t *matrix, long results[RESULTS_LEN]) {
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->cols; j++) {
int q = j % RESULTS_LEN;
results[q] += MGET(matrix, i, j);
}
}
}
The function above will need to be optimized to be 4x faster. In this function, I am finding the sums of integers based on their location in the matrix. Elements in column 0, 5, 10, etc. go into the first element of the results array. Elements in column 1, 6, 11, etc. go into the second column of the array. This pattern continues for the remaining columns. To summarize, the numbers in column i go into element i % 5 of the results array.
long get_each(const matrix_t *matrix) {
long sum = 0;
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->cols; j++) {
sum += MGET(matrix, i, j);
}
}
return sum;
}
This one will need to be 2x faster; it is the sum all of the elements in the matrix and return the result.
MGET and MSET are defined:
#define MGET(mat, i, j) ((mat)->data[((i)*((mat)->cols)) + (j)])
#define MSET(mat, i, j, x) ((mat)->data[((i)*((mat)->cols)) + (j)] = (x))
and the matrix_t struct is defined
typedef struct {
long rows;
long cols;
int *data;
} matrix_t;
and is allocated with this function:
void set_up_matrix(matrix_t *matrix, int rows, int cols) {
if (matrix == NULL) {
return;
}
matrix->rows = rows;
matrix->cols = cols;
matrix->data = malloc(sizeof(int) * rows * cols);
srand(2021);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
MSET(matrix, i, j, rand() % 100);
}
}
}
and result len is defined:
#define RESULTS_LEN 5
Any help would be appreciated!
I would change it to flexible array member and leave the arithmetic to the compiler. It will make it more cache friendly as well. You need to make its task easier by showing what kind of array your data represents. It will allow the compiler to optimize the loops or use vector instructions (if you use some additional command line options). You can use also compiler specific pragmas or attributes like in the example below. It will unroll the loops speeding up the execution speed.
typedef struct {
size_t rows;
size_t cols;
int data[];
} matrix_t;
void get_each_fifth(const matrix_t * restrict matrix, long results[RESULTS_LEN])
{
int (*array)[matrix -> cols] = (int (*)[matrix -> cols])matrix -> data;
#pragma GCC unroll 10
for (size_t i = 0; i < matrix->rows; i++) {
#pragma GCC unroll 10
for (size_t j = 0; j < matrix->cols; j++) {
size_t q = j % RESULTS_LEN;
results[q] += array[i][j];
}
}
}
matrix_t *set_up_matrix(matrix_t *matrix, size_t rows, size_t cols)
{
int (*array)[cols];
matrix = realloc(matrix, sizeof(*matrix) + rows * cols * sizeof(matrix -> data[0]));
if(matrix)
{
matrix->rows = rows;
matrix->cols = cols;
srand(time(NULL)); // it should be called once in main
array = (int (*)[cols])matrix -> data;
for (size_t i = 0; i < rows; i++)
{
for (size_t j = 0; j < cols; j++)
{
array[i][j] = rand() % 100;
}
}
}
return matrix;
}
Related
#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.
I am trying to return a contiguous memory allocated array from a function but I keep on receiving errors.
Compiler returns a warning saying return from incompatible pointer type [-Wincompatible-pointer-types]
Can someone tell me what I am doing wrong?
int *test() {
size_t rows, cols;
// assign rows and cols
rows = 3;
cols = 3;
int count = 0;
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr) {
// do stuff with arr[i][j]
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; j++) {
arr[i][j] = count;
count++;
}
/* code */
}
}
return arr;
}
int main() {
size_t rows, cols;
// assign rows and cols
rows = 3;
cols = 3;
int count = 0;
int (*arr)[cols] = malloc(sizeof *arr * rows);
arr = test();
int i = 0;
int j = 0;
for (i = 0; i < rows; ++i) {
for (j = 0; j < 3; ++j)
printf("%d ", arr[i][j]);
printf("\n");
}
free(arr);
}
it should return a 2D array but returns an error and am using gcc on ubuntu
Your allocation function is fine, except for a few details:
you should pass rows and cols as arguments
you should use type size_t for i and j and iterate to rows and cols instead of hard coded bounds.
you should use parentheses in malloc(sizeof *arr * rows); for readability:
malloc(sizeof(*arr) * rows);
you should return &arr[0][0] or arr[0] for type correctness.
The problem is you cannot define the return type of test to be pointer to 2D array of a parametric second dimension. Hence the type error on the assignment arr = test(); cannot be fixed. You can work around this shortcoming by casting the return value to (int (*)[cols]) or simply (void *).
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int *test(size_t rows, size_t cols) {
int (*arr)[cols] = malloc(sizeof(*arr) * rows);
if (arr) {
// initialize the matrix
size_t count = 0;
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
arr[i][j] = count;
count++;
}
/* code */
}
return &arr[0][0];
}
return NULL;
}
int main() {
// assign rows and cols
size_t rows = 3;
size_t cols = 3;
int (*arr)[cols] = (int (*)[cols])test(rows, cols);
if (arr) {
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
free(arr);
}
return 0;
}
Output:
0 1 2
3 4 5
6 7 8
If all what you need is
to return a contiguous memory allocated array from a function
You can ignore this answer.
If what you are trying to do is to model a bidimensional container (like a matrix) using a dynamically allocated contiguous block of memory, you could define a struct and pass that around:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct {
int rows, cols;
int values[]; // I'm using a Flexible Array Member here.
} iMat;
iMat *alloc_matrix(int rows, int columns)
{
assert(rows > 0 && columns > 0);
iMat *tmp = malloc(sizeof *tmp + sizeof *(tmp->values) * rows * columns);
if (tmp)
{
tmp->rows = rows;
tmp->cols = columns;
}
return tmp;
}
void fill_matrix_iota(iMat *m, int start)
{
if ( m )
for (size_t i = 0, n = m->rows * m->cols; i < n; ++i)
m->values[i] = start + i;
}
void print_matrix(iMat *m, int width)
{
if (m)
{
for (int i = 0, k = 0; i < m->rows; ++i)
{
for(int j = 0; j < m->cols; ++j, ++k)
{
printf("%*.d", width, m->values[k]);
}
putchar('\n');
}
}
}
iMat *make_transposed(iMat *m)
{
if ( !m )
return NULL;
iMat *tmp = alloc_matrix(m->cols, m->rows);
if ( tmp )
{
for (int i = 0; i < m->rows; ++i)
{
for(int j = 0; j < m->cols; ++j)
{
tmp->values[j * m->rows + i] = m->values[i * m->cols + j];
}
}
}
return tmp;
}
int main(void)
{
iMat *a = alloc_matrix(3, 4);
if (!a)
exit(EXIT_FAILURE);
fill_matrix_iota(a, 1);
print_matrix(a, 3);
iMat *b = make_transposed(a);
if (!b)
{
free(a);
exit(EXIT_FAILURE);
}
putchar('\n');
print_matrix(b, 3);
free(b);
free(a);
return EXIT_SUCCESS;
}
I am really new to C and this is for a school assignment.
So, I am tasked to transpose a given matrix.
My current function is the following:
void matrixTranspose(int rows, int cols, int **array) {
int temp[rows][cols];
int i, j;
for (i = 0; i < rows; i++) {
for(j = 0; j < cols; j++) {
temp[i][j] = array[i][j];
}
}
array = realloc(array, cols * sizeof(int *));
for (i = 0; i < cols; i++) {
array[i] = realloc(array[i], rows * sizeof(int));
}
for (i = 0; i < cols; i++) {
for(j = 0; j < rows; j++) {
array[i][j] = temp[j][i];
}
}
}
If I introduce equal values for columns and rows or if the value of rows is bigger than the value of columns it works fine, but for some reason when the value of rows is smaller than the value of columns, it does not works. (Throws me "Segmentation fault (core dumped)" error).
My main looks like this:
int main() {
int **mat;
int cols, rows;
int i, j;
printf("Enter number of rows\n");
scanf("%d", &rows);
printf("Enter number of columns\n");
scanf("%d", &cols);
mat = (int **) malloc (sizeof(int *) * rows);
for (i = 0; i < rows; i++) {
mat[i] = (int *) malloc (sizeof(int) * cols);
}
for (i = 0; i < rows; i++) {
for(j = 0; j < cols; j++) {
mat[i][j] = rand() % 10;
}
}
printf("\nBefore transpose: \n");
for (i = 0; i < rows; i++) {
for(j = 0; j < cols; j++) {
printf("%d ", mat[i][j]);
}
printf("\n");
}
matrixTranspose(rows, cols, mat);
printf("\nAfter transpose: \n");
for (i = 0; i < cols; i++) {
for(j = 0; j < rows; j++) {
printf("%d ", mat[i][j]);
}
printf("\n");
}
}
I hope I explained myselft correctly, sorry for my english, it is not my first language. Thanks
When you modify array in matrixTranspose, you're changing a local variable. That change isn't visible in the calling function, so mat in main no longer points to valid memory.
You need to change the function to accept address of a int ** and dereference it as needed.
void matrixTranspose(int rows, int cols, int ***array) {
int temp[rows][cols];
int i, j;
for (i = 0; i < rows; i++) {
for(j = 0; j < cols; j++) {
temp[i][j] = (*array)[i][j];
}
}
*array = realloc(*array, cols * sizeof(int *));
if (!*array) {
perror("realloc failed");
exit(1);
}
int min = rows < cols ? rows : cols;
for (i = 0; i < min; i++) {
(*array)[i] = realloc((*array)[i], rows * sizeof(int));
if (!(*array)[i]) {
perror("realloc failed");
exit(1);
}
}
if (rows > cols) {
for (i = min; i < rows; i++) {
free((*array)[i]);
}
} else if (cols > rows) {
for (i = min; i < cols; i++) {
(*array)[i] = malloc(rows * sizeof(int));
if (!(*array)[i]) {
perror("malloc failed");
exit(1);
}
}
}
for (i = 0; i < cols; i++) {
for(j = 0; j < rows; j++) {
(*array)[i][j] = temp[j][i];
}
}
}
Note that if the number of rows and columns are not the same, you'll need to either free the extra rows you no longer have or use malloc to allocate new rows.
Note also that you should be checking the return value of malloc and realloc for failure.
Then pass the address of mat to this function:
matrixTranspose(rows, cols, &mat);
You can change the transpose function like this:
int ** matrixTranspose(int rows, int cols, int **array) {
...
return array;
}
And then in main call it like this:
mat = matrixTranspose(rows, cols, mat);
Apart from that, I recommend these thanges. I have changed the argument to sizeof to be the actual variable instead of the type.
array = realloc(array, cols * sizeof(*array));
for (i = 0; i < cols; i++) {
array[i] = realloc(array[i], rows * sizeof(*array[0]));
}
and
mat = (int **) malloc (sizeof(*mat) * rows);
for (i = 0; i < rows; i++) {
mat[i] = (int *) malloc (sizeof(*mat[0]) * cols);
}
Your array is passed by value (i.e. you don't pass a pointer to your matrix). Yet you change it.
array = realloc(array, cols * sizeof(int *));
This is just a local change. Also,
for (i = 0; i < cols; i++) {
array[i] = realloc(array[i], rows * sizeof(int));
}
If rows < col this piece of code will try to reallocate memory for array[i] where i>rows-1. That implies deallocating the memory pointed to by array[i] has never been allocated and you have no idea where it points to.
I am tasked to transpose a given matrix.
Key problem: Code passed the pointer by value and matrixTranspose() need to receive its address in order to modify it. Well answered by others without changing much.
Yet consider a larger change instead. Do not modify the original matrix, make a transposed copy and free matrix helper functions.
int **matrixTranspose_copy(int rows, int cols, const int **array) {
int **transpose = malloc(sizeof *transpose * cols);
for (int r = 0; r < cols; r++) {
transpose[r] = malloc(sizeof *transpose[r] * rows);
for(int c = 0; c < rows; c++) {
transpose[r][c] = array[c][r];
}
}
}
return transpose;
}
void matrixFree(int rows, const int **array) {
for (int r = 0; r < rows; r++) {
free(array[r]);
}
free(array);
}
void matrixTranspose_inplace(int rows, int cols, int ***array) {
int **original = *array;
*array = matrixTranspose_copy(rows, cols, original);
matrixFree(original);
}
I have a matrix that is represented by a one dimensional array,
example:
the matrix
0 1 2 3
4 5 6 7
8 9 10 11
the array
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
now give the dimensions of this matrix and the array I want to find the transpose, i.e.
0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11
I'm working in C and here is my code
#include <stdlib.h>
#include <stdio.h>
void transpose(int *array, int m, int n){
int new_array[12];
for (int i=0; i<m*n; i++) {
new_array[i] = ??;
}
for (int i=0; i<m*n; i++) {
array[i] = new_array[i];
}
}
void print_array(int array[], int size){
for (int i=0; i<size; i++) {
printf("%d\n",array[i]);
}
}
int main(){
int array[12];
for (int i=0; i<12; i++) {
array[i]=i;
}
print_array(array,12);
transpose(array,3,4);
print_array(array,12);
return 0;
}
I've tried a dozen times and failed. Is there a simple way to do this that I have missed?
Use couple of for loops to make the code easier to follow.
void transpose(int *array, int m, int n){
int new_array[12];
for (int i = 0; i < m; ++i )
{
for (int j = 0; j < n; ++j )
{
// Index in the original matrix.
int index1 = i*n+j;
// Index in the transpose matrix.
int index2 = j*m+i;
new_array[index2] = array[index1];
}
}
for (int i=0; i<m*n; i++) {
array[i] = new_array[i];
}
}
void transpose(int *array, int m, int n){
int new_array[12];
int k = 0;
for(int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
new_array[k++] = array[j*n + i];
}
}
for (int i=0; i<m*n; i++) {
array[i] = new_array[i];
}
}
Write the transpose in terms of a double loop over range [0..n) and [0..m) and calculate the indexes corresponding to the old position and the new position:
#include <stdio.h>
static void transpose(int *array, int m, int n)
{
int new_array[m * n];
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
int old_idx = i * n + j;
int new_idx = j * m + i;
new_array[new_idx] = array[old_idx];
}
}
for (int i = 0; i < m * n; i++)
{
array[i] = new_array[i];
}
}
static void print_array(int array[], int size)
{
for (int i = 0; i < size; i++)
{
printf(" %d", array[i]);
}
putchar('\n');
}
int main(void)
{
int array[12];
for (int i = 0; i < 12; i++)
{
array[i] = i;
}
print_array(array, 12);
transpose(array, 3, 4);
print_array(array, 12);
return 0;
}
The functions have to be pre-declared or made static to compile with my default compilation options. The transpose() function shown will work with any shape (size) of matrix (whereas the original won't work if the product of the dimensions is more than 12). I flattened the output from the array printer, too (though I'd probably make it print matrix shaped output if it were for 'production' use). I do assume that you have C99, or C11 with VLA support.
$ ./trans
0 1 2 3 4 5 6 7 8 9 10 11
0 4 8 1 5 9 2 6 10 3 7 11
$
I have changed:
for (int i = 0 ; i < m*n ; i++) {
new_array[i] = ??;
}
to:
int ctr = 0;
for (int i = 0 ; i <= m*n ; i++) {
if (ctr > m*n)
ctr -= m*n - 1;
new_array[i] = array[ctr];
ctr += n;
}
The logic is quite simple. Each row is n integers long and so the number below a num in the 2-D matrix form would be n+num
You can rewrite your transpose function as like this:
static void transpose(int *array, int m, int n)
{
int *temp=malloc(m*n*sizeof(int)); //need to create a temporary array.
memcpy(temp,array,m*n*sizeof(int));
int i, j;
for (i = 0; i < m; ++i)
{
for (j = 0; j < n; ++j)
{
array[j*m+i]=temp[i*n+j];
}
}
free(temp);
}
You almost had it, I think this would do it...
void transpose(int *array, int m, int n){
int new_array[12];
int count;
count = 0;
for (int i=0; i < n; i++) {
for (int j=0; j < m; j += n) {
new_array[count++] = i + j;
}
}
for (int i=0; i < m * n; i++) {
array[i] = new_array[i];
}
}
This algorithm works for any number of rows an columns:
for (std::size_t i = 0; i < col; i++) {
for (std::size_t j = 0; j < row; j++) {
transpose[c++] = array[j * col + i];
}
}
I have a problem with indexing a a 2D matrix declare as pointer.
Here is what I am doing
Compute(int *matrix, int rows, int cols )
{
int i, j;
for(j = 1; j < cols; j++)
{
for(i = 0; i < rows; i++)
{
matrix[j][i] = 5; //what is wrong with this line?
}
}
}
Error: subscripted value is neither array nor pointer
Any help?
thanks
For a 2D array pointer should be double pointer array (**matrix).In your code matrix is declared as a single dimension (*matrix) array in function arguments. It should be **matrix
Compute(int **matrix, int rows, int cols )
{
int i, j;
for(j = 1; j < cols; j++)
{
for(i = 0; i < rows; i++)
{
matrix[j][i] = 5;
}
}
}