How to copy a "double pointer"? - c

I'm a novice in C. I have a function with such a structure (this code is not reproducible, this is "pseudo-code", but I hope it's enough to explain my problem):
unsigned** myfunction(double*** A, unsigned nx, unsigned ny, unsigned nz){
unsigned* cells[nz-1];
unsigned totallength = 0;
unsigned lengths[nz-1];
unsigned** bottomTypes = function1(A, nx, ny, 0);
for(unsigned k=0; k<nz-1; k++){
unsigned** topTypes = function1(A, nx, ny, k+1);
unsigned** cellTypes = function2(bottomTypes, topTypes);
unsigned length
unsigned** goodcells = function3(cellTypes, &length);
cells[k] = malloc(length * sizeof(unsigned));
for(unsigned l=0; l<length; l++){
cells[k][l] = goodcells[0][l] + k;
}
lengths[k] = length;
totallength += length;
bottomTypes = function1(A, nx, ny, k+1); // the same as topTypes
}
unsigned** out = malloc(4 * sizeof(unsigned*));
......
......
return out;
}
As you can see, at the end of the loop, I do bottomTypes = function1(A, nx, ny, k+1); which is the same as topTypes previousy introduced. Thus function1(A,nx,ny,k+1) is called twice. That's because I've not been able to copy topTypes in bottomTypes. The code produced the expected output when I do like this.
Instead of doing like this, to avoid the doube call, I've tried
**bottomTypes = **topTypes;
or
bottomTypes = malloc((nx-1) * sizeof(unsigned*));
for ( int i = 0; i < nx-1; ++i ){
bottomTypes[i] = malloc((ny-1)*sizeof(unsigned));
memcpy(bottomTypes[i], topTypes[i], ny-1);
}
The code compiles but I don't get the expected resut when I do that.
What is the right way to copy topTypes into bottomTypes ?
I hope this is clear. Otherwise do not hesitate to say me it's not clear and I'll try to make a reproducibe exampe, but it's not easy. I've found similar questions on SO but none of them allows me to solve my issue.
Edit
Below is a complete reproducibe example. Not very minimal, I admit.
#include <stdlib.h> // for malloc
#include <stdio.h> // for printf
// function to create a "three-dimensional array" (I know this is not the correct wording)
// from a given function
double*** fun2array(double f(unsigned,unsigned,unsigned), unsigned nx, unsigned ny, unsigned nz){
double*** out = (double***) malloc(nx * sizeof(double**));
for(unsigned i=0; i<nx; i++){
out[i] = (double**) malloc(ny * sizeof(double*));
for(unsigned j=0; j<ny; j++){
out[i][j] = (double*) malloc(nz * sizeof(double));
for(unsigned k=0; k<nz; k++){
out[i][j][k] = f(i,j,k);
}
}
}
return out;
}
// a three-dimensional array
double fun(unsigned i, unsigned j, unsigned k){
return i+j+k;
}
double*** A = fun2array(fun, 2, 3, 4);
// function to "slice" a 3d-array to a 2D-array (a "matrix")
double** toMatrix(double*** A, unsigned nx, unsigned ny, unsigned k){
double** out = (double**) malloc(nx * sizeof(double*));
for(unsigned i=0; i<nx; i++){
out[i] = (double*) malloc(ny * sizeof(double));
for(unsigned j=0; j<ny; j++){
out[i][j] = A[i][j][k];
}
}
return out;
}
// function to convert double matrix to integer matrix
unsigned** floorMatrix(double** M , unsigned nx, unsigned ny){
unsigned** out = (unsigned**) malloc(nx * sizeof(unsigned*));
for(unsigned i=0; i<nx; i++){
out[i] = (unsigned*) malloc(ny * sizeof(unsigned));
for(unsigned j=0; j<ny; j++){
out[i][j] = (unsigned) M[i][j];
}
}
return out;
}
// function to sum 2 "matrices"
unsigned** matricialSum(unsigned** M1, unsigned** M2, unsigned nx, unsigned ny){
unsigned** out = (unsigned**) malloc(nx * sizeof(unsigned*));
for(unsigned i=0; i<nx; i++){
out[i] = (unsigned*) malloc(ny * sizeof(unsigned));
for(unsigned j=0; j<ny; j++){
out[i][j] = M1[i][j] + M2[i][j];
}
}
return out;
}
unsigned myfunction(double*** A, unsigned nx, unsigned ny, unsigned nz){
unsigned** bottomTypes = floorMatrix(toMatrix(A, nx, ny, 0), nx, ny);
unsigned** cellTypes;
for(unsigned k=0; k<nz-1; k++){
unsigned** topTypes = floorMatrix(toMatrix(A, nx, ny, k+1), nx, ny);
cellTypes = matricialSum(bottomTypes, topTypes, nx, ny);
bottomTypes = floorMatrix(toMatrix(A, nx, ny, k+1), nx, ny); // the same as topTypes
}
return cellTypes[0][0];
}
int main(){
unsigned result = myfunction(A, 2, 3, 4);
printf("result:%u\n", result);
return 0;
}
2nd edit
I have a solution, but surey not optimal:
unsigned** copyMatrix(unsigned** M, unsigned nx, unsigned ny){
unsigned** MM = malloc(nx * sizeof(unsigned*));
for(unsigned i=0; i<nx; i++){
MM[i] = malloc(ny * sizeof(unsigned));
for(unsigned j=0; j<ny; j++){
MM[i][j] = M[i][j];
}
}
return MM;
}
Then in the example code I free bottomTypes and then I do
unsigned** bottomTypes = copyMatrix(topTypes, nx-1, ny-1);

