C change pointer to structure - c

I'm not that familiar with C and try to add a row to a existing matrix structure with a function. This function will be used in a iteration loop.
In my code, I use the matrix PreparedData_B4 as reference matrix. In the first step I slice 3 rows out of PreparedData_B4 and create the matrix ActData. Afterwards I call the function add_row with the arguments mat In, mat **Out and mat Out1. Maybe there is also another idea to avoid the passing of the adress of ActData (mat **Out) and the ActData (mat Out1) itself. It was my only chance to get the right dimensions of Tmp.
EDIT: In this function, I create a temporary matrix Temp with the new dimensions. After *Out = &Tmp the new address is set and works fine in my opinion. (**Out)->n = 3, (**Out)->m = 4 and (**Out)->v[][] is accessable.
So far, so good.
After the function is completed, things go wrong. ActData->n = 0 and ActData->v[][] is not accessable.
Another questions is, how to free the memory of the "old" ActData?
#include <stdio.h>
#include <stdlib.h>
#define NELEMS(x) (int)(sizeof(x) / sizeof((x)[0]))
// Raw data
double raw_T7[][3] = {
{1800, 261.753, 1032.354},
{1750, 247.46, 1028.439},
{1700, 250.385, 1003.689},
{1243, 69.92, 816.569},
{670, 67.485, 614.319},
{533, 73.591, 533.15},
{509, 73.404, 517.456},
{485, 89.233, 515.994},
{460, 110.535, 501.412},
{435, 141.864, 471.876},
{411, 195.009, 480.623},
{386, 260.166, 529.444},
{361, 375.958, 462.411}
};
// Matrix structure
typedef struct {
int m, n;
double ** v;
} mat_t, *mat;
// Create new matrix
mat mat_new(int m, int n){
int i = 0;
mat out = malloc(sizeof(mat_t));
out->v = malloc(sizeof(double*) * m);
out->v[0] = calloc(sizeof(double), m * n);
for (i = 0; i < m; i++) out->v[i] = out->v[0] + n * i;
out->m = m;
out->n = n;
return out;
}
// Show matrix
void mat_show(mat A){
int i = 0, j = 0;
for(i = 0; i < A->m; i++) {
for (j = 0; j < A->n; j++) {
printf(" %8.3f", A->v[i][j]);
}
printf("\n");
}
printf("\n");
}
void add_row(mat In, mat **Out, mat Out1){
int i = 0, j = 0;
// Create new matrix
mat Tmp = mat_new(Out1->m + 1, Out1->n);
for (i = 0 ; i < Tmp->n ; i++) {
for(j = 0 ; j < Tmp->m ; j++){
Tmp->v[j][i] = In->v[j][i];
}
}
mat_show(Tmp);
// Delete old address
//free(Out1->v[0]);
//free(Out1->v);
//free(Out1);
*Out = &Tmp;
}
int main()
{
int i = 0, j = 0;
// Assign array address to first matrix structure
mat PreparedData_B4 = mat_new(NELEMS(raw_T7), NELEMS(raw_T7[0]));
double *ptr1[PreparedData_B4->m];
free(PreparedData_B4->v[0]);
free(PreparedData_B4->v);
PreparedData_B4->v = (double **)ptr1;
for (i = 0 ; i < PreparedData_B4->m ; i++) ptr1[i] = (double *)raw_T7 + i * NELEMS(raw_T7[0]);
// Create new matrix with the first 3 rows of PreparedData_B4
mat ActData = mat_new(3, PreparedData_B4->n);
for (i = 0 ; i < ActData->n ; i++) {
for(j = 0 ; j < ActData->m ; j++){
ActData->v[j][i] = PreparedData_B4->v[j][i];
}
}
puts("PreparedData_B4");
mat_show(PreparedData_B4);
puts("ActData");
mat_show(ActData);
puts("ActData with additional row");
add_row(PreparedData_B4, &ActData, ActData);
mat_show(ActData);
free(PreparedData_B4);
return 0;
}
SOLUTION:
Due the solid foundation of David C. Rankin and all the other responses my working example. Many thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NELEMS(x) (int)(sizeof(x) / sizeof((x)[0]))
// Raw data
double raw_T7[][3] = {
{1800, 261.753, 1032.354},
{1750, 247.46, 1028.439},
{1700, 250.385, 1003.689},
{1243, 69.92, 816.569},
{670, 67.485, 614.319},
{533, 73.591, 533.15},
{509, 73.404, 517.456},
{485, 89.233, 515.994},
{460, 110.535, 501.412},
{435, 141.864, 471.876},
{411, 195.009, 480.623},
{386, 260.166, 529.444},
{361, 375.958, 462.411}
};
// Matrix structure
typedef struct {
int m, n;
double *v;
} mat_t;
// Create new matrix
mat_t *mat_new (int m, int n)
{
mat_t *out = malloc (sizeof *out); /* allocate struct */
if (!out) {
perror ("malloc-out");
exit (EXIT_FAILURE);
}
out->v = malloc(sizeof *out->v * m * n); /* allocate for m * n doubles */
if (!out->v) {
perror ("malloc-out->v");
exit (EXIT_FAILURE);
}
out->m = m;
out->n = n;
return out;
}
// Show matrix
void mat_show(mat_t *A)
{
int i = 0, j = 0;
for(i = 0; i < A->m; i++) {
for (j = 0; j < A->n; j++)
printf(" %8.3f", (A->v)[i * A->n + j]);
putchar ('\n');
}
putchar ('\n');
}
void add_row(mat_t *In, mat_t **Out){
int i = 0, j = 0;
// Create new matrix
mat_t *Tmp = mat_new((*Out)->m + 1, (*Out)->n);
for (i = 0 ; i < Tmp->m ; i++) {
for(j = 0 ; j < Tmp->n ; j++){
(Tmp->v)[i * Tmp->n + j] = (In->v)[i * In->n + j];
}
}
// Delete old address
free((*Out)->v);
free(*Out);
// Assign new address
*Out = Tmp;
}
int main(void)
{
int rows = NELEMS(raw_T7), cols = NELEMS(raw_T7[0]);
int i = 0, j = 0;
// Assign array address to first matrix structure
mat_t *PreparedData_B4 = mat_new(rows, cols); /* allocate, set m & n */
/* copy raw_T7 to PreparedData_B4->v */
memcpy (PreparedData_B4->v, raw_T7, rows * cols * sizeof PreparedData_B4->v);
// Create new matrix with the first 3 rows of PreparedData_B4
mat_t *ActData = mat_new(3, PreparedData_B4->n);
for (i = 0 ; i < ActData->m ; i++) {
for(j = 0 ; j < ActData->n ; j++){
(ActData->v)[i * ActData->n + j] = (PreparedData_B4->v)[i * PreparedData_B4->n + j];
}
}
puts("PreparedData_B4");
mat_show(PreparedData_B4);
puts("ActData");
mat_show(ActData);
puts("ActData with additional row");
add_row(PreparedData_B4, &ActData);
mat_show(ActData);
free (PreparedData_B4->v);
free (PreparedData_B4);
return 0;
}

