How to initialize an array of arrays with non-constant length? - c

I am trying to make an array which contains 1D arrays of varying length. Due to the variation in length, I cannot use a 2D array. My code is as follows:
int ROW = 6;
int COL = 4;
int faceverts[6][4] = {{3,2,1,0}, {4,5,1,0}, {2,6,5,1}, {2,3,5,6}, {7,3,0,4}, {1,6,7,4}};
int (*q)[4] = faceverts;
int main(){
for (int i = 0; i < ROW; i++){
for (int k = 0; k < COL; k++)
printf("%d ", *(*(q+i)+k));
printf("\n");
}
}
My goal is to be able to get rid of those ROW and COL variables, as well as not have a fixed 2D array, but rather an array of 1D arrays of varying length. I have been told that using pointers is key to doing this task, but I do not know how to do this myself.

One approach is to create an array of structures. Each structure element contains a pointer and count to an array.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *a;
size_t n;
} TwoD;
#define AN(a) (sizeof (a)/sizeof (a)[0])
int smallest[1] = { 1 };
int smaller[2] = { 2, 3 };
int small[3] = { 4, 5, 6 };
int big[4] = { 7, 8, 9, 10 };
int bigger[5] = { 11, 12, 13, 14, 15 };
int biggest[6] = { 16, 17, 18, 19, 20, 21 };
TwoD faceverts[6] = {
{ smallest, AN(smallest) }, { smaller, AN(smaller) }, { small, AN(small) },
{ big, AN(big) }, { bigger, AN(bigger) }, { biggest, AN(biggest) } };
int main(void) {
// Let us change things a bit at run time
int change[] = { 22,23,24,25,26,27,28 };
faceverts[0] = (TwoD) {change, AN(change)}; // compound literal
for (size_t row = 0; row < AN(faceverts); row++) {
for (size_t col = 0; col < faceverts[row].n; col++) {
printf(" %d", faceverts[row].a[col]);
}
printf("\n");
}
return 0;
}
Output
22 23 24 25 26 27 28
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21

There is only 1D array in memory. (2D array is actually a long 1D array)
Allocate a 2D array (rows, cols)
int *arr;
int size;
size = width * height;
arr = (int *) malloc(sizeof(int) * size);
Access element (x, y) in the array
int e;
int offset;
offset = x * cols + y;
e = *(arr + offset);
Free the array
free(arr);
Allocate a irregular 2D array (col_0, col_2, ...., col_n-1);
int arr;
int size = 0;
// size = col_0 + ... + col_n-1;
arr = (int *) malloc(sizeof(int) * size);
Access element (x_row, y_col) in the array
int e;
int offset;
// offset = col_1 + ... + col_x-1 + y_col;
e = *(arr + offset);

Related

Array of Matrices with Different sizes in C