I finally understand your question, you write **bottomTypes = **topTypes; in place of bottomTypes = topTypes;. This is simply replace pointer by another.
However there are a lot of potential issue with your code, you have memory leak, you use ThreeStar, you cast return of malloc, etc. If your purpose to use C is to be fast, I advice you to change your data structure. malloc() is expensive and unless you want to be able to swap two lines of your matrix with O(1), there are no need to have one malloc for every lines of yours matrix.
So:
Do I cast the result of malloc?
You could use FAM if you don't want too many malloc()
You have memory leak each time you drop topTypes and bottomTypes or cellTypes, I suppose it only in your [mcve].
In your orignal code you use VLA, this should be use carefully.
You use unsigned instead of size_t for index, not a big problem if you don't use very big matrix.
Your [mcve] with little fix, memory leak everywhere:
#include <stdlib.h> // for malloc
#include <stdio.h> // for printf
// function to create a "three-dimensional array" (I know this is not the
// correct wording)
// from a given function
double ***fun2array(double (*f)(size_t, size_t, size_t), size_t nx, size_t ny,
size_t nz) {
double ***out = malloc(nx * sizeof *out);
for (size_t i = 0; i < nx; i++) {
out[i] = malloc(ny * sizeof *out[i]);
for (size_t j = 0; j < ny; j++) {
out[i][j] = malloc(nz * sizeof *out[i][j]);
for (size_t k = 0; k < nz; k++) {
out[i][j][k] = f(i, j, k);
}
}
}
return out;
}
// a three-dimensional array
double fun(size_t i, size_t j, size_t k) { return i + j + k; }
// function to "slice" a 3d-array to a 2D-array (a "matrix")
double **toMatrix(double ***A, size_t nx, size_t ny, size_t k) {
double **out = malloc(nx * sizeof *out);
for (size_t i = 0; i < nx; i++) {
out[i] = malloc(ny * sizeof *out[i]);
for (size_t j = 0; j < ny; j++) {
out[i][j] = A[i][j][k];
}
}
return out;
}
// function to convert double matrix to integer matrix
unsigned **floorMatrix(double **M, size_t nx, size_t ny) {
unsigned **out = malloc(nx * sizeof *out);
for (size_t i = 0; i < nx; i++) {
out[i] = malloc(ny * sizeof *out[i]);
for (size_t j = 0; j < ny; j++) {
out[i][j] = M[i][j];
}
}
return out;
}
// function to sum 2 "matrices"
unsigned **matricialSum(unsigned **M1, unsigned **M2, size_t nx, size_t ny) {
unsigned **out = malloc(nx * sizeof *out);
for (size_t i = 0; i < nx; i++) {
out[i] = malloc(ny * sizeof *out[i]);
for (size_t j = 0; j < ny; j++) {
out[i][j] = M1[i][j] + M2[i][j];
}
}
return out;
}
unsigned myfunction(double ***A, size_t nx, size_t ny, size_t nz) {
unsigned **bottomTypes = floorMatrix(toMatrix(A, nx, ny, 0), nx, ny);
unsigned **cellTypes = bottomTypes;
for (size_t k = 1; k < nz; k++) {
unsigned **topTypes = floorMatrix(toMatrix(A, nx, ny, k), nx, ny);
cellTypes = matricialSum(bottomTypes, topTypes, nx, ny);
bottomTypes = topTypes;
}
return cellTypes[0][0];
}
int main(void) {
double ***A = fun2array(fun, 2, 3, 4);
unsigned result = myfunction(A, 2, 3, 4);
printf("result:%u\n", result);
}