Before you can build the perfect house, you must build a solid foundation -- otherwise the house will not last.
You are confusing the use of pointers and allocated blocks of memory for storage of data. This is quite apparent in your mat_new() function. Think about it... You allocate for m pointers,
out->v = malloc(sizeof(double*) * m);
But then only use a single-pointer:
out->v[0] = calloc(sizeof(double), m * n);
(what are you using the other m - 1 pointers for??)
You look like you want to allocate a single block of memory to store your matrix values in, but then simulate a 2D array in your indexing (which is fine and is a very efficient approach) However, to do that, you do not use a double-pointer for v, you simply use a single-pointer (e.g. double *v;) This provides the benefit of a single-allocation and single-free for your stored data. (you still must free the struct itself)
Let's just take your mat_new (int m, int n) function and get that working properly and then output the data with your mat_show(mat_t *A) and finally free the memory we have allocated to that point, e.g.
// Create new matrix
mat_t *mat_new (int m, int n)
{
mat_t *out = malloc (sizeof *out); /* allocate struct */
if (!out) {
perror ("malloc-out");
exit (EXIT_FAILURE);
}
out->v = malloc(sizeof *out->v * m * n); /* allocate for m * n doubles */
if (!out->v) {
perror ("malloc-out->v");
exit (EXIT_FAILURE);
}
out->m = m;
out->n = n;
return out;
}
(note: I have removed the typedeffed pointer mat)
For your mat_show() function, you would then have:
// Show matrix
void mat_show(mat_t *A)
{
int i = 0, j = 0;
for(i = 0; i < A->m; i++) {
for (j = 0; j < A->n; j++)
printf(" %8.3f", (A->v)[i * A->n + j]);
putchar ('\n');
}
putchar ('\n');
}
(note: don't use printf to output a single-character, that is what putchar() is for -- though a good compiler will make that optimization for you)
If you put those functions together with a shortened example, you would have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NELEMS(x) (int)(sizeof(x) / sizeof((x)[0]))
// Raw data
double raw_T7[][3] = { {1800, 261.753, 1032.354},
{1750, 247.46, 1028.439},
{1700, 250.385, 1003.689},
{1243, 69.92, 816.569},
{670, 67.485, 614.319},
{533, 73.591, 533.15},
{509, 73.404, 517.456},
{485, 89.233, 515.994},
{460, 110.535, 501.412},
{435, 141.864, 471.876},
{411, 195.009, 480.623},
{386, 260.166, 529.444},
{361, 375.958, 462.411} };
// Matrix structure
typedef struct {
int m, n;
double *v;
} mat_t;
// Create new matrix
mat_t *mat_new (int m, int n)
{
mat_t *out = malloc (sizeof *out); /* allocate struct */
if (!out) {
perror ("malloc-out");
exit (EXIT_FAILURE);
}
out->v = malloc(sizeof *out->v * m * n); /* allocate for m * n doubles */
if (!out->v) {
perror ("malloc-out->v");
exit (EXIT_FAILURE);
}
out->m = m;
out->n = n;
return out;
}
// Show matrix
void mat_show(mat_t *A)
{
int i = 0, j = 0;
for(i = 0; i < A->m; i++) {
for (j = 0; j < A->n; j++)
printf(" %8.3f", (A->v)[i * A->n + j]);
putchar ('\n');
}
putchar ('\n');
}
int main (void)
{
int rows = NELEMS(raw_T7), cols = NELEMS(raw_T7[0]);
mat_t *PreparedData_B4 = mat_new(rows, cols); /* allocate, set m & n */
/* copy raw_T7 to PreparedData_B4->v */
memcpy (PreparedData_B4->v, raw_T7, rows * cols * sizeof PreparedData_B4->v);
mat_show (PreparedData_B4); /* output matrix */
free (PreparedData_B4->v);
free (PreparedData_B4);
}
(note: string.h was included to make the memcpy() function available to initialize out->v from raw_T7 in a single call )
Example Use/Output
$ ./bin/mat_prepare
1800.000 261.753 1032.354
1750.000 247.460 1028.439
1700.000 250.385 1003.689
1243.000 69.920 816.569
670.000 67.485 614.319
533.000 73.591 533.150
509.000 73.404 517.456
485.000 89.233 515.994
460.000 110.535 501.412
435.000 141.864 471.876
411.000 195.009 480.623
386.000 260.166 529.444
361.000 375.958 462.411
Memory Use/Error Check
$ valgrind ./bin/mat_prepare
==10301== Memcheck, a memory error detector
==10301== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10301== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10301== Command: ./bin/mat_prepare
==10301==
1800.000 261.753 1032.354
1750.000 247.460 1028.439
1700.000 250.385 1003.689
1243.000 69.920 816.569
670.000 67.485 614.319
533.000 73.591 533.150
509.000 73.404 517.456
485.000 89.233 515.994
460.000 110.535 501.412
435.000 141.864 471.876
411.000 195.009 480.623
386.000 260.166 529.444
361.000 375.958 462.411
==10301==
==10301== HEAP SUMMARY:
==10301== in use at exit: 0 bytes in 0 blocks
==10301== total heap usage: 3 allocs, 3 frees, 1,352 bytes allocated
==10301==
==10301== All heap blocks were freed -- no leaks are possible
==10301==
==10301== For counts of detected and suppressed errors, rerun with: -v
==10301== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
This is what it appears you were trying to accomplish. Let me know if I misinterpreted your intent or if you have further questions. Get your memory use correct first to provide a solid foundation and build from there.

Related

Pointer arrays allocated with malloc/calloc initializing with values other than 0

I have been given a school assignment in C to create a program that multiplies matrices. I will list assignment constraints below so people don't respond with questions as to why I am doing things this way.
Constraints from instructor:
Cannot use square brackets anywhere in code (use pointer notation instead)
Matrices A, B, C must be single integer pointer variables (int *A, *B, *C)
Can only use main function and those specified by header
Must compile with "gcc -ansi -Wall -o p2 p2.c"
I have not implemented the matrix multiplication function yet, as the issues I am having relate to either file reading or memory allocation.
The specific problem I am having is when I allocate space to the pointer matrix with either malloc OR calloc (tried both), the program inserts 33 in some places in the output instead of 0. I've tried everything at this point and am convinced my knowledge of pointers is fundamentally flawed.
p2.h (given by instructor)
#include <stdio.h>
#include <stdlib.h>
/* This function reads m, n, and p from the datafile.
It then allocates the correct amount of memory required for matrices
A, B, and C.
Then matrices A and B are filled from the datafile.
The values for m, n, and p are passed by reference, and are
thus filled in by this function
PARAMETERS in order are:
int ** matrix A
int ** matrix B
int ** matrix C
int * m The number of rows in matrix A
int * n The number of columns in matrix A and
The number of rows in matrix B
int * p The number of columns in matrix B
char * The name of the datafile, from the command line
*/
void read_matrices(int **, int **, int **, int *, int *, int *, char *);
/* This function prints a matrix. Rows and columns should be preserved.
PARAMETERS in order are:
int * The matrix to print
int The number of rows in the matrix
int The number of columns in the matrix
*/
void print_matrix(int *, int, int);
/* The two matrices A and B are multiplied, and matrix C contains the
result.
PARAMETERS in order are:
int * Matrix A
int * Matrix B
int * Matrix C
int m
int n
int p
*/
void mult_matrices(int *, int *, int *, int, int, int);
p2.c (sorry for the mess a lot of debugging went on)
#include <stdio.h>
#include <stdlib.h>
#include "./p2.h"
/* constants for testing */
#define cM 3
#define cN 2
#define cP 5
int main(int argc, char **argv) {
if (argc < 2) {
printf("Must include an argument.\n");
exit(1);
}
char *path = *(argv + 1);
int *m = (int *) malloc(sizeof(int));
int *n = (int *) malloc(sizeof(int));
int *p = (int *) malloc(sizeof(int));
*m = cM; *n = cN; *p = cP;
int i,j; /* loop counters */
/* allocate space for 2d pointer arrays */
int **A = NULL;
A = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(A+i) = (int *) malloc(*n * sizeof(int));
}
int **B = NULL;
B = (int **) malloc(*n * sizeof(int *));
for (i = 0; i < *n; i++) {
*(B+i) = (int *) malloc(*p * sizeof(int));
}
int **C = NULL;
C = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(C+i) = (int *) malloc(*p * sizeof(int));
}
/* write data to A */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
*(*(A+i)+j) = 0;
}
}
/* testing a */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
if (*(*(A+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to B */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
*(*(B+i)+j) = 0;
}
}
/* testing b */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
if (*(*(B+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to C */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
*(*(C+i)+j) = 0;
}
}
/* testing c */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
if (*(*(C+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
printf("Matrix A: \n");
print_matrix(*A, *m, *n);
printf("Matrix B: \n");
print_matrix(*B, *n, *p);
printf("Matrix C: \n");
print_matrix(*C, *m, *p);
return 0;
}
void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *path) {
FILE *fptr;
fptr = fopen(path, "r");
if (fptr == NULL) {
printf("Cannot open file: ./p2 [filename].txt\n");
exit(1);
}
/* get first 3 numbers from file, set m,n,p */
*m = fgetc(fptr);
fgetc(fptr);
*n = fgetc(fptr);
fgetc(fptr);
*p = fgetc(fptr);
fgetc(fptr);
/* read first matrix */
/* 1) calculate matrix size m x n
* 2) loop through malloc'ed matrix
* 3) each loop, insert char in loc
* 4) if next char NOT 10/32, add nextchar*10 to value in loc
*/
char cur;
while ( (cur = fgetc(fptr)) != EOF ) {
if (cur == 10 || cur == 32) {
/* do nothing :) */
} else {
*m = cur;
*n = cur;
*p = cur;
break;
}
}
printf("m: %c\n", *m);
printf("n: %c\n", *n);
printf("p: %c\n", *p);
printf("next: %c\n", fgetc(fptr));
fclose(fptr);
}
void print_matrix(int *X, int rows, int cols) {
int r, c;
int k = 0;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("\t%d", *(X+k));
k++;
}
printf("\n");
}
}
void mult_matrices(int *A, int *B, int *C, int m, int n, int p) {
}
d2.txt (data file)
3
2
4
1 2
3 4
5 6
7 8 9 10
11 12 13 14
Output: ./p2 d2.txt
[0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
Matrix A:
0 0
0 0
0 0
Matrix B:
0 0 0 0 0
0 33 0 0 0
Matrix C:
0 0 0 0 0
0 33 0 0 0
0 0 0 0 33
If you notice, I have some debug code that checks whether or not the current item in the array is 0. It seems to indicate that they are all 0, making me think it is a printing problem, but I am even more lost on what would be causing that. The ascii code for 33 is an exclamation point, but I am not sure what relevance it has.
Based on the function signatures you're supposed to use, you need to implement your 2D arrays as 1D with the correct index math. This will result in all memory being laid out contiguously, which is not at all guaranteed with the way you're allocating memory now (two calls to malloc for each matrix). For example:
#include <stdio.h>
#include <stdlib.h>
void print_matrix(int* A, int rows, int cols)
{
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
// If you want to treat A as a 2D matrix, this is where we have to do a bit of
// fancy index math to give you what double bracket notation [][] does for you
// r * cols gives you the index of the right row
// + c give you the column offset in that row
// add that offset to A then dereference
printf("%d\t", *(A + (r * cols + c)));
}
printf("\n");
}
}
int main(void)
{
// matrix A is supposed to be m by n
int* A;
// read these from file, or where ever they're supposed to come from
int m = 2;
int n = 10;
// Allocate the memory in one chunk. This makes the memory all contiguous, just the
// same as if you had done A[m][n]. However, the double call malloc for each int**
// matrix probably will not give you contiguous memory for the entire matrix. Each
// call to malloc is independent.
A = malloc(m * n * sizeof(int)); // or sizeof(*A) would be even better
if (A == NULL)
{
// handle error
}
// We can initialize values for A at this point, still not needing to care about
// rows or columns
for (int i=0; i<m*n; i++)
{
*(A + i) = i; // using i for a better visual when we print
}
print_matrix(A, m, n);
free(A);
return 0;
}
Demo
You are ovecomplicating simple things. Use pointers to arrays and allocate 2D array.
Use the correct type of your size variables.
Try to avoid side effects. Use parameters and function return values.
//this function is for the test purposes only
int writefile(const char *fn)
{
FILE *fo = fopen(fn, "w");
fprintf(fo,
"3\n"
"2\n"
"4\n"
"1 2\n"
"3 4\n"
"5 6\n"
"7 8 9 10\n"
"11 12 13 14\n");
fclose(fo);
}
void *allocIntMatrix(size_t rows, size_t cols)
{
int (*m)[cols] = malloc(rows * sizeof(*m));
return m;
}
void printIntMatrix(size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
printf("[%5d] ", m[row][col]);
}
printf("\n");
}
}
int readData(FILE *fi, size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
fscanf(fi, "%d", &m[row][col]);
}
}
return 0;
}
int main(int argc, char **argv)
{
size_t n,m,p;
writefile("a.aaa");
FILE *fi = fopen("a.aaa", "r");
fscanf(fi, "%zu", &m);
fscanf(fi, "%zu", &n);
fscanf(fi, "%zu", &p);
printf("n = %zu, m = %zu, p = %zu\n", n, m, p);
int (*A)[n] = allocIntMatrix(m, n);
int (*B)[p] = allocIntMatrix(n, p);
readData(fi, m, n, A);
readData(fi, n, p, B);
fclose(fi);
printIntMatrix(m, n, A);
printf("\n");
printIntMatrix(n, p, B);
return 0;
}
https://godbolt.org/z/adoEx1r4f
You need to check for errors (file, memory etc). I skipped it for the sake of simplicity of the example.

