how to set a vector element in a mex structure - c

I'm trying to populate a structure in a mex function. I have the basics of the structure created in the mexFunction, but its getting a little confusing when a field in the structure is an array and i want to populate each element in this array as the 'for' loop iterates.
....
mxArray *value;
mwSize dims[2] = {16,8};
int numFields = 2;
const char *fieldNames[] = {"array1", "array2"};
plhs[2] = mxCreateStructArray(2, dims, numFields, fieldNames);
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 8; j ++)
{
value1 = (some calculation);
value = mxCreateDoubleMatrix(1,18,mxREAL);
*mxGetPr(value[sampleIndex]) = value1;
mxSetField(plhs[2], i, "array1", value);
// i want to set the array1[j] element
value2 = (some other calculation);
value = mxCreateDoubleMatrix(1,8,mxREAL);
*mxGetPr(value) = value2;
mxSetField(plhs[2], i, "array2", value);
}
}
....
The fields "array1" and "array2" are both vectors of the same size (lets say 8 elements) i am not sure how to populate each individual element. How do i set the field name by array index 'j'.
To aid in the explanation, this is how the structure should look:
structure is an array of 16 elements, each element has 2 fields, each field has 8 elements each
structure(0).array1 = [1 2 3 4 5 6 7 8];
structure(0).array2 = [11 12 13 14 15 16 17 18];
structure(1).array1 = [21 22 23 24 25 26 27 28];
structure(1).array2 = [211 212 213 214 215 216 217 218];
structure(2).array1 = [31 32 33 34 35 36 37 38];
structure(2).array2 = [311 312 313 314 315 316 317 318];
structure(3).array1 = [41 42 43 44 45 46 47 48];
structure(3).array2 = [411 412 413 414 415 416 417 418];
...
The values are just arbitrary.

Consider the following C code:
structArrayMEX.c
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mxArray *x, *y;
double *xData, *yData;
mwIndex idx, i;
int counter = 1;
// create a 16x1 structure array, each with two fields x and y
const char *fieldNames[] = {"x", "y"};
mxArray *s = mxCreateStructMatrix(16, 1, 2, fieldNames);
// fill structure array
for (idx=0; idx<16; idx++) {
// create x and y matrices each of size 1x8
x = mxCreateDoubleMatrix(1, 8, mxREAL);
y = mxCreateDoubleMatrix(1, 8, mxREAL);
// fill x and y matrices: x[i], y[i]
xData = mxGetPr(x);
yData = mxGetPr(y);
for (i=0; i<8; i++) {
xData[i] = counter;
yData[i] = counter + 100;
counter++;
}
// set fields: s(idx).x = x and s(idx).y = y
mxSetField(s, idx, "x", x);
mxSetField(s, idx, "y", y);
}
// return structure array
plhs[0] = s;
}
The returned structure array:
>> s = structArrayMEX();
>> whos s
Name Size Bytes Class Attributes
s 16x1 4096 struct
>> s(1)
ans =
x: [1 2 3 4 5 6 7 8]
y: [101 102 103 104 105 106 107 108]
>> s(16)
ans =
x: [121 122 123 124 125 126 127 128]
y: [221 222 223 224 225 226 227 228]
The above MEX-function should be equivalent to the following MATLAB code
vals = reshape(1:16*8, [8 16])';
s = struct('x',num2cell(vals,2), 'y',num2cell(vals+100,2));

Related

reading and printing matrix from stdin