Related

Dynamically allocating a 3D matrix in C

So I've got a 2D Array which I am creating like this:
int** init_grid(int cell_grid_size) {
// matrix variables
int *memory_grid;
int **matrix;
int i;
int j;
// memory for matrix
memory_grid = malloc(cell_grid_size * cell_grid_size * sizeof(int));
matrix = malloc(cell_grid_size * sizeof(int *));
// fill matrix with rows
for(i = 0; i < cell_grid_size; i++) {
matrix[i] = &memory_grid[i*cell_grid_size];
}
// return fresh matrix
return matrix;
}
As you can see it's initialising a matrix of integers. However, I'd like to to initialize a matrix of integer arrays of size 2 (ie a 3D Matrix) but I can't quite seem to get my head around how to add the next dimension.
Any help would be greatly appreciated.
void grid_init(int* matrix, unsigned int xsize, unsigned int ysize, unsigned int unsigned int zsize)
{
unsigned int matrix_size;
// flatten matrix size in Byte
matrix_size = xsize*ysize*zsize*sizeof(int);
matrix = (int*)malloc(matrix_size);
memset(matrix, 0, sizeof(matrix_size);
}
Once matrix is built, you can loop through it using that loop:
void grid_fill(int* matrix, int value, unsigned int xsize, unsigned int ysize, unsigned int zsize)
{
int i,j,k;
for(k=0; k<zsize; k++)
{
for(i=0; i<ysize; i++)
{
for(j=0; j<xsize; j++)
{
matrix[j+i*xsize+k*ysize*xsize] = value;
}
}
}
}
For an int *** pointing to an array of pointers of type int **. Each pointing to an int *. Each int * pointer to an array of int.
Allocation checks for NULL omitted for brevity.
int*** init_grid(size_t xsize, size_t ysize, size_t zsize) {
int ***matrix = malloc(sizeof matrix[0] * xsize);
for (x = 0; x < xsize; x++) {
matrix[x] = malloc(sizeof matrix[x][0] * ysize);
for (y = 0; y < ysize; y++) {
matrix[x][y] = malloc(sizeof matrix[x][y][0] * zsize);
// or to zero-out the `int` data
matrix[x][y] = calloc(zsize, sizeof matrix[x][y][0]);
}
}
return matrix;
}
Use size_t for array indexing and sizing.
To free:
void free_grid(int ***matrix, size_t xsize, size_t ysize) {
if (matrix) {
for (x = 0; x < xsize; x++) {
if (matrix[x]) {
for (y = 0; y < ysize; y++) {
free(matrix[x][y])
}
}
free(matrix[x]);
}
free(matrix);
}
}

Matrix operations for arbitrary data types in C

Say I have some function that performs a matrix operation (like a transpose) on a float array:
void transpose(float *result, const float *input, int rows, int cols){
int i,j;
for(i = 0; i < rows; i++){
for(j = 0; j < cols; j++){
result[rows*j+i] = input[cols*i+j];
}
}
}
This function will work for any data type with size sizeof(float). Can this function be modified to work with arrays of arbitrary data type, or is it necessary to have separate functions for each data type of different size (e.g. transpose_8, transpose_32, etc.)?
From a comment by Eugene Sh., you can pass void *, the size of the data, and the size of the types you're passing so it works for all types.
You have to convert these to char * so you can use pointer arithmetic, though.
Here's how you can do that:
void transpose(void *result, const void *input, int size, int rows, int cols)
{
int i, j;
char *r = result;
const char *i = input;
for( i = 0; i < rows; i++ )
{
for( j = 0; j < cols; j++ )
{
memcpy(r + size * (rows * j + i), i + size * (cols * i + j), size);
}
}
}
Can this function be modified to work with arrays of arbitrary data type?
Yes, you can pass a generic void * pointer and the size of a single element as a parameter, which is exactly how qsort() handles any kind of data type (source).
Here's a working example:
void transpose(void *result, const void *input, size_t rows, size_t cols, size_t element_size) {
unsigned char *input_ptr = (unsigned char *)input;
unsigned char *result_ptr = (unsigned char *)result;
size_t i, j;
for(i = 0; i < rows; i++) {
for(j = 0; j < cols; j++) {
unsigned char *in = input_ptr + element_size * (cols * i + j);
unsigned char *res = result_ptr + element_size * (rows * j + i);
memcpy(res, in, element_size);
}
}
}
You could also do this in-place using the same swapping technique as qsort() does:
void transpose_inplace(void *input, size_t n, size_t element_size) {
unsigned char *input_ptr = (unsigned char *)input;
size_t i, j;
for(i = 0; i < n; i++) {
for(j = 0; j < i; j++) {
unsigned char *a = input_ptr + element_size * (n * i + j);
unsigned char *b = input_ptr + element_size * (n * j + i);
size_t size = element_size;
while (size--) {
unsigned char tmp = *a;
*a++ = *b;
*b++ = tmp;
}
}
}
}
I'm using n here since to transpose in-place you need a square matrix where rows = cols = n.

Why Segmentation fault is happening in this situation? Openmp problems

After writing a sequential program, I need to parallelize it. Here is a small part, which for some reason does not work. When N > 64 and 4 threads, the program starts to produce a segmentation error. And with 2 threads everything works fine. I tried to set the environment variable KMP_STACK_SIZE = 128m, but this did not help me. What could be the problem?
#include <omp.h>
void setMatrix(double *matrix, int size) {
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++) {
if (i == j) {
matrix[i * size + j] = 2;
} else
matrix[i * size + j] = 1;
}
}
void setVector(double *vector, int size, int value) {
for (int i = 0; i < size; i++) {
vector[i] = value;
}
}
void clearVec(double *vector, int size) {
for (int i = 0; i < size; i++) {
vector[i] = 0;
}
}
void mulMatrAndVec(double *result, const double *matrix, const double *vector, int size) {
clearVec(result, size);
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
result[i] += matrix[i * size + j] * vector[j];
}
}
}
void subVectors(double *result, const double *vector1, const double *vector2, int size) {
for (int i = 0; i < size; i++) {
result[i] = vector1[i] - vector2[i];
}
}
void mulMatrAndVecMP(double *result, const double *matrix, const double *vector, int place, int blockSize, int size) {
for (int i = place; i < (place + blockSize); i++) {
for (int j = 0; j < size; j++) {
result[i] += matrix[i * size + j] * vector[j];
}
}
}
int main(int argc, char *argv[]) {
int N = 68;
double *A = (double *) malloc(N * N * sizeof(double));
double *x = (double *) malloc(N * sizeof(double));
double *b = (double *) malloc(N * sizeof(double));
double *u = (double *) malloc(N * sizeof(double));
double *r1 = (double *) malloc(N * sizeof(double));
double *r2 = (double *) malloc(N * sizeof(double));
double *z = (double *) malloc(N * sizeof(double));
double *vec1 = (double *) malloc(N*N * sizeof(double));
double *vec2 = (double *) malloc(N * sizeof(double));
double a = 0;
double bt = 0;
int threadNum, threadCount;
setMatrix(A, N);
setVector(x, N, 0);
setVector(b, N, N + 1);
mulMatrAndVec(vec1, A, x, N);
subVectors(r1, b, vec1, N);
clearVec(vec1, N);
memcpy(z, r1, N * sizeof(double));
memcpy(r2, r1, N * sizeof(double));
omp_set_num_threads(4);
threadCount = omp_get_num_threads();
#pragma omp parallel private(threadNum) shared(threadCount, vec1, A, z)
{
threadNum = omp_get_thread_num();
mulMatrAndVecMP(vec1, A, z, (threadNum * N) / threadCount, N / threadCount, N);
}
free(A);
free(x);
free(b);
free(r1);
free(r2);
free(z);
free(vec1);
free(vec2);
free(u);
return 0;
}
The problem is that you call
threadCount = omp_get_num_threads();
outside the parallel block so it's 1 and your loop inside
mulMatrAndVecMP(vec1, A, z, (threadNum * N) / threadCount, N / threadCount, N);
goes out of bounds.
Setting
threadCount = 4
instead should fix your problem.
As you can read here the call returns the number of threads in the current team, and there's no current team.
Edit: be careful in case N is not divisible by the number of threads: your code skips some lines of the multiplication.

