reading and printing matrix from stdin - arrays

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;
}

Related

How can i run a command only one time inside of for loop?

How can i run a command only one time inside of for loop?
I couldn't find how to do it so i wrote code like that. But the problem on this code you can see when the program goes to else command it doesn't work.
I just wanted to see odd and even numbers with using for loop but I don't want to get result like;
Even numbers :12
Even numbers :28
Even numbers :46
I just want to see only one time print Even numbers and then print numbers like;
Even numbers:
12
28
46
etc.
I hope I could explain clearly.
My alternative but wrong code is:
#include <stdio.h>
int main()
{
int num [] = {12, 14, 16, 33, 65, 98, 45, 25, 87, 18, 20};
printf("even numbers:");
printf("\t\t\t\t Odd numbers:");
for (int i = 0; i < 11; i++) {
if (num[i] % 2 == 0) {
printf("\n%d", num[i]);
}
else {
printf("\t\t\n%d");
}
}
return 0;
}
You want two loops:
#include <stdio.h>
int main(void)
{
int num[] = {12,14,16,33,65,98,45,25,87,18,20};
size_t n = sizeof num / sizeof *num;
printf ("Even numbers:\t\t\t\tOdd numbers:\n");
for (size_t i = 0; i < n; i++) {
if (num[i] % 2 == 0) {
printf ("%d ", num[i]);
}
}
printf("\r\t\t\t\t\t");
for (size_t i = 0; i < n; i++) {
if (num[i] % 2 != 0) {
printf ("%d ", num[i]);
}
}
printf("\n");
return 0;
}
Output:
Even numbers: Odd numbers:
12 14 16 98 18 20 33 65 45 25 87
Notice the \r to go to the beginning of the line
Here a different format:
#include <stdio.h>
int main(void) {
unsigned num []={12,14,16,33,65,98,45,25,87,18,20};
printf("even numbers"
"\todd numbers\n");
const char *prefix[] = {"", "\t\t"};
for(unsigned i = 0; i < sizeof(num) / sizeof(*num); i++) {
printf("%s%u\n", prefix[num[i] % 2], num[i]);
}
}
and the output is:
even numbers odd numbers
12
14
16
33
65
98
45
25
87
18
20
Based on the assumption that the least changes to your shown code, with explanation, are most helpful, here is my explained solution:
#include <stdio.h>
int main()
{
int num [] = {12, 14, 16, 33, 65, 98, 45, 25, 87, 18, 20};
printf("even numbers:");
printf("\tOdd numbers:\n"); // newline after the output, one tab, no blanks
for (int i = 0; i < 11; i++) {
if (num[i] % 2 == 0) {
printf("%d\n", num[i]); // newline after output
}
else {
printf("\t\t%d\n", num[i]); // tabs, then output, then newline
}
}
return 0;
}
this gets you an output of:
even numbers: Odd numbers:
12
14
16
33
65
98
45
25
87
18
20
Your problem was only caused by missapplied whitespaces.
(Apart from accidentally dropping the parameter for the odd output....)
Doing newlines after output is a good practice, but that is a matter of taste.
Important is to not output tabulators followed by a newline; because the newline spoils the effect of the tabulators.
Here is the version with newlines before output (for really minimal changes), but I recommend against it.
#include <stdio.h>
int main()
{
int num [] = {12, 14, 16, 33, 65, 98, 45, 25, 87, 18, 20};
printf("even numbers:");
printf("\t\t\t\t Odd numbers:");
for (int i = 0; i < 11; i++) {
if (num[i] % 2 == 0) {
printf("\n%d", num[i]);
}
else {
printf("\n\t\t\t\t\t %d", num[i]); // newline, tabs, blank, output
}
}
return 0;
}
This gets you an output of:
even numbers: Odd numbers:
12
14
16
33
65
98
45
25
87
18
20
Wider, because I left the multiple tabulators and the unneeded blank in.
EDIT: OP has been edited to show desired output. I had add '\n' to two lines of this to effect the change.
"Factoring out" common processing into a function is always a good idea.
#include <stdio.h>
void show( int num[], int nItems, char *title, int rem ) {
printf( "%s\n", title );
for( int i = 0; i < nItems; i++ )
if( num[i]%2 == rem )
printf( "%d\n", num[ i ] );
printf( "\n" );
}
int main () {
int num [] = { 12, 14, 16, 33, 65, 98, 45, 25, 87, 18, 20 };
show( num, sizeof num/sizeof num[0], "even numbers: ", 0 );
show( num, sizeof num/sizeof num[0], "odd numbers: ", 1 );
return 0;
}
Output:
even numbers:
12
14
16
98
18
20
odd numbers:
33
65
45
25
87