C - Function to allocate dynamically a 3 dimension array (using malloc)

I created this function to allocate dynamically a 3D array.
int ***create_3D_Array(int nb_block, int nb_lin, int nb_col) {
int i, j;
int ***A = (int***)malloc(nb_block * sizeof(int**));
for (i = 0; i <nb_col; i++) {
A[i] = (int**)malloc(nb_col * sizeof(int*));
for (j = 0; j < nb_lin; j++) {
A[i][j] = (int*)malloc(nb_lin * sizeof(int));
}
}
return A;
}
I then used it here
int ***all_blocks = NULL;
all_blocks = create_3D_Array(54, 5, 5);
However, it is not working correctly because when I want to give a value to my 6th block all_blocks[5], the program stops working.
Is there any error in my function ?
The dimensions are incorrect in your allocation loops. The outer loop should run to nb_block, the second malloc should allocate nb_lin * sizeof(int*) and the third malloc should allocate nb_col * sizeof(int).
Here is a corrected version:
int ***create_3D_Array(int nb_block, int nb_lin, int nb_col) {
int i, j;
int ***A = (int***)malloc(nb_block * sizeof(int**));
for (i = 0; i < nb_block; i++) {
A[i] = (int**)malloc(nb_lin * sizeof(int*));
for (j = 0; j < nb_lin; j++) {
A[i][j] = (int*)malloc(nb_col * sizeof(int));
}
}
return A;
}
Note that it might be simpler to use a direct 3D array:
int (*all_blocks)[5][5] = malloc(54 * sizeof(*all_blocks));

