Difficulty creating a contiguous 2D array on the heap - c

I am currently implementing an N x 2 matrix of floats on the heap as follows:
float **matrix = malloc(sizeof(float*) * n_cols);
for (int i = 0; i < n_cols; ++i) {
matrix[i] = malloc(sizeof(float) * 2);
}
The elements of matrix are not contiguous in memory, making this data structure cache unfriendly (as I understand it). I am trying to re-write the above to create a genuine 2D array on the heap. Based on some previous SO posts, I tried the following:
float (*matrix)[2] = malloc(sizeof(float) * n_cols * 2);
However, this lead to a segmentation fault when I ran my code.

If you want the whole array to be contiguous then you need to declare it as follows.
float *matrix = malloc(n1 * n2 * sizeof(float));
Does this help. Note the second way the matrix has been allocated.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
size_t r = 0;
size_t c = 0;
int rows = 82;
int columns = 30;
float *matrix = malloc(rows * columns * sizeof(float));
for(r = 0; r < rows; r++) {
printf("%zu - ", r);
for(c = 0; c < columns; c++) {
printf("%zu|", c);
matrix[r + r*c] = 1.0;
}
printf("\n");
}
float **matrix2 = malloc(rows * sizeof(float*));
for(r = 0; r < rows; r++) {
matrix2[r] = malloc(columns * sizeof(float));
}
for(r = 0; r < rows; r++) {
printf("%zu - ", r);
for(c = 0; c < columns; c++) {
printf("%zu|", c);
matrix2[r][c] = 1.0;
}
printf("\n");
}
free(matrix);
for(r = 0; r < rows; r++) {
free(matrix2[r]);
}
free(matrix2);
return 0;
}
You can find a benchmark with the code here...
https://github.com/harryjackson/doc/blob/master/c/cache_locality_2d_array_test.c