Why does the program display warning passing argument 1 of 'circularswap' makes pointer from integer without a cast?

I am working on this problem:
Given an array p[5], write a function to shift it circularly left by two positions. Thus, if p[0] = 15, p[1]= 30, p[2] = 28, p[3]= 19 and p[4] = 61 then after the shift p[0] = 28, p[1] = 19, p[2] = 61, p[3] = 15 and p[4] = 30. Call this function for a (4 x 5 ) matrix and get its rows left shifted.
Here's the code I tried:
#include <stdio.h>
#include <stdio.h>
void circularswap(int arr[][5],int n,int m){ int arr1[n][m],i,j;
for (i=0;i<n;i++){
for (j=0;j<m;j++){
arr1[i][j]=*(*(arr+i)+j);
}
}
for (i=0;i<m;i++){
*(*(arr+i)+0)=arr1[i][2];
*(*(arr+i)+1)=arr1[i][3];
*(*(arr+i)+2)=arr1[i][4];
*(*(arr+i)+3)=arr1[i][0];
*(*(arr+i)+4)=arr1[i][1];
}
for (i=0;i<4;i++){
for (j=0;j<5;j++){
printf ("%d",arr[i][j]);
}
printf ("\n");
}
}
int main(){ int i,j;
int arr[4][5]={(15,30,28,19,61),(15,30,28,19,61),(15,30,28,19,61),(15,30,28,19,61)};
circularswap((arr,4,5));
return 0;
}
Unfortunately, this shows up warnings. Can someone please tell why the warnings pop up and how to remove them?
You have to many parentheses when calling the function.
The expression (arr,4,5) is using the comma operator and will evaluate all the sub-expressions in the list, but return only the 5.
I.e. your call is really the same as circularswap(5), which is incorrect in multiple ways.
To solve your problem drop the inner parentheses:
circularswap(arr,4,5);
You have a similar problem when initializing your array: You use parentheses () instead of curly braces {}.
So the array definition is really equal to:
int arr[4][5]={ { 61 }, { 61 }, { 61 }, { 61 } };
[Note how I use curly-braces in the example above]
On another note, for any pointer p and index i, the expression *(p + i) is exactly equal to p[i]. The latter is easier to read and understand, and also less to write.
It matters especially when using arrays of arrays like you do, where e.g. *(*(arr+i)+0) could be replaced with arr[i][0].
You declared a two-dimensional array
int arr[4][5]
So elements of the array in turn are one-dimensional arrays. You may initialize a one-dimensional array by an initializer list or a string literal if the array element type is char.
However you are using an expression of a scalar type with the comma operator like
(15,30,28,19,61)
The value of the expression is the value of the last operand that is 61. In fact your initialization looks like
int arr[4][5]=
{
[0] = 61,
[1] = 61,
[2] = 61,
[3] = 61
};
that under the hood looks like for example
a[0] = 61;
That is you are trying to assign the value 61 to an array of the type int[5].
You need to enclose the lists in braces like
int arr[4][5] =
{
{ 15, 30, 28, 19, 61 },
{ 15, 30, 28, 19, 61 },
{ 15, 30, 28, 19, 61 },
{ 15, 30, 28, 19, 61 }
};
Also in the assignment there is written that you need to write a function that shifts element of a one-dimensional array to the left. But in your program there is no such a function.
Moreover your function circularswap has bugs. For example in this loop
for (i=0;i<m;i++){
*(*(arr+i)+0)=arr1[i][2];
*(*(arr+i)+1)=arr1[i][3];
*(*(arr+i)+2)=arr1[i][4];
*(*(arr+i)+3)=arr1[i][0];
*(*(arr+i)+4)=arr1[i][1];
}
there is used the variable m instead of n and a magic numbers like 4. So using the variable m instead of the variable n and using the magic number 4 instead of using the variable m in an inner loop makes your loop senseless.
Also though in the assignment there is written to circularly shift elements of rows by 2 positions you should always write a more general function that allows the user to specify the number of shifts.
Thus you need to write a function that circularly shifts elements to the left and call the function for each row specifying the number of shifts equal to 2.
The program can look the following way as it is shown below.
#include <stdio.h>
#include <string.h>
void circular_shift_left( int a[], size_t n, size_t pos )
{
if ( n != 0 )
{
pos = pos % n;
if ( pos != 0 )
{
for ( size_t i = 0; i < pos; i++ )
{
int tmp = a[0];
memmove( a, a + 1, ( n - 1 ) * sizeof( *a ) );
a[n-1] = tmp;
}
}
}
}
int main(void)
{
enum { M = 4, N = 5 };
int a[M][N] =
{
{ 15, 30, 28, 19, 61 },
{ 15, 30, 28, 19, 61 },
{ 15, 30, 28, 19, 61 },
{ 15, 30, 28, 19, 61 }
};
for ( size_t i = 0; i < M; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
printf( "%d ", a[i][j] );
}
putchar( '\n' );
}
putchar( '\n' );
for ( size_t i = 0; i < M; i++ )
{
circular_shift_left( a[i], N, 2 );
}
for ( size_t i = 0; i < M; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
printf( "%d ", a[i][j] );
}
putchar( '\n' );
}
putchar( '\n' );
return 0;
}
The program output is
15 30 28 19 61
15 30 28 19 61
15 30 28 19 61
15 30 28 19 61
28 19 61 15 30
28 19 61 15 30
28 19 61 15 30
28 19 61 15 30