I am trying to make an array of say 3 matrices with different sizes:
Array ={ {{1, 2, 3}, {10, 20, 30}},
{{4, 5}, {40, 50}, {400, 500}},
{{6, 7}, {60, 70}} };
I need to use array indexing rather than pointer arithmetic for my codes.
I think I should create a 1-d array containing 3 pointers to matrices. Something like:
{ *ptr1[3], *ptr2[2], *ptr3[2]}
But how can I declare such an object? Also how can I assign values to that?
I am readying the actual data from a binary file using fread.
Thank you,
Jagged array is array of arrays such that member arrays can be of different sizes, i.e., we can create a 2-D array but with a variable number of columns in each row.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int Mat1row0[3] = { 1, 2, 3};
int Mat1row1[3] = {10, 20, 30};
int Mat2row0[2] = {4, 5};
int Mat2row1[2] = {40, 50};
int Mat2row2[2] = {400, 500};
int Mat3row0[2] = {6, 7};
int Mat3row1[2] = {60, 70};
int* jagged1[2] = {Mat1row0, Mat1row1 };
int* jagged2[3] = {Mat2row0, Mat2row1, Mat2row2};
int* jagged3[2] = {Mat3row0, Mat3row1 };
int** jaggedkk[3] = {jagged1, jagged2, jagged3};
printf("%d",jaggedkk[0][0][0]);
return 0;
}
The output is : 1
You could create a struct to represent a matrix and then create an array of that struct. Further, you would need a function for initializing a matrix (i.e. allocate memory) and also a function for deleting a matrix (i.e. free allocated memory).
Something like:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
size_t rows;
size_t columns;
int **data;
} Matrix;
void initMatrix(size_t rows, size_t columns, Matrix *m)
{
if (rows == 0 || columns == 0) exit(1); // error
// Allocate row pointers
m->data = malloc(rows * sizeof m->data[0]);
if (m->data == NULL) exit(1); // error
// Allocate data area, i.e. rows x columns ints
m->data[0] = malloc(rows * columns * sizeof m->data[0][0]);
if (m->data[0] == NULL) exit(1); // error
// Initialize the remaining row pointers
for (size_t i=1; i < rows; ++i)
{
m->data[i] = m->data[0] + i * columns;
}
m->rows = rows;
m->columns = columns;
}
void deleteMatrix(Matrix *m)
{
free(m->data[0]);
free(m->data);
m->rows = 0;
m->columns = 0;
m->data = NULL;
}
void printMatrix(Matrix *m)
{
printf("---------------------------\n");
printf("rows=%zu columns=%zu\n", m->rows, m->columns);
for (size_t i=0; i < m->rows; ++i)
{
printf("row[%zu] at %p\t", i, (void*)m->data[i]);
for (size_t j=0; j < m->columns; ++j)
{
printf("%d\t", m->data[i][j]);
}
printf("\n");
}
printf("---------------------------\n");
}
int main(void)
{
Matrix m[2];
initMatrix(2, 5, &m[0]);
for(size_t i=0; i < 2; ++i)
{
for(size_t j=0; j < 5; ++j)
{
m[0].data[i][j] = 10*i + j;
}
}
initMatrix(3, 2, &m[1]);
for(size_t i=0; i < 3; ++i)
{
for(size_t j=0; j < 2; ++j)
{
m[1].data[i][j] = 100 + 10*i + j;
}
}
for(size_t i=0; i < 2; ++i)
{
printMatrix(&m[i]);
}
for(size_t i=0; i < 2; ++i)
{
deleteMatrix(&m[i]);
}
return 0;
}
Possible output:
---------------------------
rows=2 columns=5
row[0] at 0x1979030 0 1 2 3 4
row[1] at 0x1979044 10 11 12 13 14
---------------------------
---------------------------
rows=3 columns=2
row[0] at 0x1979080 100 101
row[1] at 0x1979088 110 111
row[2] at 0x1979090 120 121
---------------------------
A 'short/simple' solution could be just to write:
int *** Array =(int**[]){ (int*[]){(int[]){1, 2, 3}, (int[]){10, 20, 30}},
(int*[]){(int[]){4, 5}, (int[]){40, 50}, (int[]){400, 500}},
(int*[]){(int[]){6, 7}, (int[]){60, 70}} };
Now Array[0][0][0] will be 1, Array[2][1][1] will be 70, etc;
If you need to do it dynamically, you can do it the following way:
int *** Array;
Array = malloc(sizeof(int**)*3);
Array[0] = malloc(sizeof(int*)*2);
Array[0][0] = malloc(sizeof(int)*3);
Array[0][0][0] = 1;
...
(and so on)

Create a variable size matrix

