I am trying to sort a 2D array of doubles using qsort() in C. The arrays contain 3D point data, which is read in from a file using fscanf. My programming skills are rather limited, but I have really large datasets that I need to deal with. Sorry in advance if my code sucks.
23127.947, 23127.947, 23127.947
523127.790, 523127.790, 523127.790
523127.747, 523127.747, 523127.747
523127.761, 523127.761, 523127.761
523127.768, 523127.768, 523127.768
(...for 3,158,632 points)
I've used printf to isolate that the problem in my code seems to be the qsort() line, which causes a segmentation fault. From other questions on Stack Overflow that I read, it could be a problem with my "compare" function. Examples for doing a 1D array seemed easy, but the examples I saw for 2D arrays didn't go into comparing the other dimensions (first X, then if X1 = X2, compare Y, then if Y1 = Y2, compare Z).
int main(int argc, char *argv[]) {
int i,j,c;
double x,y,z;
int ROWS = 3158632;
int COLS = 3;
char buffer[100];
double** data = Make2DDoubleArray(ROWS, COLS);
//Open the plot file to read in, and have an output write file
FILE *fp = fopen("Plot_1-2.txt","r");
if(fp == NULL) {
printf("Can't open file\n");
exit;
}
fgets(buffer, 100, fp); //Ignore header
for(i=0; ; i++){
if ((c = fgetc(fp)) == EOF){
break;
}
fscanf(fp,"%lf, %lf, %lf",&x, &y, &z);
data[i][0] = x;
data[i][1] = y;
data[i][2] = z;
}
printf("First 5 unsorted numbers:\n");
for(j=0;j<5;j++){
printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
}
printf("Last 5 unsorted numbers:\n");
for(j=ROWS-5;j<ROWS;j++){
printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
}
/* Sort array using Quicksort algorithm: */
printf("Sorting...\n");
qsort(data, ROWS, COLS*sizeof(double), &compare);
printf("First 10 sorted numbers:\n");
for(j=0;j<10;j++){
printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
}
fclose(fp);
for (i=0; i<ROWS; i++){
free(data[i]);
}
free(data);
return 0;
}
double** Make2DDoubleArray(int arraySizeX, int arraySizeY) {
double** theArray;
int i;
theArray = (double**) malloc(arraySizeX*sizeof(double*));
for (i = 0; i < arraySizeX; i++)
theArray[i] = (double*) malloc(arraySizeY*sizeof(double));
return theArray;
}
int compare(const void *arg1, const void *arg2) {
//double a, b, c, d, e, f;
double *a = (double*)arg1;
double *b = (double*)arg2;
double *c = ((double*)arg1 + 1);
double *d = ((double*)arg2 + 1);
double *e = ((double*)arg1 + 2);
double *f = ((double*)arg2 + 2);
if(a > b)
return 1;
else if(a < b)
return -1;
else {
if(c > d)
return 1;
else if(c < d)
return -1;
else {
if(e > f)
return 1;
else if(e < f)
return -1;
else
return 0;
}
}
}
I'm wondering if telling qsort to go "COLS * sizeof(double)" is the wrong way to do it with how I allocated the memory for the 2D array? Would treating this problem as a 1D array make the rest of it work? I'd prefer to keep it as a 2D array, if possible.
qsort expects the sorted elements to come in a contiguous block of memory. You can still keep your data in a 2D array, if all your cells constitute a contiguous block of memory that can be interpreted as an 1D array and used with qsort.
Instead of allocating memory separately for each row as you do in Make2DDoubleArray, allocate memory for all rows at once. Then, in addition to what you return now: an array of pointers to rows; you will also have to return (using argument-by-pointer) the memory block containing all of your rows.
You are allocating memory for each row
for (i = 0; i < arraySizeX; i++)
theArray[i] = (double*) malloc(arraySizeY*sizeof(double));
while you could allocate the memory in one step
double *cells = malloc(sizeof(double) * arraySizeX * arraySizeY);
if (cells == NULL) { ... }
for (i = 0; i < arraySizeX; i++)
theArray[i] = &cells[arraySizeY * i];
Then you will have two arrays: an array of pointers to rows which you have now (called theArray in your code); and a new 1D array that keeps all rows (not pointers to rows, but the arrays of cells) (and in effect, all cells where each row, a triplet, is one datapoint) and can be used for qsort (in my code called cells).
Then, pass the latter one - cells (and not data) to qsort
qsort(cells, ROWS * COLS, sizeof(double), &compare);
Also note that the call in the code in the question
qsort(data, ROWS, COLS*sizeof(double), &compare);
is wrong, because you are not sorting an amount of ROWS rows, each with a size of COLS*sizeof(double).
EDIT: Uh, my apologies. I misunderstood that you have a 2D array of entries, but now I see that COLS represents fields of one cell. In which case you would be better of with #SpacedMonkey's solution.
Just for reference, my answer would also work, then you would call qsort like you did, but on cells
qsort(cells, ROWS, COLS*sizeof(double), &compare);
None of this means anything without headers like <stdio.h>, <stdlib.h>, etc...
Please explain exit;. I think you mean exit(0);.
There are a few problems in your main. Because of that fgetc, your code potentially loses the most significant digit of your first value, which is a subtle bug. If you want to test for EOF, test the return value of scanf (Jee! I didn't think of that! I wish they wrote these things in manuals! Duh, they do...). The example at the end of the file is better than this, because that example ensures that three values are actually parsed by fscanf.
for(size_t i=0; fscanf(fp,"%lf, %lf, %lf",&x, &y, &z) != EOF; i++){
data[i][0] = x;
data[i][1] = y;
data[i][2] = z;
}
There's a problem in your Make2DDoubleArray function. It allocates many disjoint arrays, which qsort can't handle. Isn't it much cleaner to allocate your array in one step?
void *Make2DDoubleArray(size_t x) {
double (*theArray)[3] = malloc(x * sizeof *theArray);
return theArray;
}
theArray is declared as a pointer to an array of 3 doubles. You don't even need a Make2DDoubleArray for this.
There's a problem in the compare function.
double *a = (double*)arg1;
double *b = (double*)arg2;
a and b are pointers,
if(a > b)
return 1;
else if(a < b)
return -1;
... yet your code compares them as integers, rendering the sort malfunctional. The address of array[0] will always be less than the address of array[1].
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(int argc, char *argv[]) {
int j,c;
double x,y,z;
size_t ROWS = 3158632;
size_t COLS = 3;
char buffer[100];
double (*theArray)[COLS] = malloc(ROWS * sizeof *theArray);
//Open the plot file to read in, and have an output write file
FILE *fp = fopen("Plot_1-2.txt","r");
if(fp == NULL) {
printf("Can't open file\n");
exit(0);
}
fgets(buffer, 100, fp); //Ignore header
for(size_t i=0; fscanf(fp,"%lf, %lf, %lf", &x, &y, &z) == 3; i++){
data[i][0] = x;
data[i][1] = y;
data[i][2] = z;
}
printf("First 5 unsorted numbers:\n");
for(size_t j=0; j<5; j++){
printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
}
puts("Last 5 unsorted numbers:");
for(size_t j=ROWS-5; j<ROWS; j++){
printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
}
/* Sort array using Quicksort algorithm: */
puts("Sorting...");
qsort(data, ROWS, sizeof *data, compare);
puts("First 10 sorted numbers:");
for(size_t j=0;j<10;j++){
printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
}
fclose(fp);
free(data);
return 0;
}
int compare(const void *arg1, const void *arg2) {
double (*x)[3] = arg1;
double (*y)[3] = arg2;
if ((*x)[0] > (*y)[0])
return 1;
else if ((*x)[0] < (*y)[0])
return -1;
else if ((*x)[1] > (*y)[1])
return 1;
else if ((*x)[1] < (*y)[1])
return -1;
else if ((*x)[2] > (*y)[2])
return 1;
else if ((*x)[2] < (*y)[2])
return -1;
else
return 0;
}
Try using a struct for the data instead:
typedef struct {
double x;
double y;
double z;
} point_data;
Then you only need a 1 dimensional array of this new type:
point_data *array = malloc(linesRead * sizeof *array);
And your comparison function remains fairly similar:
int compare(const void *arg1, const void *arg2) {
point_data *point1 = arg1,
*point2 = arg2;
if ( point1->x > point2->x ) {
return 1;
else if ( point1->x < point2->x ) {
return -1;
} else {
if ( point1->y > point2->y ) {
return 1;
else if ( point1->y < point2->y ) {
return -1;
} else {
if ( point1->z > point2->z ) {
return 1;
else if ( point1->z < point2->z ) {
return -1;
} else {
return 0;
}
}
}
}
Also, please don't hardcode the number of points, instead count the number you read in.
Related
I have a problem where I have this structure
typedef struct _COMPLEX {
double real, imag;
}COMPLEX;
and I need to declare an array of this structure and sum the elements of the array. Here is my code.
#include <stdio.h>
#include <stdlib.h>
void* xmalloc(size_t nrOcteti);
int main()
{
COMPLEX* v = 0, *s = 0;
int n, i;
printf("\n n = ");
scanf("%d", &n);
v = (COMPLEX*)xmalloc((n)*sizeof(COMPLEX));
s = (COMPLEX*)xmalloc(sizeof(COMPLEX));
for(i = 0; i < n; i++)
{
printf("\n v[%d].real and imag:", i);
scanf("%lf %lf", &v[i].real, &v[i].imag);
}
for(i = 0; i < n; i++)
printf("V%d after scan=%.2lf + %.2lf * i\n", i, v[i].real, v[i].imag);
s->real = 0; s->imag = 0;
for(i = 0; i < n; i++)
{
s->real = s->real + v[i].real;
s->imag = s->imag + v[i].imag;
}
for(i = 0; i < n; i++)
printf("V%d after sum=%.2lf + %.2lf * i\n", i, v[i].real, v[i].imag);
printf("\nS=%lf + %lf\n", s->real, s->imag);
if(s) free(s);
s = 0;
if(v) free(v);
v = 0;
return 0;
}
void* xmalloc(size_t nrOcteti)
{
void *p = 0;
p = malloc(sizeof(nrOcteti));
if(!p)
{
fprintf(stderr, "Allocation failed!");
exit(EXIT_FAILURE);
}
return p;
}
After I give the elements of the array I print them everything is alright, but just before the sum the elements of the array are changed(and for multiple test, apparently the element with the index 2 is modified) and the sum at the end is incorrect. And sometimes(I think because of different inputs) it gives me at the end Segmentation fault because of the free().
The array and sum needs to be pointers to that struct and need to be dynamically allocated.
I tried many times and I can't manage to make it work properly.
If somebody can help me solve this it will be a blessing =))
The line
p = malloc(sizeof(nrOcteti));
in the function xmalloc() is wrong. This line is ignoring what is passed as the argument and just allocating for one size_t.
It should be
p = malloc(nrOcteti);
to allocate specified size.
I am trying to practice with C by making a bubble sort program. The problem until now seems to be that the for loop that is giving values to the cells of the array is stuck after the condition is no longer fulfilled but it doesn't seem to be executing the commands in the loop. I don't know what is happening exactly and I have added some extra lines to see what is happening an these were my conclusions. Here is the code:
#include <stdio.h>
#include <stdlib.h>
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int *sort(int *array)
{
int finish = 1;
while (finish = 1)
{
finish = 0;
for (int i = 0; i <= sizeof(array); i++)
{
if ((array + i) > (array + i + 1))
{
swap(array + i, array + i + 1);
finish = 1;
}
}
}
return array;
}
int main()
{
int s, res;
printf("Give me the size of the array being sorted(larger than 1) : ");
do
{
res = scanf("%d", &s);
if (res != 1)
{
printf("Wrong Input!\n");
exit(1);
}
if (s < 2)
printf("Only numbers equal or larger than 2\n");
} while (s < 2);
int array[s];
for (int i = 0; i < s; i += 1)
{
scanf("%d", array + i);
printf("%d %d %d\n\n", *(array + i), i, i < s); // I used this to check if my values were ok
}
printf("end of reading the array"); //I added this line to see if I would exit the for loop. I am not seeing this message
sort(array);
printf("\n");
for (int i = 0; i < sizeof(array); i++)
printf("%d\n\n", array + i);
printf("Array has been sorted! Have a nice day!\n\n************************************************************");
return 0;
}
See the annotations in the code:
#include <stddef.h> // size_t 1)
#include <stdio.h>
#include <stdlib.h>
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int *sort(int *array, size_t size) // needs an extra parameter to know the size of the array
{
int finish = 1;
while (finish /* = 1 * you don't want assignment, you want comparison: */ == 1)
{
finish = 0;
for (int i = 0; i /* <= sizeof(array) */ < size - 1; i++) // i should be of type size_t
{
// if ((array + i) > (array + i + 1)) you are not dereferencing:
if(array[i] > array[i + 1])
{
// swap(array + i, array + i + 1); // easier to read imho:
swap(&array[i], &array[i + 1]);
finish = 1;
}
}
}
return array; // why does this function return anything? it is never used.
}
int main()
{
int s; /* , res; no need for an extra variable res */
printf("Give me the size of the array being sorted(larger than 1) : ");
do
{
// res = scanf("%d", &s);
// if (res != 1)
if (scanf("%d", &s) != 1)
{
printf("Wrong Input!\n");
// exit(1); // should be EXIT_FAILURE. Use return instead of exit() when in main().
return EXIT_FAILURE;
}
if (s < 2)
printf("Only numbers equal or larger than 2\n");
} while (s < 2);
int array[s];
for (int i = 0; i < s; /* i += 1* idiomatic: */ ++i) // size_t would be the correct type for s and i.
{
scanf("%d", /* array + i use indexes: */ &array[i]);
printf("%d %d %d\n\n", array[i], i, i < s); // again: indexes. i < s is allready ensured by the condition of the for-loop
}
printf("end of reading the array");
// sort(array); // sort will have no idea about the size of array use
sort(array, s); // instead.
printf("\n");
for (int i = 0; i < /* sizeof(array) 2) */ s; i++)
printf("%d\n\n", /* array + i * again you don't dereference */ array[i]);
printf("Array has been sorted! Have a nice day!\n\n************************************************************");
return 0;
}
1) size_t is the type that is guaranteed to be big enough to hold all sizes of objects in memory and indexes into them. The conversion specifier for scanf() is "%zu".
2) sizeof(array) in main() will yield the number of bytes in array, but you want the number of elements so you'd have to use sizeof(array) / sizeof(*array). But thats not needed since you already know its size. It is s.
This line
printf("end of reading the array");
has no line feed at the end of the string. This is a problem because printf is part of the family of functions called "buffered IO". The C library maintains a buffer of the things you want to print and only sends them to the terminal if the buffer gets full or it encounters \n in the stream of characters. You will not see, end of reading the array on your screen until after you have printed a line feed. You only do this after calling sort(). So all you know is your program is getting into an infinite loop at some point before the end of sort.
So there are actually three loops that could be infinite: the for loop you identified, the while loop in sort and the for loop inside the while loop. As the other answers point out, you have made the classic mistake of using assignment in the while conditional
while (finish = 1)
// ^ not enough equals signs
Unless your C compiler is really old, it is probably outputting a warning on that line. You should heed warnings.
Also, you should learn to use a debugger sooner rather than later. Believe me, it will save you a lot of time finding bugs.
In the sort function sizeof(array) returns the size of the pointer. (you can check it by yourself using printf("%d", sizeof(array).
The solution is to change your function to:
int sort(int* array, size_t size) { ... }
and call it with the correct array size:
sort(array, s);
thanks for taking the time in reading this.
In my question a "vector" is defined as a 1D dimensional array of integers.
Therefore an array of vectors would be a 2D dimensional array in which every vector can be of a different length.
I'm asked to use:
int** vectors- the 2D array
int size -an integer that represents how many vectors exist inside **vectors
int* sizes-a 1D array of integers that represents the length of the vectors
for example,for:
vectors = {{4,3,4,3},{11,22,33,44,55,66},NULL,{5},{3,33,333,33,3}}.
size is 5 (there are 5 vectors inside vectors).
sizes is {4,6,0,1,5} (4 is the length of the first vector and so on).
size is inputted by the user at the beginning of main() and **vectors&*sizes are dynimacilly allocated with size's value.
I'm asked to write the function:
int init(int ***vectors, int **sizes, int size) which initializes **vectors to be an array of NULLs and *sizes to be an array of zeros.
I came up with this code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int init(int*** vectors, int** sizes, int size)
{
int i, k,j;
printf("check\n");
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
*(vectors + i) = NULL;
}
printf("check 2\n");
for (k = 0; k<size; k++)
{
if (*(vectors+k) != NULL)
printf("didn't work\n");
else
printf("current is null\n");
}
*sizes= (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j= 0; j < size; j++)
{
*(sizes + j) = 0;
printf("%d ", *(sizes + j));
}
printf("\n");
return 1;
}
int main()
{
int size, i;
int** vectors = NULL;
int* sizes = NULL;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
printf("%d\n", init(&vectors, &sizes, size));
printf("size is %d now\n", size);
// for (i = 0; i < size; i++)
// printf("%d ", *(sizes+i));
printf("check 3\n");
free(sizes);
free(vectors);
printf("check 4\n");
printf("check 5\n");
return 0;
}
forgot to mention that init returns 0 if it fails to allocate memory and 1 otherwise.
printing the "checks" was so I could see where the program fails.
the problem is that no matter what,after printing the last check (check 5)
the program fails.(Run-Time Check Failure #2)
if anyone could help me understand what I'm doing wrong I would HIGHLY appreciate it.
thanks alot for reading and have an amazing day.
edit:
i also printed the array sizes/vectors inside init just to see if it prints zeros/nulls,i don't actually need to do it.
One problem of OP's code is in the pointer arithmetic. Given:
int ***vectors;
*vectors = malloc(size * sizeof(int*));
This loop:
for (i = 0; i < size; i++)
{
*(vectors + i) = NULL;
}
Would iterate over the next unallocated pointer to pointer to pointer to int, while what the OP needs is
for (i = 0; i < size; i++)
{
*(*vectors + i) = NULL; // or (*vectors)[i] = NULL;
}
The same holds in the following loops, where *(sizes + j) is used instead of *(*sizes + j) (or (*sizes)[j]).
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.
I have spent last few hours trying to debug my code but I failed to do so. I think the problem lies in me not fully understanding dynamic memory allocation, however I could've made some other mistakes aswell. The question here is a bit more of a personal problem and I'm sorry if someone finds this question not fulfilling "Make it relevant to others".
I've been given the next assigment:
Create an array A[] out of n random elements from interval 0-100. Create a function which splits two arrays such as: array B[] contains elements > 50 while C[] contains rest of the elements. Create arrays A and B using dynamic memory allocation. Arguments of the function have to be all three arrays and their respective lengths.
#include <stdio.h>
#include <stdlib.h>
void Array(int *A, int *nA, int *B, int *nB, int *C, int*nC){
int i;
int nB1 = 0;
int nC1 = 0;
int *tmpB;
int *tmpC;
B = malloc((nB1+1)*sizeof(int));
C = malloc((nC1+1)*sizeof(int));
printf("\n");
for(i = 0 ; i < nA ; i++){
if(A[i] <= 50){
C[i] = A[i];
nC1++;
// The idea here is to have a new array with basically
// no length so that each time one element passes to either
// B or A array that array gets increased at the same
// time as nC or nB
tmpC = realloc(C, sizeof(int) * nC1);
if(tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
C = tmpC;
// C = realloc(C, nC1 + 1);
}
else{
B[i] = A[i];
nB1++;
tmpB = realloc(B, sizeof(int) * nB1);
if(tmpB == NULL){
printf("ERROR: realloc failed.\n");
}
B = tmpB;
// B = realloc(B, nB1 + 1);
}
}
printf("\n");
printf("Array B: ");
nB = nB1;
for(i = 0 ; i < nB ; i++){
printf("%d ", B[i]);
}
printf("\n");
printf("Number of elements in array B: %d\n", nB);
printf("\n");
printf("Array C: ");
nC = nC1;
for(i = 0 ; i < nC ; i++){
printf("%d ", C[i]);
}
printf("\n");
printf("Number of elements in array C: %d\n", nC);
}
void main(){
int *A;
int *B;
int *C;
int nA, nB, nC, i, r, j;
nB = 0;
nC = 0;
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
A = malloc(nA * sizeof(int));
if (A == NULL){
printf("ERROR: malloc failed.\n");
return 1;
}
time_t t;
srand((unsigned)time(&t));
printf("Array A: ");
for(i = 0 ; i < nA ; i++){
r = rand() % 101;
A[i] = r;
printf("%d ", r);
}
printf("\n");
Array(A, nA, B, nB, C, nC);
}
So far my code is breaking when:
User input from nA is higher than 6.
Code is working fine while array A has all elements which can be put in one single array such as B or C. But if elements can be split, last element of the array A is not shown properly on the screen while being in B or C array.
EDIT: Updated code so it's easier to keep track of my mistakes.
#include <stdio.h>
#include <stdlib.h>
void Array(int *A, int nA, int *B, int nB, int *C, int nC){
int i;
int nB1 = 0;
int nC1 = 0;
int *tmpB;
int *tmpC;
B = malloc(1*sizeof(int));
if(B == NULL){
printf("ERROR: malloc B failed.\n");
return 1;
}
C = malloc(1*sizeof(int));
if(C == NULL){
printf("ERROR: malloc C failed.\n");
return 1;
}
printf("\n");
for(i = 0 ; i < nA ; i++){
if(A[i] <= 50){
// C[nC1] = A[i];
// nC1++;
// if( nC1 > 1){
// tmpC = realloc(C, sizeof(int) * nC1);
// if(tmpC == NULL){
// printf("ERROR: realloc C failed.\n");
// return 1;
// }
// C = tmpC;
// }
tmpC = realloc(C, sizeof(int) * nC1);
if(tmpC == NULL){
printf("ERROR: realloc C failed.\n");
return 1;
}
C = tmpC;
C[nC1++] = A[i];
// nC1++;
}
else{
// B[nB1] = A[i];
// nB1++;
// if(nB1 > 1){
// tmpB = realloc(B, sizeof(int) * nB1);
// if(tmpB == NULL){
// printf("ERROR: realloc B failed.\n");
// return 1;
// }
// B = tmpB;
// }
tmpB = realloc(B, sizeof(int) * nB1);
if(tmpB == NULL){
printf("ERROR: realloc B failed.\n");
return 1;
}
B = tmpB;
B[nB1++] = A[i];
// nB1++;
}
}
printf("\n");
printf("Array B: ");
nB = nB1;
for(i = 0 ; i < nB ; i++){
printf("%d ", B[i]);
}
printf("\n");
printf("Number of elements in array B: %d\n", nB);
printf("\n");
printf("Array C: ");
nC = nC1;
for(i = 0 ; i < nC ; i++){
printf("%d ", C[i]);
}
printf("\n");
printf("Number of elements in array C: %d\n", nC);
}
int main(){
int *A;
int *B;
int *C;
int nA, nB, nC, i, r;
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
A = malloc(nA * sizeof(int));
if (A == NULL){
printf("ERROR: malloc A failed.\n");
return 1;
}
time_t t;
srand((unsigned)time(&t));
printf("Array A: ");
for(i = 0 ; i < nA ; i++){
r = rand() % 101;
A[i] = r;
printf("%d ", r);
}
printf("\n");
Array(A, nA, B, nB, C, nC);
return 0;
}
I'll try to take a crack at this I guess. I found some notable issues with your code that would be resolved with some structural changes towards your implementation. Some of the lesser ones:
void main() {
// Code above here left out.
A = malloc(nA * sizeof(int));
if (A == NULL){
printf("ERROR: malloc failed.\n");
return 1; // Might be a problem here.
}
You return an integer in main when there is not enough memory to allocate for A. This could cause issues on some compilers - or if you hate warnings in general a simple fix from void main to int main will clear this up.
2nd, in your function Array you have
void Array(int *A, int *nA, int *B, int *nB, int *C, int *nC)
however, you begin to use nA nB and nC as just int instead of int * which is a mismatch of types. You could change to
void Array(int *A, int nA, int *B, int nB, int *C, int nC)
Lastly and most importantly, you run into heap errors by using uninitialized ints to create memory for the arrays passed in:
int nB1;
int nC1;
B = malloc((nB1 + 1)*sizeof(int));
C = malloc((nC1 + 1)*sizeof(int));
It would be better to instead add just one int to the arrays without using nB1 and nC1.
B = malloc(1*sizeof(int));
C = malloc(1*sizeof(int));
You should first make checks as to whether B and C are empty arrays when they are passed in, then add memory to them as you see fit.
if (A[i] <= 50){
C[i] = A[i];
nC1++;
// The idea here is to have a new array with basically
// no length so that each time one element passes to either
// B or A array that array gets increased at the same
// time as nC or nB
tmpC = realloc(C, sizeof(int) * nC1);
if (tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
C = tmpC;
}
tmpC is realloc'd but C is never given more space thus when assigning the value C[i] = A[i] it crashes. You need to expand on maintaining the arrays C and B.
EDIT
Disregard the comment about reallocation, the realloc operation you have is fine.
You iterate through each element in the array A, if the value is less than or equal to 50 you insert into array C otherwise B. However, you might have a few elements that satisfy the first condition but then the next condition could be satisfied. You then assign like so B[i] = A[i] but as stated you are at element 3 in A but you insert at element 1 in B, so using i to iterate for both is not correct. Follow SGM1's advice for reading into each array using nB1 and nC1, and also ryyker for the comment on reallocation.
I was able to compile and run this every time, however now you have to deal with actually assigning the values now:
for (i = 0; i < nA; i++){
if (A[i] <= 50){
C[nC1] = A[i];
nC1++;
tmpC = (int *)realloc(C, sizeof(int) * nC1);
if (tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
C = tmpC;
// C = realloc(C, nC1 + 1);
}
Logic error B[i] = A[i]; in your condition should be B[nB1] = A[i];. Same thing with C array, should be C[nC1] = A[i] (both of this in the loop).
Also, from KillaBytes bytes analysis. Yes, you should definitely realloc BEFORE adding the new value. Probably is the reason your program crashes eventually:
else {
nB1++; // since you started at size 0
tmpB = realloc(B, sizeof(int) * nB1); //realloc to 0 = (sizeof(int) * 0) is bad
if(tmpB == NULL){
printf("ERROR: realloc failed.\n");
}
B = tmpB;
B[nB1 - 1] = A[i];///*****KEY POINT, This happens at the very end***
}
Still, there are many other problems, but not with the core logic. Especially with the the understanding of pointers. I'll try to list a few you need to think about:
Nothing comes out of the Array function (besides the printed output), the original B and C remain the same.
A, B (in the function), C (in the function) is not freed at the end. The idea is, for every malloc/calloc (realloc would free when successful), you would have to call free on the pointer to avoid any memory leakage :) just a trivial point, but very good habit.
Error conditions shouldn't continue logic, simplest solution would be to kill the program
if(tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
should be
if(tmpC == NULL){
free(C);//unnecessary because the program is going to exit
// I would argue to get used to this, to force the habit
// to alway free all mallocs
printf("ERROR: realloc failed.\n");
exit(-1);// -1 is a generic value, error code that is checked
// if the caller cares to look (you can make it any int)
}
Now, if you wanted to "return" the value outside of for B and C Array() there are a few approaches, I'll demo one way.
void Array(int *A, int nA, int **B, int *nB, int **C, int *nC){ // funciton signature
Any time you use B, nB, C, nC in this function, use *B, *nB, *C, *nC. Eg:
*B = malloc((*nB1+1)*sizeof(int));
*C = malloc((*nC1+1)*sizeof(int));
And the call to the function from main should be:
printf("\n");
Array(A, nA, &B, &nB, &C, &nC);
There were a few bugs. There were a lot of errors/warnings flagged by the compiler (i.e. always compile with -Wall)
In the Array prototype, nA was defined as *nA [a pointer] but you used nA throughout the body.
*nB and *nC were correct, but near the bottom you needed:
*nB = nB1;
*nC = nC1;
There was a lot of replication code for all arrays. Each array had a custom loop to print it. To simplify, create a "print array" function.
The reallocation of B and C are similar, so, once again, create a common function.
Other bugs aside, while Array created B and C, it had no way to pass the updated values back to main. So, in the prototype, we need int **Bp and int **Cp.
In all, Array had two input values and four return values.
Here's the corrected code [please pardon the gratuitous style cleanup]:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// prtarray -- print an array
void
prtarray(int *arr,int count,const char *sym)
{
printf("\n");
printf("Array %s:",sym);
for (int i = 0; i < count; i++)
printf(" %d ", arr[i]);
printf("\n");
printf("Number of elements in array %s: %d\n",sym,count);
}
// growarray -- grow array
int *
growarray(int *arr,int *pcount,int val)
{
int off;
off = *pcount;
arr = realloc(arr,sizeof(int) * (off + 1));
arr[off] = val;
*pcount = off + 1;
return arr;
}
// BUGFIX: we need "int nA" and _not_ "int *nA"
#if 0
void
Array(int *A, int *nA, int *B, int *nB, int *C, int *nC)
#else
void
Array(int *A, int nA, int **Bp, int *nB, int **Cp, int *nC)
#endif
{
#if 1
int *B = NULL;
int *C = NULL;
#endif
int i;
printf("\n");
for (i = 0; i < nA; i++) {
if (A[i] <= 50)
C = growarray(C,nC,A[i]);
else
B = growarray(B,nB,A[i]);
}
*Bp = B;
*Cp = C;
}
int
main()
{
int *A;
int *B;
int *C;
int nA;
int nB;
int nC;
nB = 0;
nC = 0;
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
A = malloc(nA * sizeof(int));
if (A == NULL) {
printf("ERROR: malloc failed.\n");
return 1;
}
time_t t;
srand((unsigned) time(&t));
for (int i = 0; i < nA; i++)
A[i] = rand() % 101;
prtarray(A,nA,"A");
#if 0
Array(A, nA, B, nB, C, nC);
#else
Array(A, nA, &B, &nB, &C, &nC);
#endif
prtarray(B,nB,"B");
prtarray(C,nC,"C");
return 0;
}
But, dynamic arrays "cry out" for using a struct to control things. The code becomes even simpler:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// array control
struct array {
int *arr_data; // data
int arr_count; // array count
const char *arr_sym; // array name
};
// arrinit -- initialize array
void
arrinit(struct array *arr,const char *sym)
{
arr->arr_data = NULL;
arr->arr_count = 0;
arr->arr_sym = sym;
}
// arrprint -- print an array
void
arrprint(struct array *arr)
{
printf("\n");
printf("Array %s:",arr->arr_sym);
for (int i = 0; i < arr->arr_count; i++)
printf(" %d ", arr->arr_data[i]);
printf("\n");
printf("Number of elements in array %s: %d\n",arr->arr_sym,arr->arr_count);
}
// arrgrow -- grow array
void
arrgrow(struct array *arr,int val)
{
int off;
off = arr->arr_count;
arr->arr_data = realloc(arr->arr_data,sizeof(int) * (off + 1));
arr->arr_data[off] = val;
arr->arr_count = off + 1;
}
// BUGFIX: we need "int nA" and _not_ "int *nA"
void
Array(struct array *A, struct array *B, struct array *C)
{
int i;
int val;
printf("\n");
for (i = 0; i < A->arr_count; i++) {
val = A->arr_data[i];
if (val <= 50)
arrgrow(C,val);
else
arrgrow(B,val);
}
}
int
main()
{
struct array A;
struct array B;
struct array C;
int nA;
arrinit(&A,"A");
arrinit(&B,"B");
arrinit(&C,"C");
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
time_t t;
srand((unsigned) time(&t));
for (int i = 0; i < nA; i++)
arrgrow(&A,rand() % 101);
arrprint(&A);
Array(&A, &B, &C);
arrprint(&B);
arrprint(&C);
return 0;
}
UPDATE:
Here's a clean wrapper for realloc to use in the above.
// qrealloc -- reallocate with null check
void *
qrealloc(void *ptr,size_t len)
{
#if 1
// what is normally sufficient
ptr = realloc(ptr,len);
if (ptr == NULL) {
fprintf(stderr,"qrealloc: realloc failure -- len=%lu\n",len);
exit(1);
}
#else
// what valgrind needs
void *tmp = realloc(ptr,len);
if (tmp == NULL) {
free(ptr);
fprintf(stderr,"qrealloc: realloc failure -- ptr=%p len=%lu\n",ptr,len);
exit(1);
}
ptr = tmp;
#endif
return ptr;
}