How to change a division hash function according to bucket size

I'm working on a school project, in which I have to implement rehashing. I don't know which method would be the best for this case, but I was thinking about hashing the actual number like this:
int hash (struct Table *temp, int key)
{
int test = 3; // here would be the buckets size +1 but the function below cannot return it
return key % test;
}
The init function:
void init (struct Table *temp, int buckets)
{
if (buckets == 0) // make sure I allocate something
buckets = 2;
temp->entries = 0;
temp->size = 1;
while (temp->size < buckets) // ensure buckets is a power of 2
temp->size *= 2;
printf("post temp->size: %d\n", temp->size);
temp->buckets=(struct Node **) calloc(temp->size, sizeof(struct Node *));
}
This is how I insert to the table and rebuild the table if neccessary:
struct Node *insert (struct Table *temp, int key)
{
struct Node *temp2 = search(temp, cislo);
if (temp2 != NULL) // if temp2 doesnt exists
return temp2;
// I extend the table if neccessary
while (temp->entries >= 0.5 * temp->size)
rebuildTable(temp);
// add the new entry
int h = hash(temp, key);
temp2=(struct Node *) malloc(sizeof(struct Node));
temp2->key=key;
temp2->next=temp->bucket[h];
temp->bucket[h] = temp2;
temp->entries++;
return NULL;
}
void rebuildTable (struct Table *temp)
{
struct Node **oldBucket, *oldHash, *temp2;
int oldSize;
int h, i;
oldBucket=temp->bucket;
oldSize=temp->size;
/* create a new table and rehash old buckets */
init (temp, oldSize * 2);
for (i=0; i < oldSize; i++)
{
oldHash=oldBucket[i];
while(oldHash)
{
temp2=oldHash;
oldHash=oldHash->next;
h=hash(temp, temp2->key);
temp2->next=temp->bucket[h];
temp->bucket[h]=temp2;
temp->entries++;
}
}
free(oldBucket); //
}
The main problem is that the "test" variable in the hash function can only be bigger by one than buckets in the init function, otherwise the program fails, SEGMENTATION FAULT. I have to change it somehow so it could dynamically work based on the size of the buckets. For this input:
int arr[] = {0, 7, 14, 21, 28, 35, 42, 49, 56, 63, 1, 8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85};
init(temp, 0);
for (int i = 0; i < sizeof(arr)/4; i++)
insert(temp, arr[i]);
showTable(temp);
I get this output:
post temp->size: 2
post temp->size: 4
post temp->size: 8
post temp->size: 16
post temp->size: 32
post temp->size: 64
Numbers in the 0. bucket: // the number mod 3 == 0
78 57 42 0 21 63 15 36
Numbers in the 1. bucket:
85 64 43 49 28 7 1 22
Numbers in the 2. bucket:
71 50 35 14 56 8 29