I am trying to create a variable matrix using a function that inputs an empty array pointer m and outputs the int array pointer m with values 1,2,3,4,...n elements in the matrix. I use the variable k and increment the value upwards to accomplish this (not sure if this is the best way).
I am getting a subscripted value is not an array, pointer, or vector in my for loop here matrix[i][j] = k++; and I am not really sure why it is only appearing inside the for loop and nowhere else.
If I am inputting an int array pointer called matrix, I shouldn't be getting this error right?
int *create_matrix(int* matrix) {
int i,j;
int k = 0;
// 'total' will be 70 = 10 * 7
int total = sizeof(matrix);
// 'column' will be 7 = size of first row
int column = sizeof(matrix[0]);
// 'row' will be 10 = 70 / 7
int row = total / column;
for (i=0; i < row; i++) {
for (j=0; j < column; j++) {
matrix[i][j] = k++;
}
}
return matrix;
}
int main(void) {
// Creating a custom matrix.
int m[3][4] = {0};
create_matrix(*m);
return 0;
}
You need to learn the difference between arrays and pointers. You can point a pointer to a matrix, but the information about size and number of dimensions are lost as long as you're only accessing the array via the pointer.
You would need to do something like this:
int *create_matrix(int* matrix, size_t size_x, size_t size_y) {
...
}
int main()
{
int m[3][6];
size_t size_y=sizeof m[0]/sizeof m[0][0];
size_t size_x=sizeof m / sizeof m[0];
create_matrix(m);
}
To do
int m[3][4] = {0};
create_matrix(*m);
is equivalent of
int m[3][4] = {0};
create_matrix(m[0]);
so is equivalent of having
int m[4] = {0};
create_matrix(m);
// 'total' will be 70 = 10 * 7
int total = sizeof(matrix);
matrix is a int *, sizeof(matrix) values 4 if an address uses 32b and 8 if an address uses 64b
The effective size of matrix in main is not relevant
// 'column' will be 7 = size of first row
int column = sizeof(matrix[0]);
matrix[0] is an int, so you get the size of an int (4 or 8 probably)
matrix[i][j] = k++;
because matrix is an int * the form matrix[i][j] is invalid.
To name it matrix is not helpful.
Your program can be :
#include <stdio.h>
void fill_matrix(int matrix[][4], size_t row) {
size_t i, j;
int k = 0;
for (i=0; i < row; i++) {
for (j=0; j < sizeof(matrix[0])/sizeof(int); j++) {
matrix[i][j] = k++;
}
}
}
int main(void) {
// Creating a custom matrix.
int m[3][4] = {0};
fill_matrix(m, sizeof(m)/sizeof(m[0]));
size_t i, j;
for (i=0; i < sizeof(m)/sizeof(m[0]); i++) {
for (j=0; j < sizeof(m[0])/sizeof(int); j++) {
printf("matrix[%d][%d] = %d\n", i, j, m[i][j]);
}
}
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra m.c
pi#raspberrypi:/tmp $ ./a.out
matrix[0][0] = 0
matrix[0][1] = 1
matrix[0][2] = 2
matrix[0][3] = 3
matrix[1][0] = 4
matrix[1][1] = 5
matrix[1][2] = 6
matrix[1][3] = 7
matrix[2][0] = 8
matrix[2][1] = 9
matrix[2][2] = 10
matrix[2][3] = 11
Probably it is more visible if you initialize each cell of the matrix with i*10+j rather than with k++, in that case that prints :
matrix[0][0] = 0
matrix[0][1] = 1
matrix[0][2] = 2
matrix[0][3] = 3
matrix[1][0] = 10
matrix[1][1] = 11
matrix[1][2] = 12
matrix[1][3] = 13
matrix[2][0] = 20
matrix[2][1] = 21
matrix[2][2] = 22
matrix[2][3] = 23
Your attempt is a reasonable attempt but it reveals some misconceptions about how objects in C work. That's all right. Yours is a good teaching example and I believe that you will be glad that you have made it. Now try this:
static const int NO_ROWS = 3;
static const int NO_COLUMNS = 4;
int *create_matrix(
int *const matrix, const int no_rows, const int no_columns
) {
int k = 0;
for (int i = 0; i < no_rows; i++) {
for (int j = 0; j < no_columns; j++) {
matrix[no_columns*i+j] = k++;
}
}
return matrix;
}
int main(void) {
// Creating a custom matrix.
int m[NO_ROWS][NO_COLUMNS];
create_matrix(m[0], NO_ROWS, NO_COLUMNS);
return 0;
}
Your matrix is constructed as an array of arrays. However, in C, an array is just a region of storage in which a sequence of objects of the same type (in your case, int) can be kept. The symbol m is interpreted by the C compiler as
meaning the address of the matrix's initial element—or, more precisely, because your matrix is an array of arrays, the address of the matrix's initial row; and
referring to the type of the matrix's initial row, which is itself an array type, int[NO_COLUMNS].
The problem is that there exists no really neat, direct way to specify to a precompiled function the type int[NO_COLUMNS] unless you are willing to hard-code the type. Therefore, one relatively straightforward way to treat the matrix within create_matrix() would be as a single, linear array, as shown.
One point to grasp here is that C does not understand the shape of your matrix. Rather than rows and columns, C sees a linear region of storage.
Another point to grasp is that function to which an array is passed receives only the array's initial address. If it needs the size, that must be separately passed.

C: Initializing a dynamically typed 2D matrix inside another function

I am trying to create 3 matrices which are dynamically typed (int, float, double) for the purpose of matrix multiplication. I've created a void** "typed" container for each matrix in the main, then passing them (as void***) into an init function to be malloc'd based on user selections for the type. The code below compiles, but I am getting a segmentation fault after one iteration of the j loop, and I can't figure out for the life of me why this happens. Similarly if I were to do the initialization in a separate 2-deep loop (take out j-loop from malloc loop), then the segmentation error occurs after one iteration of the i-loop still.
Is this even a good way to accomplish my goal of dynamic-typed matrix multiplication? Thank you very much for the help.
void initMat(int type, int matSize, void ***matA, void ***matB, void ***matC)
{
int i, j, k;
switch(type) {
case 0 :
*matA = malloc(matSize * sizeof(int*));
*matB = malloc(matSize * sizeof(int*));
*matC = malloc(matSize * sizeof(int*));
for (i = 0; i < matSize; i++) {
*matA[i] = malloc(matSize * sizeof(int));
*matB[i] = malloc(matSize * sizeof(int));
*matC[i] = malloc(matSize * sizeof(int));
for (j = 0; j < matSize; j++) {
*(int*)matA[i][j] = rand()/RAND_MAX * 10;
*(int*)matB[i][j] = rand()/RAND_MAX * 10;
*(int*)matC[i][j] = 0;
}
}
break;
case 1 :
// with float, double, etc.
break;
default :
printf("Invalid case.\n" );
}
}
int main()
{
int type = 0;
int size = 0;
void **matA, **matB, **matC;
int sizes[6] = {3, 4, 5};
int matSize = sizes[size];
printf("The selected matrix size is: %d. \n", matSize); //allows user to select matrix size
initMat(type, matSize, &matA, &matB, &matC);
// displayMat(matSize, matA);
}
To work with dynamically allocated 2d arrays, correct pointer types should be used. (int **) is a pointer to a pointer, pointing to the first element of an array of pointers which themselves point to disparate allocations. The result of this sort of code is a jagged array, but not a 2d array. The allocated memory is not guaranteed to be contiguous (as array allocations must be):
size_t num_rows = 3;
size_t num_cols = 5;
int **jagged_arr = malloc(sizeof *jagged_arr * num_rows);
for (size_t i = 0; i < num_rows; i++) {
jagged_arr[i] = malloc(sizeof *jagged_arr[i] * num_cols);
}
One possibility is to simply allocate storage for a 1d array, and calculate offsets into this array from 2d array indices. This works fine, but the result is not a 2d array:
size_t num_elems = num_rows * num_cols;
int *simulated_2d_arr = malloc(sizeof *simulated_2d_arr * num_elems);
This can't be indexed as a 2d array, but the 1d index can be calculated from the number of columns and the 2d array indices:
for (size_t i = 0; i < num_rows; i++) {
for (size_t j = 0; j < num_cols; j++) {
simulated_2d_arr[i * num_cols + j] = i * num_cols + j;
}
}
Both of these approaches have their uses, but they suffer from a disadvantage in that the resulting arrays can't be passed to functions which are meant to work with 2d arrays. That is, consider a function to print a 2d array, such as:
void print_2d_arr(size_t rows, size_t cols, int arr[][cols])
{
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
printf("%5d", arr[i][j]);
}
putchar('\n');
}
}
This function will work for something like:
int real_2d_arr[2][3] = { { 1, 2, 3 },
{ 4, 5, 6 } };
But it will not work for the earlier jagged_arr:
expected ‘int (*)[(sizetype)(cols)]’ but argument is of type ‘int **’
or for simulated_2d_arr:
expected ‘int (*)[(sizetype)(cols)]’ but argument is of type ‘int *’
The correct type to use when dynamically allocating 2d arrays is seen in the above error messages. For a 2d array of ints, that would be int (*)[]. This is the type that a 2d array decays to in most expressions, including function calls. So, to dynamically allocate a 2d array of ints, this would work:
size_t num_rows = 3;
size_t num_cols = 5;
int (*array_2d)[num_cols] = malloc(sizeof *array_2d * num_rows);
This allocates space for num_rows arrays of num_cols ints. Note that this does not create a VLA, but the VLA type is used. Of course, VLAs were introduced back in C99, but were made optional in C11 (though still widely supported).
As for the dynamic type part of your question, one option would be to create an enum to hold type identifiers, and pass one of these enumeration constants to whatever functions need them. These functions will need to accept (void *) arguments, which will be appropriately converted based on the type enumeration constant. This is a little more involved, but here is an example program. Note that the print_array() function works for both the dynamically allocated arrays, and for a statically sized array. Also note that there is no need for triple, or even double indirection!
#include <stdio.h>
#include <stdlib.h>
enum Type { CHAR,
INT,
FLOAT,
DOUBLE };
void * get_array(enum Type type, size_t rows, size_t cols);
void init_array(enum Type type, size_t rows, size_t cols, void *arr);
void print_array(enum Type type, size_t rows, size_t cols, void *arr);
int main(void)
{
char (*arr_char)[5] = get_array(CHAR, 4, 5);
int (*arr_int)[5] = get_array(INT, 4, 5);
double (*arr_double)[5] = get_array(DOUBLE, 4, 5);
int arr_static[][3] = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
if (arr_char) { // check for null pointer
init_array(CHAR, 4, 5, arr_char);
puts("4x5 array of char");
print_array(CHAR, 4, 5, arr_char);
putchar('\n');
}
if (arr_int) { // check for null pointer
init_array(INT, 4, 5, arr_int);
puts("4x5 array of int");
print_array(INT, 4, 5, arr_int);
putchar('\n');
}
if (arr_double) { // check for null pointer
init_array(DOUBLE, 4, 5, arr_double);
puts("4x5 array of double");
print_array(DOUBLE, 4, 5, arr_double);
putchar('\n');
}
puts("Statically sized 3x3 array of int");
print_array(INT, 3, 3, arr_static);
putchar('\n');
/* Cleanup */
free(arr_char);
free(arr_int);
free(arr_double);
return 0;
}
/* Returns null pointer on allocation failure */
void *get_array(enum Type type, size_t rows, size_t cols)
{
size_t array_sz = 0;
void *ret = NULL;
switch (type) {
case CHAR:
array_sz = sizeof (char) * rows * cols;
break;
case INT:
array_sz = sizeof (int) * rows * cols;
break;
case FLOAT:
array_sz = sizeof (float) * rows * cols;
break;
case DOUBLE:
array_sz = sizeof (double) * rows * cols;
break;
default:
fprintf(stderr, "Unrecognized type in get_array()");
}
if (array_sz) {
ret = malloc(array_sz);
}
return ret;
}
void init_array(enum Type type, size_t rows, size_t cols, void *arr)
{
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
int offset = i * cols + j;
switch (type) {
case CHAR:
{
char (*array_char)[cols] = arr;
array_char[i][j] = 'a' + offset;
break;
}
case INT:
{
int (*array_int)[cols] = arr;
array_int[i][j] = 0 + offset;
break;
}
case FLOAT:
{
float (*array_float)[cols] = arr;
array_float[i][j] = 0.0 + offset;
break;
}
case DOUBLE:
{
double (*array_double)[cols] = arr;
array_double[i][j] = 0.0 + offset;
break;
}
default:
fprintf(stderr, "Unrecognized type in get_array()");
}
}
}
}
void print_array(enum Type type, size_t rows, size_t cols, void *arr)
{
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
switch (type) {
case CHAR:
{
char (*array_char)[cols] = arr;
printf("%3c", array_char[i][j]);
break;
}
case INT:
{
int (*array_int)[cols] = arr;
printf("%5d", array_int[i][j]);
break;
}
case FLOAT:
{
float (*array_float)[cols] = arr;
printf("%8.2f", array_float[i][j]);
break;
}
case DOUBLE:
{
double (*array_double)[cols] = arr;
printf("%8.2f", array_double[i][j]);
break;
}
default:
fprintf(stderr, "Unrecognized type in get_array()");
}
}
putchar('\n');
}
}
Program output:
4x5 array of char
a b c d e
f g h i j
k l m n o
p q r s t
4x5 array of int
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
4x5 array of double
0.00 1.00 2.00 3.00 4.00
5.00 6.00 7.00 8.00 9.00
10.00 11.00 12.00 13.00 14.00
15.00 16.00 17.00 18.00 19.00
Statically sized 3x3 array of int
1 2 3
4 5 6
7 8 9
Your basic problem is that postfix operators are higher precedence than prefix operators. So when you say
*matA[i] = malloc(matSize * sizeof(int));
you are getting
*(matA[i]) = malloc(matSize * sizeof(int));
when what you want is
(*matA)[i] = malloc(matSize * sizeof(int));
so you need the explicit parenthesis to make it work. Similarly, instead of
*(int*)matA[i][j] = rand()/RAND_MAX * 10;
you need
((int**)*matA)[i][j] = rand()/RAND_MAX * 10;
I've actually been working on something exactly like this on my own. My advice on how to do this is to actually abandon the way you're doing it. From the looks of it you have an array of pointers (lets say an array of int pointers), and each one of those pointers has an array of its own, basically a variable declared as such int **exampleMatrix. There's actually a huge issue with you doing it this way which is cache misses. A better way for you to do this is as follows
#include <stdlib.h>
void *initMat(size_t rows, size_t cols, int type);
int main(void){
int *matrix = initMat();
free(matrix);
return 0;
}
void *initMat(size_t rows, size_t cols, int type){
//check for what type to allocate here
void *matrix = malloc(sizeof(int)*rows*cols);
//check for errors here
return matrix;
}
you of course will have to decide if your matrix is row or column major. I hope this makes sense, English isn't my first language and I'm not the best at explaining sometimes. If you need me to explain it better just tell me :)
The way you're allocating memory is weird.
*matA = malloc(matSize * sizeof(int*));
Where does matA point??, unless you allocated some memory and made matA point to it outside this function then you are thrashing you memory.
Malloc returns a pointer to allocated memory, it doesn't allocate it wherever your random pointer is pointing.
You also don't need three levels of indirection***matA, two is enough.
This is your code with the changes I suggested - disclaimer:I didn't actually try this but I think it'll work-:
void initMat(int type, int matSize, void ***matA, void ***matB, void ***matC)
{
int i, j, k;
switch(type) {
case 0 :
*matA = malloc(matSize * sizeof(int*));
*matB = malloc(matSize * sizeof(int*));
*matC = malloc(matSize * sizeof(int*));
for (i = 0; i < matSize; i++) {
(*matA)[i] = malloc(matSize * sizeof(int));
(*matB)[i] = malloc(matSize * sizeof(int));
(*matC)[i] = malloc(matSize * sizeof(int));
for (j = 0; j < matSize; j++) {
(*matA)[i][j] = rand()/RAND_MAX * 10;
(*matB)[i][j] = rand()/RAND_MAX * 10;
(*matC)[i][j] = 0;
}
}
break;
case 1 :
// with float, double, etc.
break;
default :
printf("Invalid case.\n" );
}
}
and when calling:
int type,matSize;
//whatever type you like
Type **matA,**matB,**matC;
//your code here
initMat(type,matSize,&matA,&matB,&matC);
//the rest of your code here