Well I posted this before but it's kinda improved now, and I only have one problem (I guess).
The assignment was to write a function which reads an integer matrix given in a ‘.txt file’ using
I/O redirection, then write another function to print it.
I read txt into a 1D array (arr) then create 2D matrix (mat) out of it, before those, I allocated memory dynamically bc our professor asked to do it that way. The problem is that arr seems to be changing when I put it on for loop and try to address it for the matrix. I would appreciate any ideas... Also, it would be helpful if you guys can comment on my way of allocating memory. (Don't forget we have 3 different input.txts some of them has -5.58234 like values or they are not seperated by "," in this example, so I want to make my code usable in any cases)
example txt file:
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int readMatrix(int *arr, int **mat);
void printMatrix(int **mat, int size);
int main(){
// declare 1D array and allocate memory
int *arr;
arr = malloc(sizeof(stdin)*sizeof(int));
// declare 2D Matrix and allocate memory
int **mat;
mat = (int **)malloc(sizeof(stdin)*sizeof(int));
// function implementations
int size;
size = readMatrix(arr, mat);
printMatrix(mat,size);
return 0;
}
int readMatrix(int *arr, int **mat){
// reading
int i=0, size=0; // loop var i and size to count the elements of array
while(scanf("%d,", &arr[i]) != EOF)
{
i++;
size++;
}
printf("arr[63] = %d \n\n",arr[63]); // VALUE IS CORRECT HERE
// finding row and column numbers
int rows = sqrt(size), cols = rows;
// appending 1d array into matrix
int m = 0;
// test printf("rows = %d, cols = %d\n", rows, cols);
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
printf("arr[%d] = %d\n",m, arr[m]); // VALUES OF arr[] BECAME WEIRD AFTER arr[12]
//mat[i][j] = arr[m]; // segmentation fault
//*(*(mat+i)+j) = arr[m]; // segmentation fault
//*(*(mat+i)+j) = &arr[m]; // segmentation fault
*(mat + i*cols + j) = &arr[m]; // I don't know if this is the proper way but it works
m++;
}
}
printf("\narr[63] = %d\n",arr[63]); // HOWWWWW
// return size for further implementations
//
return size;
}
void printMatrix(int **mat, int size){
int rows = sqrt(size), cols = rows;
printf("\nMATRIX A:\n");
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++)
{
printf("%d ", mat[i][j]);
//if(mat[i][j]>=10 && mat[i][j]<100 ){printf("%d ", mat[i][j]);}
//else if(mat[i][j]>=100 ){printf("%d ", mat[i][j]);}
//else{printf("%d ", mat[i][j]);}
}
printf("\n");
}
}
output:
$ ./secondtry < input1.txt
arr[63] = 99
arr[0] = 16
arr[1] = 11
arr[2] = 10
arr[3] = 16
arr[4] = 24
arr[5] = 40
arr[6] = 51
arr[7] = 61
arr[8] = 12
arr[9] = 12
arr[10] = 14
arr[11] = 19
arr[12] = 976
arr[13] = 8
arr[14] = 980
arr[15] = 8
arr[16] = 984
arr[17] = 8
arr[18] = 988
arr[19] = 8
arr[20] = 992
arr[21] = 8
arr[22] = 996
arr[23] = 8
arr[24] = 1000
arr[25] = 8
arr[26] = 1004
arr[27] = 8
arr[28] = 1008
arr[29] = 8
arr[30] = 1012
arr[31] = 8
arr[32] = 1016
arr[33] = 8
arr[34] = 1020
arr[35] = 8
arr[36] = 1024
arr[37] = 8
arr[38] = 1028
arr[39] = 8
arr[40] = 1032
arr[41] = 8
arr[42] = 1036
arr[43] = 8
arr[44] = 1040
arr[45] = 8
arr[46] = 1044
arr[47] = 8
arr[48] = 1048
arr[49] = 8
arr[50] = 1052
arr[51] = 8
arr[52] = 1056
arr[53] = 8
arr[54] = 1060
arr[55] = 8
arr[56] = 1064
arr[57] = 8
arr[58] = 1068
arr[59] = 8
arr[60] = 1072
arr[61] = 8
arr[62] = 1076
arr[63] = 8
arr[63] = 8
MATRIX A:
16 11 10 16 24 40 51 61
11 10 16 24 40 51 61 12
10 16 24 40 51 61 12 12
16 24 40 51 61 12 12 14
24 40 51 61 12 12 14 19
40 51 61 12 12 14 19 976
51 61 12 12 14 19 976 8
61 12 12 14 19 976 8 980
Because we're reading from stdin, we can not do simple things like:
read/parse the first to determine number of columns
rewind file
read/parse all lines and store in matrix (allocating space as we go)
Note that using sqrt on the count to get number of rows/columns is a bit "unique". This is the first time I've seen that done.
When handling a 2D matrix that has dynamic dimensions, it helps to define a control struct to be able to store the dimensions. Then, all relevant info for the matrix is available to everyone.
In general, I really prefer fgets/strtok/strtol over scanf.
In this use case, I'm not sure if scanf("%d,",&val) can parse both (e.g.) 103, and 99. That is, the last number of the input file has no comma after it.
So, I had to refactor the code quite a bit. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
#define dbgprt(_fmt...) \
printf(_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
// matrix control
typedef struct {
int mtx_cols; // number of columns
int mtx_rows; // number of rows (input lines)
int *mtx_base; // pointer to matrix data
} mtx_t;
// helper macro to access a given matrix coordinate
#define MTX(_mtx,_irow,_icol) \
_mtx->mtx_base[((_irow) * _mtx->mtx_cols) + _icol]
// newMatrix -- get new matrix control
mtx_t *
newMatrix(void)
{
mtx_t *mtx;
mtx = calloc(1,sizeof(*mtx));
return mtx;
}
// readMatrix -- read in matrix from stream
void
readMatrix(mtx_t *mtx,FILE *xfin)
{
char *bp;
char *cp;
char buf[1000];
// get first line as a special case to calculate the number of columns
fgets(buf,sizeof(buf),xfin);
// we need to preserve the original data for the second loop below
char tmp[1000];
strcpy(tmp,buf);
// calculate number of columns
bp = tmp;
while (1) {
char *cp = strtok(bp," ,\n");
bp = NULL;
if (cp == NULL)
break;
mtx->mtx_cols += 1;
}
// read in row by row
while (1) {
// get current row index and advance the row count
int irow = mtx->mtx_rows++;
dbgprt("BUF/%d: %s",irow,buf);
// add space for this row
mtx->mtx_base = realloc(mtx->mtx_base,
sizeof(*mtx->mtx_base) * mtx->mtx_rows * mtx->mtx_cols);
if (mtx->mtx_base == NULL) {
perror("realloc");
exit(2);
}
// parse this row
bp = buf;
for (int icol = 0; icol < mtx->mtx_cols; ++icol) {
char *cp = strtok(bp," ,\n");
bp = NULL;
if (cp == NULL)
break;
MTX(mtx,irow,icol) = strtol(cp,&cp,10);
dbgprt(" %d\n",MTX(mtx,irow,icol));
}
// get data for next row
if (fgets(buf,sizeof(buf),xfin) == NULL)
break;
}
}
void
printMatrix(const mtx_t *mtx)
{
printf("\nMATRIX A:\n");
for (int irow = 0; irow < mtx->mtx_rows; ++irow) {
for (int icol = 0; icol < mtx->mtx_cols; ++icol)
printf(" %d",MTX(mtx,irow,icol));
printf("\n");
}
}
int
main(int argc,char **argv)
{
--argc;
++argv;
FILE *xfin;
if (argc > 0)
xfin = fopen(*argv,"r");
else
xfin = stdin;
if (xfin == NULL)
exit(1);
// declare 1D array and allocate memory
mtx_t *mtx = newMatrix();
readMatrix(mtx,xfin);
printMatrix(mtx);
return 0;
}

How to treat negative indices in C?

I have been trying to use all possible combinations but I always get segmentation fault
my first guess was to use int *ary = &storage[0] but it doesn't work :( can someone explain me what it is that I'm doing wrong?(Im beginner in C)
thank you!
This is the problem
#include <stdio.h>
#define MINN -50
#define MAXN 50
int main() {
int storage[MAXN - MINN + 1] = {0};
int *ary = &storage[0];
for (int i = MINN; i <= MAXN; i++)
ary[i] = i;
for (int i = MINN; i <= MAXN; i++)
printf("%d ", ary[i]);
The output should be "-50, -49,-48 ... 49, 50"
I have to be doing something wrong here
int *ary = &storage[0]
Arrays always start with index 0.
You have to use an offset to ensure accessing the array accordingly.
Your MINN is useable for that.
Though I recommend to define the macro constants in a more paranoid way, because macro expansion can do weird things with operators.
#include <stdio.h>
#define MINN (-50)
#define MAXN (50)
int main(void) {
int storage[MAXN - MINN + 1] = {0};
int *ary = &storage[0];
for (int i = MINN; i <= MAXN; i++)
ary[i-MINN] = i;
for (int i = MINN; i <= MAXN; i++)
printf("%d ", ary[i-MINN]);
}
Output (from https://www.tutorialspoint.com/compile_c_online.php):
-50 -49 -48 -47 -46 -45 -44 -43 -42 -41 -40 -39 -38 -37 -36 -35 -34 -33 -32 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -21 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
Don't mix up array sizes and the values you store in them. In this case you wish to store 50 + 50 + 1 numbers in an array. So make a separate constant for its size, for example:
#define ARR_SIZE (-MINN + MAXN + 1)
int storage [ARR_SIZE] = ...;
Now we don't have to worry about what values those other constants have nor do any arithmetic involving them. Simply use ARR_SIZE. Same thing in the loop, don't mix up array indices with array values:
int val = MINN;
for(size_t i=0; i<ARR_SIZE; i++)
{
arr[i] = val;
val++;
}
Overall keep it simple and there will be no bugs.
With no defines (but malloc), and no parallel counter (but a formula) it could be:
#include <stdio.h>
#include <stdlib.h>
const int AMPL = 50;
/* Store and print numbers from -AMPL to AMPL */
void main(void) {
extern const int AMPL; // not needed
const int SZ = 2*AMPL + 1;
int *ary = malloc(SZ * sizeof *ary);
for (int i = 0; i < SZ; i++) {
ary[i] = i - AMPL;
printf("%d ", ary[i]);
}
}
This is only for symmetric series of course. What exactly are you trying?

C language wrong output...pascal triangle using 2d arrays

So this is my code for printing pascal triangle using 2d arrays but its not giving me the desired output and I cannot determine what's wrong with the logic/code.
#include <stdio.h>
int main()
{
int num, rows, col, k;
printf("Enter the number of rows of pascal triangle you want:");
scanf("%d", &num);
long a[100][100];
for (rows = 0; rows < num; rows++)
{
for (col = 0; col < (num - rows - 1); col++)
printf(" ");
for (k = 0; k <= rows; k++)
{
if (k == 0 || k == rows)
{
a[rows][k] = 1;
printf("%ld", a[rows][k]);
}
else
a[rows][k] = (a[rows - 1][k - 1]) + (a[rows - 1][k]);
printf("%ld", a[rows][k]);
}
printf("\n");
}
return 0;
}
You don't have curly braces around the statements after the else, so it looks like you'll double-printf() when the condition of the if-statement is true.
I copied the source into codechef.com/ide and changed the io for num to be just assigned to 6 which produced the following output:
Enter the number of rows of pascal triangle you want:
11
1111
11211
113311
1146411
1151010511
It looks like your close, but you want 1, 11, 121, 1331 etc right?
Wraping the else case produced the following output:
if (k == 0 || k == rows)
{
a[rows][k] = 1;
printf("(%ld)", a[rows][k]);
}
else{// START OF BLOCK HERE
a[rows][k] = (a[rows - 1][k - 1]) + (a[rows - 1][k]);
printf("(%ld)", a[rows][k]);
}//END OF BLOCK HERE, NOTE THAT IT INCLUDES THE PRINT IN THE ELSE CASE NOW
OUTPUT:
Enter the number of rows of pascal triangle you want:
(1)
(1)(1)
(1)(2)(1)
(1)(3)(3)(1)
(1)(4)(6)(4)(1)
(1)(5)(10)(10)(5)(1)
But i added () to make it clearer to me. I also added a "/n" to the end of the first printf that asks for the value of num, so that the first line is on a new line.
printf("Enter the number of rows of pascal triangle you want:\n");
You can do that without using any arrays:
#include <stdlib.h>
#include <stdio.h>
int num_digits(int number)
{
int digits = 0;
while (number) {
number /= 10;
++digits;
}
return digits;
}
unsigned max_pascal_value(int row)
{
int result = 1;
for (int num = row, denom = 1; num > denom; --num, ++denom)
result = (int)(result * (double)num / denom );
return result;
}
int main()
{
printf("Enter the number of rows of pascals triangle you want: ");
int rows;
if (scanf("%d", &rows) != 1) {
fputs("Input error. Expected an integer :(\n\n", stderr);
return EXIT_FAILURE;
}
int max_digits = num_digits(max_pascal_value(rows));
for (int i = 0; i <= rows; ++i) {
for (int k = 0; k < (rows - i) * max_digits / 2; ++k)
putchar(' ');
int previous = 1;
printf("%*i ", max_digits, previous);
for (int num = i, denom = 1; num; --num, ++denom) {
previous = (int)(previous * (double)num / denom );
printf("%*i ", max_digits, previous);
}
putchar('\n');
}
}
Output:
Enter the number of rows of pascals triangle you want: 15
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1

Sorting 2d array (matrix) in C

I have a task to sort a 2d array but it is really hard for me. I can't figure out where I'm making a mistake.
It will be good to use while loop instead of for loop
Here is the task:
Enter a square matrix of dimensions n.
Elements below main diagonal sort in ascending order.
Elements above main diagonal sort in descending order.
Elements on main diagonal sort:
first even numbers in ascending order.
then odd numbers in descending order.
Matrix before sorting:
1 5 4 7 2
4 8 5 9 0
2 7 6 5 3
3 1 7 4 9
2 5 1 7 3
Matrix after sorting :
4 9 9 7 5
1 6 5 5 4
1 2 8 3 2
2 3 4 3 0
5 7 7 7 1
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main () {
int n, i, j, a, k, l, o;
int m[50][50];
printf ("Enter n of square matrix : \n");
scanf ("%d", &n);
printf ("Enter rows and columns numbers n :\n");
i = 0;
while (i < n) {
j = 0;
while (j < n) {
scanf ("%d", &m[i][j]);
j++;
}
i++;
}
printf ("Matrix before sorting \n");
i = 0;
while (i < n) {
j = 0;
while (j < n) {
printf ("%d ", m[i][j]);
j++;
}
printf ("\n");
i++;
}
printf ("Matrix after sorting \n");
i = 0;
while (i < n) {
j = 0;
while (j < n) {
if (i < j) {
k = j + 1;
while (k < (n - 1)) {
if (m[i][k] < m[i][k + 1]) {
a = m[i][k];
m[i][k] = m[i][k + 1];
m[i][k + 1] = a;
}
k++;
}
}
else if (i > j) {
l = i + 1;
while (l < (n - 1)) {
if (m[l][j] > m[l + 1][j]) {
a = m[l][j];
m[l][j] = m[l + 1][j];
m[l + 1][j] = a;
}
l++;
}
}
else {
if (m[i][j] % 2 == 0 && m[i + 1][j + 1] % 2 == 0) {
if (m[i][j] > m[i + 1][j + 1]) {
a = m[i][j];
m[i][j] = m[i + 1][j + 1];
m[i + 1][j + 1] = a;
}
}
if (m[i][j] % 2 != 0 && m[i + 1][j + 1] % 2 != 0) {
if (m[i][j] < m[i + 1][j + 1]) {
a = m[i][j];
m[i][j] = m[i + 1][j + 1];
m[i + 1][j + 1] = a;
}
}
}
j++;
}
i++;
}
i = 0;
while (i < n) {
j = 0;
while (j < n) {
printf ("%d ", m[i][j]);
j++;
}
printf ("\n");
i++;
}
return 0;
}
CHANGES MADE ON 02/02/2018
I need to make simple code , without things like size_t,buffer and pointers etc...
I made some code but when i use odd n number of matrix it wont work properly (for example 5x5) I don't know where i m making mistake .
#include <stdio.h>
#include <stdlib.h>
int main()
{
static int a[500][500];
int i,j,l,k,m,b,n,t,d,c;
printf("Unesite n kvadratne matrice : \n");
scanf("%d" , &n);
printf("Matrica pre sortiranja \n \n");
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n ; j++)
{
scanf("%d",&a[ i ][ j ]);
}
}
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
if ( i > j ) // ispod dijagonale
{
for ( l = i ; l < n ; l++)
{
for ( k = j ; k < l ; k++ )
{
if ( a[ i ][ j ] > a[ l ][ k ] && k < l )
{
t = a[ i ][ j ];
a[ i ][ j ] = a[ l ][ k ];
a[ l ][ k ] = t ;
}
}
}
}
if ( i < j ) // iznad dijagonale
{
for ( m = i ; m < n ; m++)
{
for ( b = j ; b < n ; b++)
{
if ( a[ i ][ j ] < a[ m ][ b ] && m < b )
{
t = a[ i ][ j ];
a[ i ][ j ] = a[ m ][ b ];
a[ m ][ b ] = t ;
}
}
}
}
if ( i == j ) // dijagonala
{
for (d = i ; d < n ; d++)
{
for ( c = d + 1 ; c < n ; c++)
{
if ( a[ d ] [ d ] % 2 != 0 && a[ c ] [ c]%2 == 0 )
{
t = a[ d ] [ d ] ;
a[ d ] [ d ] = a[ c ] [ c] ;
a[ c ] [ c] = t ;
}
}
}
for (d = i ; d < n ; d++)
{
for ( c = d + 1 ; c < n ; c++)
{
if ( a[ d ][ d ] %2 == 0 && a[ c ][ c ] %2 ==0
&& a[ d ][ d ] > a [ c ][ c ])
{
t = a[ d ] [ d ] ;
a[ d ] [ d ] = a[ c ] [ c] ;
a[ c ] [ c] = t ;
}
else if ( a[ d ][ d ] %2 != 0 && a[ c ][ c ] %2
!=0 && a[ d ][ d ] < a [ c ][ c ])
{
t = a[ d ] [ d ] ;
a[ d ] [ d ] = a[ c ] [ c] ;
a[ c ] [ c] = t ;
}
}
}
}
}
}
printf("Posle sortiranja : \n");
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n;j++)
{
printf(" %d ",a[i][j]);
}
printf("\n \n");
}
return 0;
}
It's an intriguing problem. As I outlined in a comment, I think the solution has to be tackled in three separate sorting operations:
Sorting the diagonal
Sorting the upper triangle
Sorting the lower triangle
The sequence in which those operations occur is immaterial. Indeed, if you want to run the three sorts in parallel with threads, you could do that.
The trick to sorting the diagonal is to write a comparison function that ensures that all even numbers come before all odd numbers (so every even number is deemed smaller than any odd number), but when two even numbers are compared, they're sorted in ascending order whereas when two odd numbers are compared, they're sorted in descending order. The cmp_aeod() function (ascending even odd descending) function achieves this.
It would be possible to work with just one of the cmp_asc() and cmp_dsc() functions, but it is more straight-forward to have both. The (x > y) - (x < y) idiom does two comparison always, but if x is bigger than y, the first term is 1, the second 0, and the result is 1. If x is smaller than y, the first term is 0, the second is 1, and the result is -1. If x is equal to y, of course, both terms are 0 and the result is also 0.
The key to sorting the triangles is to note that sorting algorithms work on contiguous arrays, but the data in the triangles is not contiguous. The solution shown is to number the elements in the triangle from 0 to m, where m = (n * (n - 1)) / 2, given that the square matrix is an n by n one. The code then needs to be able to identify which indexes in the matrix should be accessed for the corresponding element number, and this mapping is done by the ut or lt matrix in the triangle-sorting functions. I couldn't work out a non-iterative formula to convert the sequence number in the triangle into a row/col pair, so I created the map matrix. This gives an auxilliary storage requirement of size O(N2).
The sort algorithm used is a simple quadratic sort; you can change it for a more sophisticated algorithm (quicksort or whatever) as you wish.
/*
** + Enter a square matrix of dimensions n .
** + Elements below main diagonal sort in ascending order.
** + Elements above main diagonal sort in descending order.
** + Elements on main diagonal sort :
** - first even numbers in ascending order.
** - then odd numbers in descending order.
*/
static inline int cmp_asc(int x, int y) { return (x > y) - (x < y); }
static inline int cmp_dsc(int x, int y) { return (x < y) - (x > y); }
static inline int cmp_eaod(int x, int y)
{
int px = x & 1;
int py = y & 1;
if (px != py)
return px - py;
if (px == 1)
return cmp_dsc(x, y);
return cmp_asc(x, y);
}
#include <stdio.h>
static void print_matrix(const char *tag, size_t r, size_t c, int matrix[r][c])
{
printf("%s:\n", tag);
for (size_t i = 0; i < r; i++)
{
for (size_t j = 0; j < c; j++)
printf("%3d", matrix[i][j]);
putchar('\n');
}
}
static void sort_diagonal(size_t n, int matrix[n][n])
{
for (size_t i = 0; i < n; i++)
{
for (size_t j = i + 1; j < n; j++)
{
if (cmp_eaod(matrix[i][i], matrix[j][j]) > 0)
{
int t = matrix[i][i];
matrix[i][i] = matrix[j][j];
matrix[j][j] = t;
}
}
}
}
/*
** D0 U0 U1 U2 U3
** L0 D1 U4 U5 U6
** L1 L2 D3 U7 U8
** L3 L4 L5 D4 U9
** L6 L7 L8 L9 D5
**
** D0 = (0, 0); U0 = (0, 1); U1 = (0, 2); U2 = (0, 3); U3 = (0, 4);
** L0 = (1, 0); D1 = (1, 1); U4 = (1, 2); U5 = (1, 3); U6 = (1, 4);
** L1 = (2, 0); L2 = (2, 1); D2 = (2, 2); U7 = (2, 3); U8 = (2, 4);
** L3 = (3, 0); L4 = (3, 1); L5 = (3, 2); D3 = (3, 3); U9 = (3, 4);
** L6 = (4, 0); L7 = (4, 1); L8 = (4, 2); L9 = (4, 3); D4 = (4, 4);
*/
/*
** It is probably best to create an array that does the mapping from an
** index to the row/column, with one such mapping for the lower
** triangle; one for the upper triangle.
*/
static void sort_lt(size_t n, int matrix[n][n])
{
size_t m = (n * (n - 1)) / 2;
int lt[m][2];
size_t r = 1;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
lt[i][0] = r;
lt[i][1] = c++;
if (c == r)
{
r++;
c = 0;
}
}
//print_matrix("LT map", m, 2, lt);
for (size_t i = 0; i < m; i++)
{
size_t xi = lt[i][0];
size_t yi = lt[i][1];
for (size_t j = i + 1; j < m; j++)
{
size_t xj = lt[j][0];
size_t yj = lt[j][1];
if (cmp_asc(matrix[xi][yi], matrix[xj][yj]) > 0)
{
int t = matrix[xi][yi];
matrix[xi][yi] = matrix[xj][yj];
matrix[xj][yj] = t;
}
}
}
}
static void sort_ut(size_t n, int matrix[n][n])
{
size_t m = (n * (n - 1)) / 2;
int ut[m][2];
size_t r = 0;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
ut[i][0] = r;
ut[i][1] = ++c;
if (c == n - 1)
{
r++;
c = r;
}
}
//print_matrix("UT map", m, 2, ut);
for (size_t i = 0; i < m; i++)
{
size_t xi = ut[i][0];
size_t yi = ut[i][1];
for (size_t j = i + 1; j < m; j++)
{
size_t xj = ut[j][0];
size_t yj = ut[j][1];
if (cmp_dsc(matrix[xi][yi], matrix[xj][yj]) > 0)
{
int t = matrix[xi][yi];
matrix[xi][yi] = matrix[xj][yj];
matrix[xj][yj] = t;
}
}
}
}
static void test_matrix(const char *tag, size_t n, int matrix[n][n])
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "Matrix %s (%zux%zu) - before", tag, n, n);
print_matrix(buffer, n, n, matrix);
//print_matrix("Before sorting diagonal", n, n, matrix);
sort_diagonal(n, matrix);
//print_matrix("After sorting diagonal", n, n, matrix);
sort_lt(n, matrix);
//print_matrix("After sorting lower triangle", n, n, matrix);
sort_ut(n, matrix);
//print_matrix("After sorting upper triangle", n, n, matrix);
snprintf(buffer, sizeof(buffer), "Matrix %s (%zux%zu) - after", tag, n, n);
print_matrix(buffer, n, n, matrix);
}
int main(void)
{
int matrix1[5][5] =
{
{ 1, 5, 4, 7, 2 },
{ 4, 8, 5, 9, 0 },
{ 2, 7, 6, 5, 3 },
{ 3, 1, 7, 4, 9 },
{ 2, 5, 1, 7, 3 },
};
test_matrix("SAMPLE1", 5, matrix1);
// gen_matrix -i -n matrix2 -r 10 -c 10 -L 10 -H 99
int matrix2[10][10] =
{
{ 87, 32, 98, 58, 60, 71, 46, 81, 70, 14, },
{ 22, 92, 15, 98, 51, 26, 94, 67, 46, 56, },
{ 71, 89, 86, 16, 20, 89, 97, 89, 45, 92, },
{ 63, 13, 76, 19, 75, 19, 66, 89, 58, 41, },
{ 82, 68, 75, 26, 58, 20, 89, 87, 65, 66, },
{ 74, 83, 68, 92, 10, 98, 90, 21, 39, 63, },
{ 24, 65, 23, 68, 62, 44, 48, 22, 27, 59, },
{ 26, 27, 71, 71, 51, 31, 43, 69, 92, 10, },
{ 54, 19, 41, 50, 10, 89, 42, 52, 94, 54, },
{ 42, 50, 79, 48, 77, 18, 29, 40, 61, 63, },
};
test_matrix("SAMPLE 2", 10, matrix2);
return 0;
}
When run, the output is:
Matrix SAMPLE1 (5x5) - before:
1 5 4 7 2
4 8 5 9 0
2 7 6 5 3
3 1 7 4 9
2 5 1 7 3
Matrix SAMPLE1 (5x5) - after:
4 9 9 7 5
1 6 5 5 4
1 2 8 3 2
2 3 4 3 0
5 7 7 7 1
Matrix SAMPLE 2 (10x10) - before:
87 32 98 58 60 71 46 81 70 14
22 92 15 98 51 26 94 67 46 56
71 89 86 16 20 89 97 89 45 92
63 13 76 19 75 19 66 89 58 41
82 68 75 26 58 20 89 87 65 66
74 83 68 92 10 98 90 21 39 63
24 65 23 68 62 44 48 22 27 59
26 27 71 71 51 31 43 69 92 10
54 19 41 50 10 89 42 52 94 54
42 50 79 48 77 18 29 40 61 63
Matrix SAMPLE 2 (10x10) - after:
48 98 98 97 94 92 92 90 89 89
10 58 89 89 87 81 75 71 70 67
10 13 86 66 66 65 63 60 59 58
18 19 22 92 58 56 54 51 46 46
23 24 26 26 94 45 41 39 32 27
27 29 31 40 41 98 26 22 21 20
42 42 43 44 48 50 87 20 19 16
50 51 52 54 61 62 63 69 15 14
65 68 68 68 71 71 71 74 63 10
75 76 77 79 82 83 89 89 92 19
The 'SAMPLE1 - before' data corresponds to the input in the question, and the 'SAMPLE 1 - after' output corresponds to the desired output. The bigger matrix result seems to match the requirements too.
I developed the diagonal sort first because it is by far the easiest; the even ascending, odd descending order is a problem I'd solved before. I then developed one of the triangle sorts, and debugged that. Getting the second triangle sorted was then very straight-forward. Making sure that I had a good flexible matrix printing function also helped. The commented out calls were all used at some point during the development.
Timing tests
The 'sort in place' code shown becomes very slow as the matrix grows. There's an alternative method — copy the data out of the matrix into a 1D vector; sort the vector; copy the data back into the matrix. I did some timing tests. With a matrix size of 10x10, the times were comparable (15µs for the basic sort code shown above; 12µs for code using extract, quicksort, insert). When the matrix size was 20x20, the performance was firmly in favour of the extract, quicksort, insert: 172µs vs 32µs in favour of quicksort, and by 900x900, the basic sort was taking 285s vs 0.054s for quicksort. The discrepancy is growing faster than a quadratic sort can account for. The trouble is the very complex access path to get to the elements being sorted. The code for creating the lt and ut matrices remains useful. The lt and ut matrices tell you which cells to collect the data from for sorting the triangle (order doesn't much matter while extracting the data since it is about to be sorted anyway), but also (crucially) tells you where to place each element in the sorted data.
You can find my code on GitHub in my SOQ (Stack
Overflow Questions) repository in the
src/so-4829-1562
sub-directory. (Note that at the moment, the code uses VLAs for intermediate matrices; it crashes at around 1000x1000 on a Mac. I need to change it to use dynamic memory allocation in the sort code as well as in the data generation code. It may get fixed, sooner or later. Also, I'm not convinced there's enough time between refreshes of hardware to use the basic sort on 10000x10000 size matrices, though I think the quick sort code would still be usable.)
Another interesting test would be to adapt the 'basic sort' to use extract, quadratic sort, insert when sorting the triangles. I'm pretty sure it would vastly outpace the 'basic sort' code, though it would still lose out to the O(NlogN) quick sort code as the arrays got bigger. The copying time becomes negligible compared to the sorting time.
Using qsort() etc
/* SO 4829-1562 */
#include "time.sort2d-31.h"
#include "emalloc.h"
/*
** + Enter a square matrix of dimensions n .
** + Elements below main diagonal sort in ascending order.
** + Elements above main diagonal sort in descending order.
** + Elements on main diagonal sort :
** - first even numbers in ascending order.
** - then odd numbers in descending order.
*/
/* Variation 4: Use system qsort() and common code to coordinate sorting of triangles */
/* Avoids two matrices lt and ut, thereby reducing the extra data space needed. */
static inline int cmp_asc(int x, int y) { return (x > y) - (x < y); }
static inline int cmp_dsc(int x, int y) { return (x < y) - (x > y); }
static inline int cmp_eaod(int x, int y)
{
int px = x & 1;
int py = y & 1;
if (px != py)
return px - py;
if (px == 1)
return cmp_dsc(x, y);
return cmp_asc(x, y);
}
static int qs_cmp_int_asc(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
return cmp_asc(i1, i2);
}
static int qs_cmp_int_dsc(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
return cmp_dsc(i1, i2);
}
static int qs_cmp_int_eaod(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
return cmp_eaod(i1, i2);
}
static void sort_diagonal(size_t n, int matrix[n][n])
{
int data[n];
for (size_t i = 0; i < n; i++)
data[i] = matrix[i][i];
qsort(data, n, sizeof(data[0]), qs_cmp_int_eaod);
for (size_t i = 0; i < n; i++)
matrix[i][i] = data[i];
}
/*
** D0 U0 U1 U2 U3
** L0 D1 U4 U5 U6
** L1 L2 D3 U7 U8
** L3 L4 L5 D4 U9
** L6 L7 L8 L9 D5
**
** D0 = (0, 0); U0 = (0, 1); U1 = (0, 2); U2 = (0, 3); U3 = (0, 4);
** L0 = (1, 0); D1 = (1, 1); U4 = (1, 2); U5 = (1, 3); U6 = (1, 4);
** L1 = (2, 0); L2 = (2, 1); D2 = (2, 2); U7 = (2, 3); U8 = (2, 4);
** L3 = (3, 0); L4 = (3, 1); L5 = (3, 2); D3 = (3, 3); U9 = (3, 4);
** L6 = (4, 0); L7 = (4, 1); L8 = (4, 2); L9 = (4, 3); D4 = (4, 4);
*/
typedef void (*Copier)(int *val1, int *val2);
static void copy_a_to_b(int *val1, int *val2) { *val2 = *val1; }
static void copy_b_to_a(int *val1, int *val2) { *val1 = *val2; }
static void copy_lt_data(size_t n, int matrix[n][n], int vector[], Copier copy)
{
size_t m = (n * (n - 1)) / 2;
size_t r = 1;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
(*copy)(&matrix[r][c++], &vector[i]);
if (c == r)
{
r++;
c = 0;
}
}
}
static void copy_ut_data(size_t n, int matrix[n][n], int vector[], Copier copy)
{
size_t m = (n * (n - 1)) / 2;
size_t r = 0;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
(*copy)(&matrix[r][++c], &vector[i]);
if (c == n - 1)
{
r++;
c = r;
}
}
}
typedef void (*Mapper)(size_t n, int matrix[n][n], int vector[], Copier copy);
typedef int (*Comparator)(const void *v1, const void *v2);
static void sort_triangle(size_t n, int matrix[n][n], Mapper mapper, Comparator cmp)
{
size_t m = (n * (n - 1)) / 2;
int *data = MALLOC(m * sizeof(*data));
(*mapper)(n, matrix, data, copy_a_to_b);
qsort(data, m, sizeof(data[0]), cmp);
(*mapper)(n, matrix, data, copy_b_to_a);
FREE(data);
}
void quick_sort(size_t n, int matrix[n][n])
{
sort_diagonal(n, matrix);
sort_triangle(n, matrix, copy_lt_data, qs_cmp_int_asc);
sort_triangle(n, matrix, copy_ut_data, qs_cmp_int_dsc);
}
I also put a timing test together — see GitHub for the source code. The results were:
Basic sort (10x10) - elapsed: 0.000010
Clean sort (10x10) - elapsed: 0.000008
Quick sort (10x10) - elapsed: 0.000015
Basic sort (20x20) - elapsed: 0.000153
Clean sort (20x20) - elapsed: 0.000112
Quick sort (20x20) - elapsed: 0.000026
Basic sort (30x30) - elapsed: 0.000800
Clean sort (30x30) - elapsed: 0.000645
Quick sort (30x30) - elapsed: 0.000060
Basic sort (40x40) - elapsed: 0.002661
Clean sort (40x40) - elapsed: 0.002057
Quick sort (40x40) - elapsed: 0.000106
Basic sort (50x50) - elapsed: 0.006347
Clean sort (50x50) - elapsed: 0.005038
Quick sort (50x50) - elapsed: 0.000175
Basic sort (60x60) - elapsed: 0.014120
Clean sort (60x60) - elapsed: 0.009732
Quick sort (60x60) - elapsed: 0.000258
Basic sort (70x70) - elapsed: 0.023101
Clean sort (70x70) - elapsed: 0.016593
Quick sort (70x70) - elapsed: 0.000360
Basic sort (80x80) - elapsed: 0.035169
Clean sort (80x80) - elapsed: 0.027466
Quick sort (80x80) - elapsed: 0.000445
Basic sort (90x90) - elapsed: 0.053590
Clean sort (90x90) - elapsed: 0.039012
Quick sort (90x90) - elapsed: 0.000665
Basic sort (100x100) - elapsed: 0.074192
Clean sort (100x100) - elapsed: 0.053694
Quick sort (100x100) - elapsed: 0.000797
Basic sort (200x200) - elapsed: 0.656721
Clean sort (200x200) - elapsed: 0.478688
Quick sort (200x200) - elapsed: 0.002313
Basic sort (300x300) - elapsed: 2.826153
Clean sort (300x300) - elapsed: 2.126663
Quick sort (300x300) - elapsed: 0.004871
Basic sort (400x400) - elapsed: 8.384908
Clean sort (400x400) - elapsed: 6.374244
Quick sort (400x400) - elapsed: 0.008324
Basic sort (500x500) - elapsed: 22.083337
Clean sort (500x500) - elapsed: 16.124325
Quick sort (500x500) - elapsed: 0.014953
Basic sort (600x600) - elapsed: 43.233985
Clean sort (600x600) - elapsed: 31.362548
Quick sort (600x600) - elapsed: 0.019563
Basic sort (700x700) - elapsed: 85.463261
Clean sort (700x700) - elapsed: 60.488744
Quick sort (700x700) - elapsed: 0.027003
Basic sort (800x800) - elapsed: 148.358024
Clean sort (800x800) - elapsed: 102.991679
Quick sort (800x800) - elapsed: 0.038143
Basic sort (900x900) - elapsed: 253.434539
Clean sort (900x900) - elapsed: 150.658682
Quick sort (900x900) - elapsed: 0.045815
Quick sort (10x10) - elapsed: 0.000007
Quick sort (20x20) - elapsed: 0.000025
Quick sort (30x30) - elapsed: 0.000057
Quick sort (40x40) - elapsed: 0.000104
Quick sort (50x50) - elapsed: 0.000196
Quick sort (60x60) - elapsed: 0.000245
Quick sort (70x70) - elapsed: 0.000397
Quick sort (80x80) - elapsed: 0.000435
Quick sort (90x90) - elapsed: 0.000538
Quick sort (100x100) - elapsed: 0.000676
Quick sort (200x200) - elapsed: 0.002780
Quick sort (300x300) - elapsed: 0.005868
Quick sort (400x400) - elapsed: 0.009393
Quick sort (500x500) - elapsed: 0.016258
Quick sort (600x600) - elapsed: 0.024982
Quick sort (700x700) - elapsed: 0.031137
Quick sort (800x800) - elapsed: 0.042561
Quick sort (900x900) - elapsed: 0.052450
Quick sort (1000x1000) - elapsed: 0.061720
Quick sort (2000x2000) - elapsed: 0.229984
Quick sort (3000x3000) - elapsed: 0.480724
Quick sort (4000x4000) - elapsed: 0.826916
Quick sort (5000x5000) - elapsed: 1.308370
Quick sort (6000x6000) - elapsed: 1.890218
Quick sort (7000x7000) - elapsed: 2.559171
Quick sort (8000x8000) - elapsed: 3.346258
Quick sort (9000x9000) - elapsed: 4.359553
Quick sort (10000x10000) - elapsed: 5.345243
Quick sort (20000x20000) - elapsed: 22.189061
Quick sort (30000x30000) - elapsed: 51.385711
Quick sort (40000x40000) - elapsed: 97.543689
Quick sort (50000x50000) - elapsed: 177.373366
Quick sort (60000x60000) - elapsed: 315.083561
Quick sort (70000x70000) - elapsed: 476.135379
Quick sort (80000x80000) - elapsed: 756.888114
Quick sort (90000x90000) - elapsed: 1002.540185
At the very smallest sizes (10x10 or less), it is possible that the qsort() code is slower than the others — the difference is tiny (a few microseconds) but fairly consistent. By the time you've reached 20x20, the qsort() code is persistently faster, and the discrepancy grows. Note that the size, N, used for O(NlogN) or O(N2), corresponds to the square of the size of the matrix — so the amount of data to be sorted in a 20x20 matrix is four times the amount of data to be sorted in a 10x10 matrix. The performance of the basic sort or 'clean sort' is so bad that a 90k x 90k matrix doesn't bear thinking about, but the qsort() code sorts it in a time comparable to the time taken by the others to sort a 900 x 900 matrix (1/10,000th the size).
Fixing the code added 2018-02-02
The code added to the question on 2018-02-02 is a good attempt at solving the problem in a different way.
As noted by the OP, it sometimes fails to sort the data correctly.
The problem is that the code in the lower triangle
Here's the code fixed so it produces the correct output on the two sample matrices used previously.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
static int a[500][500];
int i, j, l, k, m, b, n, t, d, c;
printf("Unesite n kvadratne matrice:\n");
scanf("%d", &n);
printf("Matrica pre sortiranja\n\n");
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
scanf("%d", &a[i][j]);
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%3d", a[i][j]);
printf("\n");
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (i > j) // ispod dijagonale (LT)
{
int s = j + 1; // JL
for (l = i; l < n; l++)
{
//for (k = j; k < l; k++) // OP
for (k = s; k < l; k++) // JL
{
//printf("a[%d][%d] = %d <=> a[%d][%d] %d\n", // JL
// i, j, a[i][j], l, k, a[l][k]); // JL
//if (a[i][j] > a[l][k] && k < l) // OP
if (a[i][j] > a[l][k]) // JL
{
t = a[i][j];
a[i][j] = a[l][k];
a[l][k] = t;
}
}
s = 0; // JL
}
}
if (i < j) // iznad dijagonale (UT)
{
int s = j + 1; // JL
for (m = i; m < n; m++)
{
//for (b = j; b < n; b++) // OP
for (b = s; b < n; b++) // JL
{
//printf("a[%d][%d] = %d <=> a[%d][%d] %d\n", // JL
// i, j, a[i][j], m, b, a[m][b]); // JL
//if (a[i][j] < a[m][b] && m < b) // OP
if (a[i][j] < a[m][b]) // JL
{
t = a[i][j];
a[i][j] = a[m][b];
a[m][b] = t;
}
}
s = m + 2; // JL
}
}
if (i == j) // dijagonala
{
for (d = i; d < n; d++)
{
for (c = d + 1; c < n; c++)
{
if (a[d][d] % 2 != 0 && a[c][c] % 2 == 0)
{
t = a[d][d];
a[d][d] = a[c][c];
a[c][c] = t;
}
}
}
for (d = i; d < n; d++)
{
for (c = d + 1; c < n; c++)
{
if (a[d][d] % 2 == 0 && a[c][c] % 2 == 0
&& a[d][d] > a[c][c])
{
t = a[d][d];
a[d][d] = a[c][c];
a[c][c] = t;
}
else if (a[d][d] % 2 != 0 && a[c][c] % 2
!= 0 && a[d][d] < a[c][c])
{
t = a[d][d];
a[d][d] = a[c][c];
a[c][c] = t;
}
}
}
}
}
}
printf("Posle sortiranja:\n");
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%3d", a[i][j]);
printf("\n");
}
return 0;
}
The commented out printing operations were crucial to seeing what the trouble was.
Sample output
This program was sort2d-mk2-73.
$ sort2d-mk2-73 < example-2.in
Unesite n kvadratne matrice:
Matrica pre sortiranja
87 32 98 58 60 71 46 81 70 14
22 92 15 98 51 26 94 67 46 56
71 89 86 16 20 89 97 89 45 92
63 13 76 19 75 19 66 89 58 41
82 68 75 26 58 20 89 87 65 66
74 83 68 92 10 98 90 21 39 63
24 65 23 68 62 44 48 22 27 59
26 27 71 71 51 31 43 69 92 10
54 19 41 50 10 89 42 52 94 54
42 50 79 48 77 18 29 40 61 63
Posle sortiranja:
48 98 98 97 94 92 92 90 89 89
10 58 89 89 87 81 75 71 70 67
10 13 86 66 66 65 63 60 59 58
18 19 22 92 58 56 54 51 46 46
23 24 26 26 94 45 41 39 32 27
27 29 31 40 41 98 26 22 21 20
42 42 43 44 48 50 87 20 19 16
50 51 52 54 61 62 63 69 15 14
65 68 68 68 71 71 71 74 63 10
75 76 77 79 82 83 89 89 92 19
$ sort2d-mk2-73 < example-1.in
Unesite n kvadratne matrice:
Matrica pre sortiranja
1 5 4 7 2
4 8 5 9 0
2 7 6 5 3
3 1 7 4 9
2 5 1 7 3
Posle sortiranja:
4 9 9 7 5
1 6 5 5 4
1 2 8 3 2
2 3 4 3 0
5 7 7 7 1
$
For comparison, the code posted in the question (sort2d-mk2-67) generated:
$ sort2d-mk2-67 < example-2.in
Unesite n kvadratne matrice :
Matrica pre sortiranja
Posle sortiranja :
48 98 98 97 94 92 92 90 89 66
10 58 89 89 89 87 81 75 70 63
10 13 86 71 67 66 65 60 59 56
18 19 22 92 58 58 54 51 46 46
23 24 26 29 94 45 41 39 32 27
26 27 31 40 41 98 26 22 21 20
42 42 43 44 48 50 87 20 19 16
50 51 52 54 61 62 63 69 15 14
65 68 68 68 71 71 71 76 63 10
74 75 77 79 82 83 89 89 92 19
$ sort2d-mk2-67 < example-1.in
Unesite n kvadratne matrice :
Matrica pre sortiranja
Posle sortiranja :
4 9 9 7 5
1 6 5 5 3
1 2 8 4 2
2 3 5 3 0
4 7 7 7 1
$
One of the changes between sort2d-mk2-67.c and sort2d-mk2-73.c was compressing the printing; another change was to print the matrix before and after the sorting operation.
In the smaller matrix, you can see that the 3 in row 1 column 4 (counting from 0) should be the 4 in row 2 column 3.
Similarly, the 5 in row 3 column 2 should be the 4 in row 4 column 1.
The fixed code is OK.
I've not benchmarked this code (yet).