Passing argument makes a pointer without cast?

I'm having an issue with compling the code.
I keep getting these errors.
"C: 194 warning passing argument 3 of 'matrix_column_subtract' makes pointer from integer without a cast"
"C: 12 note: expected 'double**' but argument is type 'int'
"C: 194 error too few arguments to function 'matrix_column_subtract'
I think I know what is going on I'm calling matrix_column_multiply is a void and I need to be calling it a pointer pointer I think and I don't know how to chage that. If anyone has some idea on how I can get this to compile that would be highly appreciated!!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEBUG 0
#define MAX_ITER 10000
double *eigen (int n, double **A);
void qr_decomp (int n, double **A, double **Q, double **R);
void matrix_copy_column(double **msrc, int col1, double **mdst,int col2, int rows);
void matrix_column_subtract(double **m1, int c1, double **m2, int c2, int rows);
void matrix_column_multiply(double **m, int c, double k, int rows);
int main() {
int i, n = 126;
double *eig, **Am;
FILE *BinInp, *TxtOut;
/* Input Code: Reads bv, Am in binary form from CGrad.bin */
if ( (BinInp = fopen("CGrad.bin","r")) == NULL ) {
fprintf(stderr, "Cannot open matrix binary file INPUT... exiting\n");
exit(-1);
}
Am = (double**)malloc (n*sizeof(double*));
Am[0] = (double*)malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Am[i] = Am[0] + i*n;
}
for (i = 0; i < n; i++) {
if (i==0) { /* Read one extra line that is discarded (bv is still in bin file) */
if (!fread(Am[i], sizeof(double), n, BinInp)) {
fprintf(stderr, "Cannot read row Am[%03d] of matrix... exiting\n", i+1);
exit(1);
}
}
if (!fread(Am[i], sizeof(double), n, BinInp)) {
fprintf(stderr, "Cannot read row Am[%03d] of matrix... exiting\n", i+1);
exit(1);
}
}
if (fclose(BinInp) == EOF) {
fprintf(stderr, "Cannot close matrix binary file INPUT... exiting\n");
exit(-1);
}
/* COMPUTE EIGENVALUES HERE USING FUNCTIONS. RETURN EIGENVALUES (AS 1D VECTOR) TO eig. */
if (DEBUG) printf ("Calling eigen\n");
eig = eigen (n, Am);
/* Output Code: Writes eig in text form to Eigs.txt */
if ( (TxtOut = fopen("Eigs.txt", "w")) == NULL ) {
fprintf(stderr, "Cannot open matrix text file OUTPUT... exiting\n");
exit(-1);
}
for (i = 0; i < n; i++) {
fprintf (TxtOut, "%18.14e ", eig[i]);
}
if (fclose(TxtOut) == EOF) {
fprintf(stderr, "Cannot close matrix text file INPUT... exiting\n");
exit(-1);
}
return 0;
}
double* eigen (int n, double **Acur)
{
double err = 1, eps = 1e-2;
double ndenom, nnumer, temp;
double *eig, **Anex, **Qsub, **Rsub;
int i, j, k, iters = 1;
/* Malloc memory for the three matricies */
Anex = malloc (n*sizeof(double*));
Anex[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Anex[i] = Anex[0] + i*n;
}
Qsub = malloc (n*sizeof(double*));
Qsub[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Qsub[i] = Qsub[0] + i*n;
}
Rsub = malloc (n*sizeof(double*));
Rsub[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Rsub[i] = Rsub[0] + i*n;
}
/* Malloc memory for the return eig vector */
eig = malloc (n*sizeof(double));
for (i = 0; i < n; i++) {
eig[i] = 0;
}
/* Enter main iteration loop for eigenvalues */
while (err > eps && iters < MAX_ITER) {
/* QR Decompose Acur then find next iterate value in Anex */
qr_decomp (n, Acur, Qsub, Rsub);
// FIND NEXT ITERATE VALUE, PUT IN Anex.
/* Determine relative error change, reset "old" iterate value. */
ndenom = 0;
nnumer = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
temp = Anex[i][j]-Acur[i][j];
ndenom += temp*temp;
nnumer += Anex[i][j]*Anex[i][j];
Acur[i][j] = Anex[i][j];
}
}
err = sqrt(ndenom)/sqrt(nnumer);
/* Increment the iteration count and report error */
if (iters % 25 == 0) {
printf ("Error at end of iteration %05d = %14.10f %%\n", iters, 100*err);
}
++iters;
}
printf ("Error at end of iteration %05d = %14.10f\nCONVERGED.\n", iters-1, err);
if (iters == MAX_ITER) {
printf ("WARNING: MAX_ITER iterations reached!...\n");
}
/* Copy diagonal entries of Acur into eig for return to main */
for (i=0; i<n; i++) {
eig[i] = Acur[i][i];
}
return eig;
}
void qr_decomp (int n, double **Adec, double **myQ, double **myR)
{
int i, j, k; /* Loop Variables: this is all you should need! */
double **T, **S;
double r;
T = malloc (n*sizeof(double*));
T[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
T[i] = T[0] + i*n;
}
S = malloc (n*sizeof(double*));
S[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
S[i] = S[0] + i*n;
}
/* Main loop for decomposition */
for (i=0; i<n; i++) {
/* Column i of Q is initially column i of A */
matrix_copy_column(Adec,i,myQ,i,n);
/* For j < i-1, Perform the dot product between the j row of Q and the
i row of A to determine the R(j,i) value, then insure the Q i column
is orthogonal to all other Q columns by subtracting existing Q columns
from it. */
for (j = 0; j < i; j++) {
//r[j,i] = Qj^T * Ui
matrix_copy_column(myQ,j,T,0,n);
matrix_copy_column(Adec,i,S,0,n);
for (k=0; k<n; k++) {
r += T[k][0] * S[k][0];
}
/* Determine the R diagonal as the magnitude of the Q column, then
normalize the Q column (make it a unit vector). */
//Qi = Ui
myR[j][i] = r;
// Something wrong here.
// There is one parameter missing, as matrix_column_subtract needs 5 parameters and
// only 4 are given.
// Also, matrix_column_multiply is defined as returning a void, whereas the 3rd parameter
// of matrix_column_subtract should be a double **
matrix_column_subtract(myQ,i,matrix_column_multiply(T,0,r,n),j);
}
}
}
/* Copies a matrix column from msrc at column col1 to mdst at column col2 */
void matrix_copy_column(double **msrc, int col1, double **mdst,int col2, int rows) {
int i = 0;
for (i=0; i<rows; i++) {
mdst[i][col2] = msrc[i][col1];
}
}
/* Subtracts m2's column c2 from m1's column c1 */
void matrix_column_subtract(double **m1, int c1, double **m2, int c2, int rows) {
int i = 0;
for (i=0; i<rows; i++) {
m1[i][c1] -= m2[i][c2];
}
/*return m1;*/
}
void matrix_column_multiply(double **m, int c, double k, int rows) {
int i = 0;
for (i=0; i<rows; i++) {
m[i][c] *= k;
}
/*return m;*/
}
A problem is here.
matrix_column_subtract(myQ,i,matrix_column_multiply(T,0,r,n),j);
The relevant function signatures are:
void matrix_column_subtract(double **m1, int c1, double **m2, int c2, int rows);
void matrix_column_multiply(double **m, int c, double k, int rows);
Note that matrix_column_multiply returns void, but you're passing it in as if it were double **. I'm guessing the compiler is desperately trying to make it work and returned some sort of garbage integer.
These functions return void because they do their work directly on the matrix in question. matrix_column_multiply alters m. matrix_column_subtract alters m1.
To make it work, call matrix_column_multiply on T then pass T (now modified by the multiplication) into matrix_column_subtract.
matrix_column_multiply(T, 0, r, n);
matrix_column_subtract(myQ, i, T, j, ...rows...);
You're still missing the fifth argument, rows. I'm going to guess that's n, same as has been used for the rows in every other matrix_column_blah call.

