Search code examples
cmatrixtranspose

How to transpose a matrix and return pointer?


I have to do this exercise: given a matrix, write a function to transpose that matrix. It has to return a pointer to that matrix.

These are key points: (1) Write a matrix constructor function.

(2) Create the function with the help of the matrix constructor.

(3) Transpose the matrix.

(4) Print the matrix.

(5) Free the allocated memory.

(6) Close the file.

(For the moment, let's ignore steps 4, 5 and 6)

(1), and (2) the matrix constructor function is pretty simple, because it takes 3 parameters: "pointer to matrix", "rows" and "columns". Here's my code:

void matrix_constructor(struct matrix *mat, size_t rows, size_t cols) {
    mat->rows = rows; mat->cols = cols; 
    mat->data = calloc(rows * cols, sizeof(double)); 
}

it works.

(3) (This is the critical point). Here's my code:

struct matrix *mat_transpose(const struct matrix *mat) {
    struct matrix *out;

The error is located here. It's a warning (green squiggle): the debugger warned me I'm using uninitialized memory. But I've initialized it in the next lines. Why do I have this warning? This warning stops me from running the program; this is strange because a warning could be ignored, right?

    out->rows = mat->cols; 
    out->cols = mat->rows; 
    out->data = mat->data; 
    for (size_t r = 0; r < out->rows; ++r) {
        for (size_t c = 0; c < out->cols; ++c) {
            out->data[r * out->cols + c] = mat->data[r * mat->rows + c]; 
        }
    }
    return out; 
}

.....

This is the reproducible example:

matrix.h:

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h> 
#include <stdio.h>

struct matrix {
    size_t rows, cols;
    double *data;
};
extern struct matrix *mat_transpose(const struct matrix *mat);

matrix.c:

#include "matrix.h"

struct matrix *mat_transpose(const struct matrix *mat) {
    struct matrix *out; 
    out->rows = mat->cols; 
    out->cols = mat->rows; 
    out->data = mat->data; 
    for (size_t r = 0; r < out->rows; ++r) {
        for (size_t c = 0; c < out->cols; ++c) {
            out->data[r * out->cols + c] = mat->data[r * mat->rows + c]; 
        }
    }
    return out; 
} 

.....

To sum up:

Why do I have this warning? Could you give me a detailed explanation about that?

EDIT: I've edited matrix_transpose function and it works. Here's the code:

struct matrix *mat_transpose(const struct matrix *mat) {
    struct matrix *out = calloc(mat->rows * mat->cols, sizeof(double));
    if (out == NULL) {
        return NULL; 
    }
    out->rows = mat->cols; 
    out->cols = mat->rows; 
    out->data = mat->data; 
    for (size_t r = 0; r < out->rows; ++r) {
        for (size_t c = 0; c < out->cols; ++c) {
            out->data[r * out->cols + c] = mat->data[r * mat->rows + c]; 
        }
    }
    return out; 
}

Now, the mat_fprint function:

void matrix_fprint(const struct matrix *m, FILE *f) {
    size_t rows = m->rows; 
    size_t cols = m->cols; 
    double *data = m->data; 

    for (size_t r = 0; r < rows; ++r) {
        for (size_t c = 0; c < cols; ++c) {
            double value = 0; 
            value = data[r * cols + c]; 
            fprintf(f, "%.4f", value); 
        }
    }
}

It doesn't have errors; but when I compile it, in the file I don't see anything (only one line of code, but it's not the entire matrix) I don't know why.

EDIT 2: I've added \t and \n and I got the same result

void matrix_fprint(const struct matrix *m, FILE *f) {
    size_t rows = m->rows; 
    size_t cols = m->cols; 
    double *data = m->data; 

    for (size_t r = 0; r < rows; ++r) {
        for (size_t c = 0; c < cols; ++c) {
            double value = 0; 
            value = data[r * cols + c]; 
            fprintf(f, "%.4f\t", value); 
        }
        fprintf(f, "\n"); 
    }
}

The output on file is the same.

3rd EDIT: This is hopefully, the final reproducible example.

matrix.h:

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h> 
#include <stdio.h>

struct matrix {
    size_t rows, cols;
    double *data;
};
extern struct matrix *mat_transpose(const struct matrix *mat);

matrix.c:

#include "matrix.h"

void matrix_constructor(struct matrix *mat, size_t rows, size_t cols) {
    mat->rows = rows; mat->cols = cols;
    mat->data = calloc(rows * cols, sizeof(double));
}

struct matrix *mat_transpose(const struct matrix *mat) {
    // allocate the matrix structure
    struct matrix *out = calloc(sizeof(*out), 1);
    if (out == NULL) {
        return NULL;
    }
    // construct the transposed matrix with rows and cols arguments swapped
    matrix_constructor(out, mat->cols, mat->rows);
    if (out->data == NULL) {
        free(out);
        return NULL;
    }
    // set the transposed data
    for (size_t r = 0; r < mat->rows; ++r) {
        for (size_t c = 0; c < mat->cols; ++c) {
            out->data[c * out->rows + r] = mat->data[r * mat->rows + c];
        }
    }
    return out;
}

void matrix_fprint(const struct matrix *m, FILE *f) {
    size_t rows = m->rows; 
    size_t cols = m->cols; 
    double *data = m->data; 

    for (size_t r = 0; r < rows; ++r) {
        for (size_t c = 0; c < cols; ++c) {
            double value = 0; 
            value = data[r * cols + c]; 
            fprintf(f, "%.4f\t", value); 
        }
        fprintf(f, "\n"); 
    }
}

void matrix_destructor(struct matrix *mat) {
    free(mat->data); 
}

int main(void) {
    struct matrix A; 
    matrix_constructor(&A, 2, 3); 
    A.data[0] = 4.5678;
    A.data[1] = 78.9876;
    A.data[2] = 67.9876; 
    A.data[3] = 4.7896;
    A.data[4] = 2.6789;
    A.data[5] = 1.1122;
    
    mat_transpose(&A); 
    FILE *f = fopen("matrix transpose.txt", "w"); 
    matrix_fprint(&A, f); 

    matrix_destructor(&A); 
    fclose(f); 
    return 0; 
}

The problem is that when I compile the code, I read in the file the original matrix (matrix A), and not the transpose matrix.

Hypothesis: this could happen because when matrix_transpose returns the value, it's not assigned to any struct variable.

But when I try to create, for example, struct matrix B it doesn't work as well. Why?


Solution

  • You need to allocate both the matrix structure and the matrix data. You can use matrix_constructor for that:

    struct matrix *mat_transpose(const struct matrix *mat) {
        // allocate the matrix structure
        struct matrix *out = calloc(sizeof(*out), 1);
        if (out == NULL) {
            return NULL; 
        }
        // construct the transposed matrix with rows and cols arguments swapped
        matrix_constructor(out, mat->cols, mat->rows);
        if (out->data == NULL) {
            free(out);
            return NULL;
        }
        // set the transposed data
        for (size_t r = 0; r < mat->rows; ++r) {
            for (size_t c = 0; c < mat->cols; ++c) {
                out->data[c * out->rows + r] = mat->data[r * mat->rows + c]; 
            }
        }
        return out; 
    }