How to find top 6 elements in an array in C

I am trying to find top 6 elements from an array with their ordering number.
int x=0;
for (int k = 0; k < 6; k++) //
{
for (i = 1; i <= 90; i++)
{
if (sorted[k] < holder[i] && i >= x)
{
sorted[k] = holder[i];
x = i; //
}
}
}
But this does not work. I want it to give me output like 43->7 15 ->3 etc..
Haven't written C in a while, but here is a simple solution that modifies the array in place and uses selection sort to select the k highest numbers in the array and moves them to the front. It keeps an array of indices that correspond to where the number originally was and applies the same swaps to it.
#include <stdio.h>
#define ELEMENTS 10
void main(void)
{
// example input for execution
int numbers[10] = {9,4,5,1,8,2,3,6,0,7};
// tracks ordering of indices
int indexes[10] = {0,1,2,3,4,5,6,7,8,9};
int k = 6;
int i, j;
int max, temp;
// Partial selection sort, move k max elements to front
for (i = 0; i < k; i++)
{
max = i;
// Find next max index
for (j = i+1; j < ELEMENTS; j++)
{
if (numbers[j] > numbers[max]) {
max = j;
}
}
// Swap numbers in input array
temp = numbers[i];
numbers[i] = numbers[max];
numbers[max] = temp;
// Swap indexes in tracking array
temp = indexes[i];
indexes[i] = indexes[max];
indexes[max] = temp;
}
for (i = 0; i < k; i++) {
printf("%d -> %d\n", indexes[i], numbers[i]);
}
}
And the output:
0 -> 9
4 -> 8
9 -> 7
7 -> 6
2 -> 5
1 -> 4
Here's the answer I have for you.
I would love some constructive criticism on it from anyone who can provide some.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int numbers[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *ptrNumbers[10];
int i=0;
for(; i < 10; i++){
ptrNumbers[i] = &numbers[i]; // assign the addresses
}
int topSix[6];
int topSixIndex=0;
for(; topSixIndex < 6; topSixIndex++){
int **best = NULL; // Pointer to the pointer to the value.
int checkIndex=0;
for(; checkIndex < 10; checkIndex++){
if(ptrNumbers[checkIndex] != NULL){
if(!best){
/* best is not yet defined */
best = &ptrNumbers[checkIndex];
// best now points to the pointer for numbers[checkIndex]
}else if(*ptrNumbers[checkIndex] > **best){
// this else if statement could be attached to the main if as
// an or condition, but I've separated it for readability.
best = &ptrNumbers[checkIndex];
// best now points to the pointer for numbers[checkIndex]
}
}
}
// assign the topSix position and flag the ptrNumbers
topSix[topSixIndex] = **best;
*best = NULL;
}
// now we'll print the numbers
for(topSixIndex = 0; topSixIndex < 6; topSixIndex++){
printf("%d\n", topSix[topSixIndex]);
}
return 0;
}
Essentially the program works like this: Given an array of ten numbers, a second array is constructed to house pointers to those 10 numbers. A third array is then constructed to house the values of the top 6 numbers. A for loop is then initialized to loop 6 times to find the highest unrecorded value. When the highest value is found by looping the pointer array, the value is assigned to the next index of the top six array. Once that value is added, the pointer array's index that points to the top six value is then assigned to NULL. This acts as a flag insuring that the value will not be added again. Finally, all numbers are printed out.
After running this code, the output I received was:
9
8
7
6
5
4
Edit: as a note, the ordering number's can be stored in a second array. You would simply need to track the checkIndex of the highest value and then assign it to a second array which contained the index values.
maybe you aren't looking for a code-only answer, but this will work:
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// return index of max element
int max_index( int* vec, int sz )
{
int idx, max, i;
if(!sz) return -1;
idx = 0;
max = vec[0];
for(i=1; i<sz; ++i)
{
if( vec[i] > max )
{
max = vec[i];
idx = i;
}
}
return idx;
}
// return indexes of N top elements
void top( int* vec, int sz, int* out_vec, int N )
{
int i, *tmp, idx;
tmp = (int*) malloc( sz*sizeof(int) );
memcpy( tmp, vec, sz*sizeof(int) );
for(i=0; i<N; ++i )
{
idx = max_index(tmp,sz);
out_vec[i]=idx;
tmp[idx] = INT_MIN;
}
free(tmp);
}
see it live here
Make an array of struct that contain data and index, then sort it and pick up first or last 6 elements to output.
Say that you are given an array numbers. Then create an array indexes with the same size as numbers in such a way that its values are equal to their indexes. Here is an illustration:
numbers = [ 1, 7, 3, 9, 2, 0 ]
indexes = [ 0, 1, 2, 3, 4, 5 ]
Sort numbers in descending order, performing the same operations on indexes. In the end, you should end up with something like this:
numbers = [ 9, 7, 3, 2, 1, 0 ]
indexes = [ 3, 1, 2, 4, 0, 5 ]
Finally, all you need to do is work with the first six elements of these arrays.
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int contains(int array[], int array_size, int value)
{
int i;
for (i = 0; i < array_size; i++)
{
if (array[i] == value)
{
return TRUE;
}
}
return FALSE;
}
int main()
{
int numbers[] = { 1, 7, 3, 9, 2, 0 };
int indexes[] = { 0, 1, 2, 3, 4, 5 };
int numbers_size = 6;
int largest[] = { -1, -1, -1, -1, -1, -1 };
int largest_index = 0;
int i;
for (i = 0; i < 6; i++)
{
int j;
int max_index = -1;
int max = -2147483648;
for (j = 0; j < numbers_size; j++)
{
if (numbers[j] >= max && contains(largest, numbers_size, j) == FALSE)
{
max_index = j;
max = numbers[max_index];
}
}
largest[largest_index++] = max_index;
}
for (i = 0; i < 6; ++i)
{
printf("%d->%d\n", largest[i], numbers[largest[i]]);
}
return 0;
}
You probably should use bubblesort (and keep a function holding all the original indexes) and then just make it show the 6 first number of both arrays (from the indexes array and from the array you sorted itself)