C multithreading slower than single-threading when multiplying matrices

I'm using theads in my C code to make the code faster, but it actually makes it worse.
I have a matrix and a matrix_operation class :
struct matrix
{
char *name;
size_t rows;
size_t columns;
double *value;
};
typedef struct matrix_operation matrix_operation;
struct matrix_operation
{
matrix r;
matrix m1;
matrix m2;
size_t row;
};
To multiply the matrices, I use these functions :
matrix matrix_mul(char *name, matrix m1, matrix m2, size_t replace)
{
matrix r = matrix_init(name, m1.rows, m2.columns);
matrix_operation *mat = malloc(sizeof *mat * m1.rows);
pthread_t *th = malloc(sizeof *th * m1.rows);
for (size_t i = 0; i < m1.rows; i++)
{
matrix_operation param = {r, m1, m2, i};
mat[i] = param;
pthread_create(&th[i], NULL , matrix_mul_th, &mat[i]);
}
for (size_t i = 0; i < m1.rows; i++)
{
pthread_join(th[i], NULL);
}
free(mat);
free(th);
if (replace == 1)
matrix_free(m1);
else if (replace == 2)
matrix_free(m2);
else if (replace == 3)
{
matrix_free(m1);
matrix_free(m2);
}
return r;
}
void *matrix_mul_th(void *arg)
{
matrix_operation mat = *(matrix_operation*)arg;
for (size_t j = 0; j < mat.m2.columns; j++)
{
double sum = 0;
for (size_t k = 0; k < mat.m1.columns; k++)
sum += matrix_get(mat.m1,mat.row,k) * matrix_get(mat.m2,k,j);
matrix_put(mat.r,mat.row,j,sum);
}
return NULL;
}
Do you have any idea why the problem may be ? And how to improve the code ?
The matrices are stored as a 1D array.
Thanks a lot for your time,
Lucas