C Program Arrays comparison

We have two arrays A and B, each of 10 integers. Write a function that tests if every element of array A is equal to its corresponding element in array B. In other words, the function must check if A[0] is equal to B[0], A[1] is equal to B[1], and so forth. The function is to return true if all elements are equal and false if at least one element is not equal.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
/* run this program using the console pauser or add
your own getch, system("pause") or input loop */
bool array(int ptr1[], int ptr2[]);
int main(int argc, char *argv[]) {
int array1[] = {11, 33, 34, 25, 16, 2, 24, 57, 86, 66};
int array2[] = {11, 33, 34, 25, 16, 2, 24, 57, 86, 66};
int i;
printf("Array A\t\tArray B\n");
for(i = 0; i < 10; i++)
printf("%d\t\t%d\n", array1[i], array2[i]);
printf("\nResult of comparision: \n");
bool result = array (array1, array2);
if(result == 1)
printf("false\n");
else
printf("false\n");
getch();
return 0;
}
The errors that I get are:
main.c(.text+0xfa): undefined 'array'
[Error] Id returned 1 exit status
recipe for target '"Problem' failed
The problem is you have declared array:
bool array(int ptr1[], int ptr2[]);
but not defined it. When you link, the linker looks for the definition of function array and cannot find one, prompting the error:
main.c(.text+0xfa): undefined 'array'
[Error] Id returned 1 exit status
recipe for target '"Problem' failed
To define the function at same point your declare it, you must add the body of the function. In that case, there is no need for a forward declaration. It has been declared before its use in main, e.g.
int arraycmp (int ptr1[], int ptr2[], size_t size)
{
return memcmp (ptr1, ptr2, size);
}
(note: regardless of whether you use memcmp or simply loop over each element and perform a single comparison for each, you must pass the number of elements as a parameter)
If on the other hand, you do not define the function until after main(), then the forward declaration is required so that the function is usable in main().
Putting it altogether, you can do something similar to the following:
#include <stdio.h>
#include <string.h>
/* run this program using the console pauser or add
your own getch, system("pause") or input loop */
int arraycmp (int ptr1[], int ptr2[], size_t size)
{
return memcmp (ptr1, ptr2, size);
}
int main (void) {
int array1[] = {11, 33, 34, 25, 16, 2, 24, 57, 86, 66},
array2[] = {11, 33, 34, 25, 16, 2, 24, 57, 86, 66},
i;
printf("Array A\t\tArray B\n");
for(i = 0; i < 10; i++)
printf(" %d\t\t %d\n", array1[i], array2[i]);
printf("\nResult of comparision: %s\n",
arraycmp (array1, array2, sizeof array1) ? "false" : "true");
#if defined (_WIN32) || defined (_WIN64)
getchar();
#endif
return 0;
}
(note: if there is any chance your arrays differ in number of elements, you should check before calling arraycmp and handle the error as you wish. Either return exiting that point or pass the size of the smaller and only compare that initial number of elements)
Example Use/Output
$ ./bin/arrcmp
Array A Array B
11 11
33 33
34 34
25 25
16 16
2 2
24 24
57 57
86 86
66 66
Result of comparision: true
Changing 57 to 56 in array2,
$ ./bin/arrcmp
Array A Array B
11 11
33 33
34 34
25 25
16 16
2 2
24 24
57 56
86 86
66 66
Result of comparision: false
Look things over and let me know if you have further questions.