I think you want something like this.
float ** matrix = malloc(sizeof(float) * ((n_col * 2) + (n_col * sizeof(float*));
for(i = 0; i < n_col; i++)
{
matrix[i] = matrix + (n_col *sizeof(float*)) + ((i * 2) *sizeof(float));
}
The size of your matrix is 2* n_col, however the first index into your matrix is going to be a pointer to a column. You have to allocate additional space for these pointers. This is where the (n_col * sizeof(float *)) comes into play. Each row is of size (2 * sizeof(float)), so each of the first indexed in the matrix need to point to an array of memory (2 * sizeof(float)) bytes away from the last one.
It looks something like this.
m[0] m[1] m[2]
matrix matrix + 1 * (2 * sizeof(float)) matrix + 2 * (2 * sizeof(float))
The second index deference a location into the memory pointed to by m[x].

Related

Why my code is not running for finding the determinant?

I want to find the determinant of a 3*3 matrix but am not sure why is it not giving a good answer?
#include <stdio.h>
int main()
{
int A[3][3];
for (int i = 1; i <= 3; i++)
{
for (int j = 1; j <= 3; j++)
{
scanf("%d", &A[i][j]);
}
}
int determinant = 0;
determinant = (A[1][1] * A[2][2] * A[3][3]) + (A[2][1] * A[3][2] * A[1][3]) + (A[1][2] * A[2][3] * A[3][1]) - (A[1][3] * A[2][2] * A[3][1]) - (A[3][2] * A[2][3] * A[1][1]) - (A[2][1] * A[1][2] * A[3][3]);
printf("Determinant of the matrix:%d", determinant);
return 0;
}
The bound of array is from 0 to N-1.
So you change bound your array.
#include <stdio.h>
int main()
{
int A[3][3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
scanf("%d", &A[i][j]);
}
}
int determinant = 0;
determinant = (A[1][1] * A[2][2] * A[0][0]) + (A[2][1] * A[0][2] * A[1][0]) + (A[1][2] * A[2][0] * A[0][1]) - (A[1][0] * A[2][2] * A[0][1]) - (A[0][2] * A[2][0] * A[1][1]) - (A[2][1] * A[1][2] * A[0][0]);
printf("Determinant of the matrix:%d", determinant);
return 0;
}
Your code will result in: "stack smashing detected" error
Usually, the compiler generates the stack smashing detected error in response to its defense mechanism against buffer overflows.
A buffer​ overflow occurs when the user input exceeds the buffer capacity. The following C code can cause the buffer to overflow if the user enters more than ten characters. In such a ​case, the compiler will throw the stack smashing detected error.
reference: https://www.educative.io/edpresso/what-is-the-stack-smashing-detected-error

Optimizing Matrix multiplication in C with Bit Packing

I'm currently attempting to write an algorithm for optimizing matrix multiplication over GF(2) using bit-packing. Both matrices A and B are provided in column major order so I start by copying A into row-major order and then packing the values into 8-bit integers and using parity checking to speed up operations. I need to be able to test square matrices of up to 2048x2048, however, my current implementation provides the correct answer up to 24x24 and then fails to compute the correct result. Any help would be appreciated.
//Method which packs an array of integers into 8 bits
uint8_t pack(int *toPack) {
int i;
uint8_t A;
A = 0;
for (i = 0; i < 8; i++) {
A = (A << 1) | (uint8_t)toPack[i];
}
return A;
}
//Method for doing matrix multiplication over GF(2)
void matmul_optimized(int n, int *A, int *B, int *C) {
int i, j, k;
//Copying values of A into a row major order matrix.
int *A_COPY = malloc(n * n * sizeof(int));
int copy_index = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
A_COPY[copy_index] = A[i + j * n];
copy_index++;
}
}
//Size of the data data type integers will be packed into
const int portion_size = 8;
int portions = n / portion_size;
//Pointer space reserved to store packed integers in row major order
uint8_t *compressedA = malloc(n * portions * sizeof(uint8_t));
uint8_t *compressedB = malloc(n * portions * sizeof(uint8_t));
int a[portion_size];
int b[portion_size];
for (i = 0; i < n; i++) {
for (j = 0; j < portions; j++) {
for (k = 0; k < portion_size; k++) {
a[k] = A_COPY[i * n + j * portion_size + k];
b[k] = B[i * n + j * portion_size + k];
}
compressedA[i * n + j] = pack(a);
compressedB[i * n + j] = pack(b);
}
}
//Calculating final matrix using parity checking and XOR on A and B
int cij;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
int cIndex = i + j * n;
cij = C[cIndex];
for (k = 0; k < portions; ++k) {
uint8_t temp = compressedA[k + i * n] & compressedB[k + j * n];
temp ^= temp >> 4;
temp ^= temp >> 2;
temp ^= temp >> 1;
uint8_t parity = temp & (uint8_t)1;
cij = cij ^ parity;
}
C[cIndex] = cij;
}
}
free(compressedA);
free(compressedB);
free(A_COPY);
}
I have two remarks:
you should probably initialize cij to 0 instead of cij = C[cIndex];. It seems incorrect to update the destination matrix instead of storing the result of A * B. Your code might work for small matrices by coincidence because the destination matrix C happens to be all zeroes for this size.
it is risky to compute the allocation size as malloc(n * n * sizeof(int)); because n * n might overflow with int n if int is smaller than size_t. Given the sizes you work with, it is probably not a problem here, but it is a good idea to always use the sizeof as the first operand to force conversion to size_t of the following ones:
int *A_COPY = malloc(sizeof(*A_COPY) * n * n);

How do I multiply two dynamic matrices in C?

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.

C: Realloc twodimensional array created by Malloc

I have a two-dimensional int array allocated as follows:
int **matrix = (int**)malloc(x * sizeof(int));
for (i = 0; i < x; i++)
matrix[i] = (int*)malloc(y * sizeof(int));
If I do realloc this array by the following code
int **matrix = (int**)realloc(matrix, x * sizeof(int));
for (i = 0; i < x; i++)
matrix[i] = (int*)malloc((y) * sizeof(int));
will there be any leftover "tails" of second dimension of the array and should I use free() function for them before reallocating, or they will go away themselves?
You will completely lose data in your matrix, so this is not really reallocing anything; you could just as well free and malloc the top-level array, getting possibly better performance. Furthermore your code would leak memory, because the 2nd level allocations are not freed.
Here is how you can resize the 2D matrix while keeping the current values intact, initializing the newly allocated cells to 0 and freeing any extra leftovers:
// matrix was allocated to x and y
// reallocate it to newx, newy
for (i = newx; i < x; i++) { /* free unneeded rows */
free(matrix[i]);
}
matrix = realloc(matrix, sizeof(*matrix) * newx);
for (i = x; i < newx; i++) { /* initialize the new row pointers */
matrix[i] = NULL;
}
for (i = 0; i < newx; i++) {
matrix[i] = realloc(matrix[i], sizeof(*matrix[i]) * newy);
for (int j = y; j < newy; j++)
matrix[i][j] = 0;
}

Multiplying two arrays in C

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.

Resources