C - Sorting 3d string array by specific column

I have code example which sorts 3d string array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
static char * rand_string(size_t ssize)
{
char * str = malloc(sizeof(char) * ssize);
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
if (ssize) {
--ssize;
for (size_t n = 0; n < ssize; n++) {
int key = rand() % (int) (sizeof charset - 1);
str[n] = charset[key];
}
str[ssize] = '\0';
}
return str;
}
char *** init_array(char *** array, int n_rows, int n_cols, int ssize)
{
int i, j;
array = malloc(n_rows * sizeof(char **));
for (i = 0; i < n_rows; i++)
{
array[i] = malloc(n_cols * sizeof(char *));
for (j = 0; j < n_cols; j++)
array[i][j] = malloc(ssize * sizeof(char));
}
return array;
}
void gen_array(char *** array, int n_rows, int n_cols, int ssize)
{
int i, j, k;
for (i = 0; i < n_rows; i++)
for (j = 0; j < n_cols; j++)
snprintf(array[i][j], ssize, "%s", rand_string(ssize));
}
int str_compare(const void * a, const void * b)
{
const char *pa = **(const char ***) a;
const char *pb = **(const char ***) b;
// printf("debug: a = %s\n", **(const char ***) a);
return strcmp(pa, pb);
}
void print_array(char *** array, int n_rows, int n_cols)
{
int i, j;
for (i = 0; i < n_rows; i++) {
for (j = 0; j < n_cols; j++)
printf("%s ", array[i][j]);
printf("\n");
}
}
int main(void)
{
int n_rows = 3, n_cols = 5, ssize = 10;
char *** z;
z = init_array(z, n_rows, n_cols, ssize);
gen_array(z, n_rows, n_cols, ssize);
print_array(z, n_rows, n_cols);
printf("\n");
qsort(z, 3, sizeof(char *), str_compare);
print_array(z, n_rows, n_cols);
return 0;
}
with the following output, where are origin array and sorted array (these are example values and randomness doesn't matter):
nwlrbbmqb hcdarzowk kyhiddqsc dxrjmowfr xsjybldbe
fsarcbyne cdyggxxpk lorellnmp apqfwkhop kmcoqhnwn
kuewhsqmg bbuqcljji vswmdkqtb xixmvtrrb ljptnsnfw
fsarcbyne cdyggxxpk lorellnmp apqfwkhop kmcoqhnwn
kuewhsqmg bbuqcljji vswmdkqtb xixmvtrrb ljptnsnfw
nwlrbbmqb hcdarzowk kyhiddqsc dxrjmowfr xsjybldbe
I am looking for a way to sort by another column (second or third). Is it possible?
Thanks.
You can sort the matrix along its second column with this sorting function:
int str_compare2(const void * a, const void * b) {
const char *pa = ((const char ***)a)[0][1];
const char *pb = ((const char ***)b)[0][1];
return strcmp(pa, pb);
}
Changing the 1 into 2 will sort along the third column, etc.
Note that you should invoke qsort this way:
qsort(z, 3, sizeof(char **), str_compare);
z is an array of char **, not char *. On most architectures, sizeof(char*) == sizeof(char **), so there is no difference, but for consistency and readability, using the correct type is advisable.

Resources