two dimensional array via pointer

I would like to create a dynamic array which store permutation sequence, such that
order[0][]={1,2,3}
order[1][]={2,1,3}
order[2][]={2,3,1}
let say order[m][n], m = number of permutation, n = number of term, m and n are identified in real-time.
I did the below, and found that the pointer address is overlapping, resulting in incorrect value storage. How can do it correctly using dynamic array via double pointer?
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
/* debug only */
for(y=num_term, x=0; y>0; y--, x++){
term[x] = y;
}
fprintf(stderr, "\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %-11d", x);
}
printf("\n");
for(y=0; y<num_permute; y++){
printf("%-5d%12p", y, (order+y));
memcpy(&(order[y]), term, sizeof(term));
for (x=0; x<num_term; x++)
printf(" %12p", order+y+x);
printf("\n");
}
}
int main(){
int y, z;
int** x;
x = (int*) malloc(5*5*sizeof(int*));
permute(5, 5, x);
printf("\n");
printf("x ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<5; y++){
printf("%-4d", y);
for(z=0; z<5; z++){
printf(" %2d ", *(x+y+z));
}
printf("\n");
}
free(x);
return 0;
}
Result: order[0][1] and order[1][0] point to same address... and so do others. With rows as the major axis and columns the minor:
order 0 1 2 3 4
0 0x100100080 0x100100080 0x100100084 0x100100088 0x10010008c 0x100100090
1 0x100100084 0x100100084 0x100100088 0x10010008c 0x100100090 0x100100094
2 0x100100088 0x100100088 0x10010008c 0x100100090 0x100100094 0x100100098
3 0x10010008c 0x10010008c 0x100100090 0x100100094 0x100100098 0x10010009c
4 0x100100090 0x100100090 0x100100094 0x100100098 0x10010009c 0x1001000a0
x 0 1 2 3 4
0 5 5 5 5 5
1 5 5 5 5 4
2 5 5 5 4 3
3 5 5 4 3 2
4 5 4 3 2 1
Source Code:
The code will be something like:
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
}
Concept:
array is a pointer-to-pointer-to-int: at the first level, it points to a block of pointers, one for each row. That first-level pointer is the first one to be allocated; it has nrows elements, with each element big enough to hold a pointer-to-int, or int *. If the allocation is successful then fill in the pointers (all nrows of them) with a pointer (also obtained from malloc) to ncolumns number of ints, the storage for that row of the array.
Pictorial Depiction:
It is simple to grasp if you visualize the situation as:
Taking this into account, the sample code could be rewritten as:
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
int* ptr = NULL;
for (y=num_term, x=0; y>0; y--, x++) {
term[x] = y;
}
printf("\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %2d ", x);
}
printf("\n");
for (y=0; y<num_permute; y++) {
ptr = order[y];
memcpy(ptr, term, sizeof(term));
printf("%-5d%12p", y, ptr);
for (x=0; x<num_term; x++) {
printf(" %2d ", ptr[x]);
}
printf("\n");
}
}
int main() {
int y, z;
int** x = NULL;
int num_term = 5;
int num_permutation = 5;
int* pchk = NULL;
x = (int**) malloc(num_permutation * sizeof(int*));
for (y=0; y<num_permutation; y++){
x[y] = (int*) malloc(num_term * sizeof(int));
printf("x[%d]: %p\n", y, x[y]);
}
permute(num_permutation, num_term, x);
printf("\nx: ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<num_permutation; y++){
pchk = x[y];
printf("%-4d", y);
for(z=0; z<num_term; z++){
printf(" %2d ", pchk[z]);
}
printf("\n");
}
for (y=0; y<num_permutation; y++) {
free(x[y]);
}
free(x);
return 0;
}
The code sample only simulates a multidimensional array, and does it incorrectly. To see what's going wrong, start by considering what happens when you declare a multidimensional array:
int foo[3][5];
This allocates a contiguous region of memory of size 3*5*sizeof(int). In an expression such as foo[i], the foo is converted to a int [5] pointer, then the index operator is applied. In other words, foo[i] is equivalent to *( (int (*)[5])foo) + i). Each foo[i] would be considered as having size 5*sizeof(int).
x,y: 0,0 0,1 0,2 0,3 0,4 1,0
foo --> | 1 | 2 | 3 | 4 | 5 | 1 |...
<- 5 * sizeof(int) ->
When you create x in the sample code, you're replicating this type of multidimensional array. The index expression you're using (*(order + y + x)) is thus wrong, as it doesn't properly handle the size of order[y]: order + 1 + 0 == order + 0 + 1, which is the problem you're seeing in the sample output.
The correct expressions are: (order + num_term * y) for the yth permutation and *(order + num_term * y + x) for element order[y][x].
This suggests another class of error in the sample. For this kind of simulated multidimensional array, the array types are actually pointers to single dimensional arrays. The declared types of x and order should be int*, not int**. This should be reinforced by the type warnings the sample code should generate:
when allocating space for x, the type of the pointer (int*) doesn't match the type of x
when printing the elements of x, the type of *(x+y+z) doesn't match the format "%d".
However, while simulating a multidimensional array saves space, it's more error prone when used (unless you write a function to handle indexing). A solution such as Als' may be safer, as you can use the standard indexing operator.
Emulating a 2D array with pointer arrays is a complete overkill if you have C99 (or C11). Just use
void permute(size_t num_permute, size_t num_term, unsigned order[][num_term]);
as your function signature and allocate your matrix in main with something like
unsigned (*order)[m] = malloc(sizeof(unsigned[n][m]));
Also, as you can see in the examples above, I'd suggest that you use the semantically correct types. Sizes are always best served with size_t and your permutation values look to me as if they will never be negative. Maybe for these you also should start counting from 0.
The following code snippet creates a 2d matrix for a given row and column. Please use this as a reference to debug your program.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int row, column;
int **matrix;
int i, j, val;
printf("Enter rows: ");
scanf("%d", &row);
printf("Enter columns: ");
scanf("%d", &column);
matrix = (int **) malloc (sizeof(int *) * row);
if (matrix == NULL) {
printf("ERROR: unable to allocate memory \n");
return -1;
}
for (i=0 ; i<row ; i++)
matrix[i] = (int *) malloc (sizeof(int) * column);
val=1;
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
matrix[i][j] = val++;
}
}
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
/*
Allocation of 2d matrix with only one call to malloc and
still get to access the matrix with a[i][j] format
the matrix is divided into headers and data.
headers = metadata to store the rows
data = actual data storage - buffer
allocate one contigious memory for header and data
and then make the elements in the header to point to the data are
<- headers -----><----------- data -----------
-----------------------------------------------------------------
| | | | | | .. |
| | | | | | .. |
-----------------------------------------------------------------
| ^
| |
|-----------------|
header points to data area
*/
/*
Output:
$ gcc 2darray.c
$ ./a.out
Enter rows: 10
Enter columns: 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
$
*/

Resources