Returning a matrix from a fuction in C

I'm making a program where I have to work constantly with matrices in functions, this is one of the many functions, this function is supposed to take open an external file which is a data set, where the data is separated with tabulations, it opens the file and saves the data in a matrix M, I know this matrix is composed of 6 columns, but the row number is unknown, I know the error is where I declare the matrix, it has to be declared with pointers since the function returns the matrix.
//type float** since it will return a matrix
float **carga_archivo(char *nombre_archivo)
{
float **M=(float **)malloc(6*sizeof(float*)); //error should be here
int i=0;
FILE *archivo; //FILE type pointer to open the external file
archivo=fopen(nombre__archivo,"r"); //Opens the file in the address indicated
//"nombre_de_archivo" is a variable
while(!feof(archivo)) //Browses the file row per row till the end of it
{
//saves the data in its corresponding place in the matrix
fscanf(archivo,"%f\t%f\t%f\t%f\t%f\t%f\n",
&M[0][i],&M[1][i],&M[2][i],&M[3][i],&M[4][i],&M[5][i]);
i++;
}
tam=i;
fclose (archivo); //closes the file
return M;
}
What I need is the right way to declare the matrix.
P.S. I documented the main lines in the code in case it could help someone who needs something similar.
Any correction is welcome.
Update:
Applied some changes proposed in comments, and worked better, here is the new code I nade for that function
float **carga_archivo(char *nombre_archivo)
{
int i=0;
float P[300][6];
FILE *archivo;
archivo=fopen(nombre_archivo,"r");
while(!feof(archivo))
{
i++;
//this was just so the feof function could browse row per row
//instead of character per character
scanf("%f\t%f\t%f\t%f\t%f\t%f\n",
&P[0][i],&P[1][i],&P[2][i],&P[3][i],&P[4][i],&P[5][i]);
printf("%i\n",i);
}
tam=i;
printf("%i",tam);
int filas = 6;
int columnas = tam;
float **M;
M = (float **)malloc(filas*sizeof(float*));
for (i=0;i<filas;i++)
M[i] = (float*)malloc(columnas*sizeof(float));
for (i = 0; i < columnas; ++i)
fscanf(archivo,"%f\t%f\t%f\t%f\t%f\t%f\n",
&M[0][i],&M[1][i],&M[2][i],&M[3][i],&M[4][i],&M[5][i]);
fclose (archivo);
return M;
}
The new problem is when the function is called, the program actually compiles, but when its running and the function is called the program crashes and stops.
Here Is the part of the code that calls to that function.
int main()
{
int i,j;
char *nombre_archivo="Agua_Vapor.txt";
float **agua_vapor=carga_archivo(nombre_archivo);
for (i = 0; i < 6; i++)
{
for (j = 0; i < tam; i++)
printf("%f ", agua_vapor[i][j]);
printf("\n");
}
return 0;
}
Your program has undefined behaviour, because you're populating memory referenced by uninitialised pointers.
Since you know there are always 6 columns, a simple approach is to store the matrix as row-major instead of column-major (your example is column-major). This means you can store the matrix data as one large piece of memory and use realloc when necessary. You may want to make a simple struct for this too.
struct matrix {
int rows, cols;
float ** data;
};
Then create it dynamically.
struct matrix * matrix_alloc( int rows, int cols )
{
int i;
struct matrix * m = malloc(sizeof(struct matrix));
m->rows = rows;
m->cols = cols;
m->data = malloc(rows * sizeof(float*));
m->data[0] = malloc(rows * cols * sizeof(float));
for( i = 1; i < rows; i++ ) {
m->data[i] = m->data[i-1] + cols;
}
return m;
}
void matrix_free( struct matrix * m )
{
free( m->data[0] );
free( m->data );
free( m );
}
Now, when you decide you need to add storage for more rows:
void matrix_set_row_dimension( struct matrix * m, int rows )
{
float **new_index, *new_block;
new_index = realloc(m->data, rows * sizeof(float**));
new_block = realloc(m->data[0], rows * m->cols * sizeof(float));
if( new_index && new_block )
{
int i = m->rows;
m->rows = rows;
m->data = new_index;
/* if block address changed, prepare to reindex entire block */
if( m->data[0] != new_block )
{
m->data[0] = new_block;
i = 1;
}
/* reindex */
for( ; i < rows; i++ ) {
m->data[i] = m->data[i-1] + cols;
}
}
}
So, now as you populate the matrix...
struct matrix * m = matrix_alloc( 10, 6 ); /* Start with 10 rows */
int row = 0;
while( 1 ) {
/* Double matrix row count if not large enough */
if( row == m->rows )
{
matrix_set_row_dimension( m, m->rows * 2 );
/* Check for error here */
}
/* Now the matrix has enough storage to continue adding */
m->data[row][0] = 42;
m->data[row][1] = 42;
m->data[row][2] = 42;
m->data[row][3] = 42;
m->data[row][4] = 42;
m->data[row][5] = 42;
row++;
}