Array of arrays, with different sizes

I'm having an array, that has arrays in every cell. For example, the big array is called arr:
int a[3] = {3, 2, 1};
int b[2] = {2, 1};
int *arr[2] = {a, b}
Now the problem is, if I want to print the small arrs, inside the big array.
Here is my code:
#include <stdio.h>
void printArr(int arr [], int n)
{
for (int i = 0 ; i < n ; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
}
int main()
{
int a[5] = {1, 8, 4, 2, 0};
int b[3] = {1, 4, 2};
int *arr [2] = {a, b};
int n = 0;
for (int i = 0 ; i < 2 ; i++)
{
printArr(*(arr + i), n);
}
}
The output is supposed to be something like this:
1 8 4 2 0
1 4 2
But I can't get the size of each array, since sizeof(*(arr + i) gives me 4, which is the size of the pointer (the name of the array), and not all the array it self.
So what can I do?
Thanks!
The Problem:
The C language only provides a way of finding the size of types.
This gives the subtle differences between applying sizeof to:
1) An array of a type such as:
int a[3];
sizeof(a); // => 3 * sizeof(int)
2) A pointer to the type:
int *ptr;
sizeof(ptr); // => sizeof(int *)
or
int a[3] = {3, 2, 1};
int b[2] = {2, 1};
int *arr[2] = {a, b};
sizeof(arr[1]); // => sizeof(int *)
Some solutions:
Store the size
As jfly proposes store the size of the arrays.
Makes finding the size a constant time operation.
Append an end marker
Adding a end marker like '\0' as used for c-style strings.
You might use INT_MAX or INT_MIN in this case.
The printArr implementation would need to change to:
void printArr(int *arr)
{
int *it = arr;
while(arr != INT_MIN);
{
printf("%d ", *it);
}
printf("\n");
}
Disadvantages:
Finding the size of the array requires iterating over the full array.
Gives the risk of an actual value colliding with the end marker value.
Advantages:
The varying sized array can be passed as a single argument.
Using iterators
Store the pointer to the first and one past the last value.
void printArr(int *begin, int *end)
{
for (int *it = begin; it != end; it++)
{
printf("%d ", *it);
}
printf("\n");
}
int *end_arr[2] = {a + 3, b + 2};
for (int i = 0 ; i < 2 ; i++)
{
printArr(arr[i], end_arr[i]);
}
Can be extended to other data structures.
Since arr is an array of pointers, so you can't get the size of array from the pointer which points to an array, you need additional size info:
int size_arr[2] = {sizeof(a) / sizeof(int), sizeof(b) / sizeof(int)};
for (int i = 0 ; i < 2 ; i++)
{
printArr(arr[i], size_arr[i]);
}

Resources