How to rearrange a two dimensional array

I want to assign the values in one array to another, but in a different
order. For example the original array would be:
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
And the desired array is:
8 11 14 3 6 16 19
9 12 1 4 7 17 20
10 13 2 5 15 18 21
How would I do this? In the code below I moved a selected row to the center, then assigned each array individually. I can't figure out a better way.
int main()
{
int decide, i, j, k;
int save[3][7];
int shuffle[3][7];
int arr[3][7] = {
{1, 2, 3, 4, 5, 6, 7},
{8, 9, 10, 11, 12, 13, 14},
{15, 16, 17, 18, 19, 20, 21}
};
printf("Select a number between 1 and 21\n\n0-GroupA (1 - 7))\n1-GroupB ( 8 - 14)\n2-GroupC (15 - 21)\n\n");
for(k = 0 ; k < 1 ; ++k)
{
printf("Select which group the number falls into:");
scanf("%d", &decide);
for(j = 0 ; j < 7 ; ++j)
{/*moves selected row to middle row of array*/
save[0][j] = arr[1][j];
arr[1][j] = arr[decide][j];
arr[decide][j] = save[0][j];
}
/*this is a horrible method*/
shuffle[0][0] = arr[0][0];
shuffle[1][0] = arr[0][1];
shuffle[2][0] = arr[0][2];
shuffle[0][1] = arr[0][3];
shuffle[1][1] = arr[0][4];
shuffle[2][1] = arr[0][5];
shuffle[0][2] = arr[0][6];
shuffle[1][2] = arr[1][0];
shuffle[2][2] = arr[1][1];
shuffle[0][3] = arr[1][2];
shuffle[1][3] = arr[1][3];
shuffle[2][3] = arr[1][4];
shuffle[0][4] = arr[1][5];
shuffle[1][4] = arr[1][6];
shuffle[2][4] = arr[2][0];
shuffle[0][5] = arr[2][1];
shuffle[1][5] = arr[2][2];
shuffle[2][5] = arr[2][3];
shuffle[0][6] = arr[2][4];
shuffle[1][6] = arr[2][5];
shuffle[2][6] = arr[2][6];
}
like this ?
#include <stdio.h>
#define ROWS 3
#define COLS 7
int main(void){
int arr[ROWS][COLS] = {
{1, 2, 3, 4, 5, 6, 7},
{8, 9, 10, 11, 12, 13, 14},
{15, 16, 17, 18, 19, 20, 21}
};
int result[ROWS][COLS];
int order[ROWS] = {1, 0, 2};
int n = sizeof(arr)/sizeof(**arr);//number of elements
int r = 0, c = 0, i = 0, j = 0;
while(n--){
result[r++][c] = arr[order[i]][j++];
if(r == ROWS){
r = 0;
c += 1;
}
if(j == COLS){
j = 0;
i += 1;
}
}
//check print
for(r = 0; r < ROWS; ++r){
for(c = 0; c < COLS; ++c)
printf("%-2d ", result[r][c]);
puts("");
}
}
The transposition part can be done like this:
#include <stdio.h>
typedef struct Sequence2D
{
int idx_slow;
int idx_fast;
int max_slow;
int max_fast;
} Sequence2D;
static inline void next2D(Sequence2D *seq)
{
if (++seq->idx_fast == seq->max_fast)
{
seq->idx_fast = 0;
if (++seq->idx_slow == seq->max_slow)
seq->idx_slow = 0;
}
}
static inline void dump2D(const char *tag, int rows, int cols, int data[rows][cols])
{
printf("%s:\n", tag);
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
printf("%3d", data[r][c]);
putchar('\n');
}
}
enum { ROWS = 3, COLS = 7 };
int main(void)
{
int src[ROWS][COLS] =
{
{ 1, 2, 3, 4, 5, 6, 7 },
{ 8, 9, 10, 11, 12, 13, 14 },
{ 15, 16, 17, 18, 19, 20, 21 },
};
int dst[ROWS][COLS];
Sequence2D dst2D = { 0, 0, COLS, ROWS };
Sequence2D src2D = { 0, 0, ROWS, COLS };
dump2D("Source", ROWS, COLS, src);
for (int i = 0; i < ROWS * COLS; i++)
{
dst[dst2D.idx_fast][dst2D.idx_slow] = src[src2D.idx_slow][src2D.idx_fast];
printf("dst[%d][%d] = src[%d][%d] = %d\n",
dst2D.idx_fast, dst2D.idx_slow,
src2D.idx_slow, src2D.idx_fast,
dst[dst2D.idx_fast][dst2D.idx_slow]);
next2D(&dst2D);
next2D(&src2D);
}
dump2D("Target", ROWS, COLS, dst);
return 0;
}
The Sequence2D structure plus the next2D() function cycle through array indexes, changing the fast index on each call of next2D() and the slow index when necessary. This saves you writing out the sequence of 21 assignments, and immediately scales to other shapes without requiring much extra work on your part. Indeed, it would not take much to handle all the sizes as run-time inputs instead of compile-time constants.
The output of this code is:
Source:
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
dst[0][0] = src[0][0] = 1
dst[1][0] = src[0][1] = 2
dst[2][0] = src[0][2] = 3
dst[0][1] = src[0][3] = 4
dst[1][1] = src[0][4] = 5
dst[2][1] = src[0][5] = 6
dst[0][2] = src[0][6] = 7
dst[1][2] = src[1][0] = 8
dst[2][2] = src[1][1] = 9
dst[0][3] = src[1][2] = 10
dst[1][3] = src[1][3] = 11
dst[2][3] = src[1][4] = 12
dst[0][4] = src[1][5] = 13
dst[1][4] = src[1][6] = 14
dst[2][4] = src[2][0] = 15
dst[0][5] = src[2][1] = 16
dst[1][5] = src[2][2] = 17
dst[2][5] = src[2][3] = 18
dst[0][6] = src[2][4] = 19
dst[1][6] = src[2][5] = 20
dst[2][6] = src[2][6] = 21
Target:
1 4 7 10 13 16 19
2 5 8 11 14 17 20
3 6 9 12 15 18 21
If you rearrange the initial matrix (src) according to whatever arcane rules you're using before you copy the 'transpose' of src into the result (dst), then you should be able to get the result you desire.
As noted, the code can be generalized rather easily using C99 and variable-length arrays:
#include <assert.h>
#include <stdio.h>
typedef struct Sequence2D
{
int idx_slow;
int idx_fast;
int max_slow;
int max_fast;
} Sequence2D;
static inline void next2D(Sequence2D *seq)
{
if (++seq->idx_fast == seq->max_fast)
{
seq->idx_fast = 0;
if (++seq->idx_slow == seq->max_slow)
seq->idx_slow = 0;
}
}
static inline void dump2D(const char *tag, int rows, int cols, int data[rows][cols])
{
printf("%s:\n", tag);
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
printf("%3d", data[r][c]);
putchar('\n');
}
}
static void transpose(int rows, int cols)
{
assert(rows * cols < 1000000);
int src[rows][cols];
int dst[rows][cols];
Sequence2D dst2D = { 0, 0, cols, rows };
Sequence2D src2D = { 0, 0, rows, cols };
int cells = rows * cols;
for (int i = 0; i < cells; i++)
{
src[src2D.idx_slow][src2D.idx_fast] = i;
next2D(&src2D);
}
/* src2D is back to its initial state! */
dump2D("Source", rows, cols, src);
for (int i = 0; i < cells; i++)
{
dst[dst2D.idx_fast][dst2D.idx_slow] = src[src2D.idx_slow][src2D.idx_fast];
printf("dst[%d][%d] = src[%d][%d] = %d\n",
dst2D.idx_fast, dst2D.idx_slow,
src2D.idx_slow, src2D.idx_fast,
dst[dst2D.idx_fast][dst2D.idx_slow]);
next2D(&dst2D);
next2D(&src2D);
}
dump2D("Target", rows, cols, dst);
}
int main(void)
{
transpose(3, 7);
transpose(9, 4);
return 0;
}
The first section of the output is the same as before; the 9x4 part looks like:
Source:
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
dst[0][0] = src[0][0] = 0
dst[1][0] = src[0][1] = 1
dst[2][0] = src[0][2] = 2
dst[3][0] = src[0][3] = 3
dst[4][0] = src[1][0] = 4
dst[5][0] = src[1][1] = 5
dst[6][0] = src[1][2] = 6
dst[7][0] = src[1][3] = 7
dst[8][0] = src[2][0] = 8
dst[0][1] = src[2][1] = 9
dst[1][1] = src[2][2] = 10
dst[2][1] = src[2][3] = 11
dst[3][1] = src[3][0] = 12
dst[4][1] = src[3][1] = 13
dst[5][1] = src[3][2] = 14
dst[6][1] = src[3][3] = 15
dst[7][1] = src[4][0] = 16
dst[8][1] = src[4][1] = 17
dst[0][2] = src[4][2] = 18
dst[1][2] = src[4][3] = 19
dst[2][2] = src[5][0] = 20
dst[3][2] = src[5][1] = 21
dst[4][2] = src[5][2] = 22
dst[5][2] = src[5][3] = 23
dst[6][2] = src[6][0] = 24
dst[7][2] = src[6][1] = 25
dst[8][2] = src[6][2] = 26
dst[0][3] = src[6][3] = 27
dst[1][3] = src[7][0] = 28
dst[2][3] = src[7][1] = 29
dst[3][3] = src[7][2] = 30
dst[4][3] = src[7][3] = 31
dst[5][3] = src[8][0] = 32
dst[6][3] = src[8][1] = 33
dst[7][3] = src[8][2] = 34
dst[8][3] = src[8][3] = 35
Target:
0 9 18 27
1 10 19 28
2 11 20 29
3 12 21 30
4 13 22 31
5 14 23 32
6 15 24 33
7 16 25 34
8 17 26 35
You can't transpose a matrix in place. That is to say, it is not possible to write a function which will take a matrix and modify it so that it is its transpose, without creating a temporary matrix of equal size. At least without some very fancy programming.
Now your task isn't exactly the transpose, but it seems to be very similar. So I wouldn't expect there to be a nice, in place solution. You must simply create a temporary, apply the mapping from input to temporary, and write the values back.
What might help is this.
/* swap two rows of a matrix */
void swaprows(int *mtx, int width, int height, int rowa, int rowb)
{
int i;
for(i=0;i<width;i++)
{
int temp = mtx[rowa*width+i];
mtx[rowa*width+i] = mtx[rowb*width+i];
mtx[rowa*width+i] = temp;
}
}
/* transpose a matrix */
int transpose(int *mtx, int width, int height)
{
int *tmtx = malloc(width*height*sizeof(int));
if(!tmtx)
return -1;
for(y=0;y<width;y++)
for(x=0;x<height;x++)
tmtx[y*height+x] = mtx[x*width+y];
mempy(mtx, tmtx, width * height * sizeof(int));
free(tmtx);
}
/* your logic */
int arr[3][7] = {
{1, 2, 3, 4, 5, 6, 7},
{8, 9, 10, 11, 12, 13, 14},
{15, 16, 17, 18, 19, 20, 21}
};
swaprows((int *) arr, 7, 3, 0, 1);
transpose(int *) arr, 7, 3);
This seems to be what you are trying to do.

Resources