Creating 2D array in single malloc() call

#include <stdio.h>
#include <stdlib.h>
#define MAX_ROWS 5
#define MAX_COLS 5
int globalvariable = 100;
void CreateMatrix(int ***Matrix)
{
int **ptr;
char *cp;
int i = 0;
*Matrix = (int**)malloc((sizeof(int*) * MAX_ROWS) + ((MAX_ROWS * MAX_COLS)*sizeof(int)));
ptr = *Matrix;
cp = (char*)((char*)*Matrix + (sizeof(int*) * MAX_ROWS));
for(i =0; i < MAX_ROWS; i++)
{
cp = (char*)(cp + ((sizeof(int) * MAX_COLS) * i));
*ptr = (int*)cp;
ptr++;
}
}
void FillMatrix(int **Matrix)
{
int i = 0, j = 0;
for(i = 0; i < MAX_ROWS; i++)
{
for(j = 0; j < MAX_COLS; j++)
{
globalvariable++;
Matrix[i][j] = globalvariable;
}
}
}
void DisplayMatrix(int **Matrix)
{
int i = 0, j = 0;
for(i = 0; i < MAX_ROWS; i++)
{
printf("\n");
for(j = 0; j < MAX_COLS; j++)
{
printf("%d\t", Matrix[i][j]);
}
}
}
void FreeMatrix(int **Matrix)
{
free(Matrix);
}
int main()
{
int **Matrix1, **Matrix2;
CreateMatrix(&Matrix1);
FillMatrix(Matrix1);
DisplayMatrix(Matrix1);
FreeMatrix(Matrix1);
getchar();
return 0;
}
If the code is executed, I get the following error messages in a dialogbox.
Windows has triggered a breakpoint in sam.exe.
This may be due to a corruption of the heap, which indicates a bug in sam.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while sam.exe has focus.
The output window may have more diagnostic information.
I tried to debug in Visual Studio, when printf("\n"); statement of DisplayMatrix() is executed, same error message is reproduced.
If I press continue, it prints 101 to 125 as expected. In Release Mode, there is no issue !!!.
please share your ideas.
In C it is often simpler and more efficient to allocate a numerical matrix with calloc and use explicit index calculation ... so
int width = somewidth /* put some useful width computation */;
int height = someheight /* put some useful height computation */
int *mat = calloc(width*height, sizeof(int));
if (!mat) { perror ("calloc"); exit (EXIT_FAILURE); };
Then initialize and fill the matrix by computing the offset appropriately, e.g. something like
for (int i=0; i<width; i++)
for (int j=0; j<height; j++)
mat[i*height+j] = i+j;
if the matrix has (as you show) dimensions known at compile time, you could either stack allocate it with
{ int matrix [NUM_COLS][NUM_ROWS];
/* do something with matrix */
}
or heap allocate it. I find more readable to make it a struct like
struct matrix_st { int matfield [NUM_COLS][NUM_ROWS]; };
struct matrix_st *p = malloc(sizeof(struct matrix_st));
if (!p) { perror("malloc"); exit(EXIT_FAILURE); };
then fill it appropriately:
for (int i=0; i<NUM_COLS; i++)
for (int j=0; j<NUM_ROWS, j++)
p->matfield[i][j] = i+j;
Remember that malloc returns an uninitialized memory zone so you need to initialize all of it.
A two-dimensional array is not the same as a pointer-to-pointer. Maybe you meant
int (*mat)[MAX_COLS] = malloc(MAX_ROWS * sizeof(*mat));
instead?
Read this tutorial.
A very good & complete tutorial for pointers, you can go directly to Chapter 9, if you have in depth basic knowledge.

Resources