Related
I am currently building a matrix calculator (required to make with pointers) as part of my introductory C assignment, and I am currently trying to make an option to Transpose a 3x3 matrix (swapping the rows of a matrix with it's columns).
However, when I apply the function on the matrix nothing happens to it.
Here is the code for the transposition function.
void transposeMatrix(int matrix[3][3]) {
int row;
int col;
int temp = 0;
for (row = 0; row<3; row++) {
for (col = 0; col < 3; col++) {
temp = *(*(matrix+row)+col);
*(*(matrix+row)+col) = *(*(matrix+col)+row);
*(*(matrix+col)+row) = temp;
}
}
}
It is just a standard swapping algorithm with a temp variable.
Here is the code for the printing function
void printMatrix(char *desc,int matrix[3][3]) {
int row;
int column;
printf("matriks %s:\n",desc);
for (row = 0; row < 3; row++) {
for (column = 0; column < 3; column++) {
printf(" %d", matrix[row][column]);
}
printf("\n");
}
}
And here is how I call the function:
int sampleM1[3][3] = {{2,2,4}, {1,1,1}, {1,1,1}};
printMatrix("before transposition", sampleM1);
transposeMatrix(sampleM1);
printMatrix("after transposition" , sampleM1);
The output of the entire operation is that sampleM1 does not change at all. Is there any way to fix this problem?
As #TomKarzes noted above you visit the same index of the matrix twice, and avoid that by starting the inner loop at row + 1. You mentioned that you needed to use pointer syntax, which is fine of course, but swap() now localizes the ugliness (to arguments) for you to change as you see fit.
#include <stdint.h>
#include <stdio.h>
#define N 3
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void printMatrix(int matrix[N][N]) {
for (uint8_t row = 0; row < N; row++)
for (uint8_t col = 0; col < N; col++)
printf("%d%s", matrix[row][col], col + 1 < N ? ", " : "\n");
}
void transposeMatrix(int matrix[N][N]) {
for (uint8_t row = 0; row < N; row++)
for (uint8_t col = row + 1; col < N; col++)
swap(&matrix[row][col], &matrix[col][row]);
}
int main() {
int matrix[N][N] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
printMatrix(matrix);
transposeMatrix(matrix);
printMatrix(matrix);
}
Here is the output of the above:
1, 2, 3
4, 5, 6
7, 8, 9
1, 4, 7
2, 5, 8
3, 6, 9
Write a function in c that takes a single 2d nxn matrix. If the matrix is a lower triangular matrix, the program should output 1 and output 0 if it is not a lower triangular matrix.
Here is my code.
// function code
#include <stdio.h>
#include <stdlib.h>
#define NUMS 5
int isLowerTriangularMatrix(int array[NUMS][NUMS]) {
for (int row = 0; row < NUMS; row++) {
for (int col = 0; col < NUMS; col++) {
if (row > col && array[row][col] == 0) {
return 1;
}
else {
return 0;
}
}
}
}
// test code
int main(void) {
int matrix[5][5] = {{1,2,3,4,5},
{7,8,9,2,3},
{7,8,9,2,3},
{7,8,9,2,3},
{7,8,9,2,3}};
int result = isLowerTriangularMatrix(matrix, 5);
printf("%d", result);
return 0;
}
My question is that how to modify my code?
Here is the compiler warnings
q23.c:16:1: warning: control reaches end of non-void function [-Wreturn-type]
16 | }
The warning is spurious. Or rather, it should have issued a different warning, one that indicated you have code that will never be executed.
That is to say that while your code doesn't suffer from the identified problem, it is nonetheless incorrect. It always returns zero. The first pass through the loops, you check if row > col. Since it's false, you execute the else clause and return zero.
You shouldn't be returning 0 in that case. But you shouldn't be returning 1 either. You can only return 1 after you've checked the entire matrix, so the return 1 should be outside the loops.
This fixes these problems:
int isLowerTriangularMatrix( int array[ NUMS ][ NUMS ] ) {
for ( int row = 0; row < NUMS; ++row ) {
for ( int col = 0; col < NUMS; ++col ) {
if ( col > row && array[ row ][ col ] != 0 ) {
return 0;
}
}
}
return 1;
}
There's one last issue to address, and it's the needless "visiting" of cells in the lower triangle. It's trivial to skip these.
int isLowerTriangularMatrix( int array[ NUMS ][ NUMS ] ) {
for ( int row = 0; row < NUMS; ++row ) {
for ( int col = row+1; col < NUMS; ++col ) {
if ( array[ row ][ col ] != 0 ) {
return 0;
}
}
}
return 1;
}
As I mentioned in my top comments ...
For your original question as to how to initialize a matrix:
With an initializer:
int mtx[3][3] = {
{ 3, 9, 7 },
{ 0, 5, 6 },
{ 0, 0, 1 }
};
Or, with assignment statements:
int mtx[3][3];
mtx[0][0] = 3;
mtx[0][1] = 9;
mtx[0][2] = 7;
mtx[1][0] = 0;
mtx[1][1] = 5;
mtx[1][2] = 6;
mtx[2][0] = 0;
mtx[2][1] = 0;
mtx[2][2] = 1;
#Craig Estey Yes, it is a method, but it also means the n not working very well on my code. –
Cedric xu
You do not have a true 2D int array. You have a 1D array of int * to int arrays. Do this instead:
#define NUMS 5
int mtx[NUMS][NUMS];
You can define the function as:
int isLowerTriangularMatrix(int arr[NUMS][NUMS])
Or, if you want the function to handle the size dynamically:
int isLowerTriangularMatrix(int n,int arr[n][n])
The first one will be a bit faster and the second a bit more flexible [albeit a bit slower].
Edit: Your function is being [correctly] flagged as reaching the end of the function and not having a return statement. It can't [seem to] determine that the code will always do one of the return statements inside the loops. Note that both gcc and clang flag it the same way.
I'm not sure your function will return a valid result because the if does a return on both the if and the else. So, it will never examine all the elements [that it needs to].
Usually, the inner return is just on the if part. Then, at the function bottom do: (e.g.) return 1;
Here's a refactored version:
// function code
#include <stdio.h>
#include <stdlib.h>
#define NUMS 5
int
isLowerTriangularMatrix(int array[NUMS][NUMS])
{
// we only need to probe the upper right part of the matrix
// if we see non-zero, it's _not_ triangular
for (int row = 0; row < NUMS; row++) {
for (int col = row + 1; col < NUMS; col++) {
//printf("arr[%d][%d] = %d\n",row,col,array[row][col]);
if (array[row][col] != 0)
return 0;
}
}
return 1;
}
// test code
int
main(void)
{
// this is _not_ a triangular matrix
int matrix[5][5] = {
{1, 2, 3, 4, 5},
{7, 8, 9, 2, 3},
{7, 8, 9, 2, 3},
{7, 8, 9, 2, 3},
{7, 8, 9, 2, 3}
};
int result = isLowerTriangularMatrix(matrix);
printf("%d\n", result);
// this _is_ a triangular matrix
int m2[5][5] = {
{ 1, 0, 0, 0, 0 },
{ 3, 1, 0, 0, 0 },
{ 4, 5, 1, 0, 0 },
{ 7, 6, 2, 1, 0 },
{ 8, 9, 7, 3, 1 }
};
result = isLowerTriangularMatrix(m2);
printf("%d\n", result);
return 0;
}
Here is the program output (with the debug printf):
arr[0][1] = 2
0
arr[0][1] = 0
arr[0][2] = 0
arr[0][3] = 0
arr[0][4] = 0
arr[1][2] = 0
arr[1][3] = 0
arr[1][4] = 0
arr[2][3] = 0
arr[2][4] = 0
arr[3][4] = 0
1
how can i shift each column of a matrix to the left by the row number ?
for example
0, 1, 2, 3
4, 5, 6, 7
8, 9,10,11
12,13,14,15
this is a 4*4 matrix, the index of the first row is 0, therefore the columns will not move,
the second row's index is 1, therefore each column will move 1 spot to the left (cyclically).
the output for the given matrix is
example
my function code is:
void ShiftRows(int message[M][M])
{
int temp = 0;
for (int i = 1; i < M ; i++)
{
for (int j = 0; j < M; j++)
{
temp = message[i][(j-i)%M];
message[i][(j-i)%M] = message[i][j];
message[i][j] = temp;
}
temp = 0;
}
}
You only swap 2 values. That does not work for cyclically shift a whole row.
void ShiftRows(int message[M][M])
{
for (int i = 1; i < M ; i++)
{
int temp[M];
// First shift using a copy
for (int j = 0; j < M; j++)
{
temp[j] = message[i][(j+i)%M];
}
// After whole row is shifted, copy back
for (int j = 0; j < M; j++)
{
message[i][j] = temp[j];
}
}
}
I want to find the neighboring element that surrounds p. the program below doesn't print of the neighbors
I know we can use brute-force approach, like this:
array[i-1][i]
array[i-1][i-1]
array[i][i-1]
array[i+1][i]
and so on...
But, I worry that it would get tedious to check every possible places of that element p. I am trying to figure out an elegant way to do this.
#include <stdio.h>
#include <stdlib.h>
void draw_board();
int row_number, column_number;
char mark_board(char mark, int row_num, int column_num);
char find_neighborhood(char board[6][6], int i, int j);
char board[6][6] = {
{ '0','0','0','0','0','0' },
{ '0','1','2','3','0','0' },
{ '0','4','P','5','0','0' },
{ '0','6','7','8','0','0' },
{ '0','0','0','0','0','0' },
{ '0','0','0','0','0','0' }
};
int main() {
draw_board();
find_neighborhood(board[6][6], 3, 3); // trying to find neighbor of char p
return 0;
}
void draw_board() {
printf(" 1 2 3 4 5 6\n");
printf(" -----------\n");
for (int i = 0; i < 6; i++) { // rows
printf("%i| ", i + 1);// row number to be printed
for (int j = 0; j < 6; j++) { // columns
printf("%c ", board[i][j]);
}
printf("\n");
}
}
char find_neighborhood(char board[6][6], int row_num, int col_num) {
int rows = sizeof(board); // row limit
int columns = sizeof(board[0]) - 1; // column limit
for (int j = row_num - 1; j <= row_num + 1; j++) {
for (int i = col_num - 1; i <= col_num + 1; i++) {
if (i >= 0 && j >= 0 && i < columns && j < rows && !(j == row_num && i == col_num)) {
printf("The neighbor of p is: %c\n", board[j][i]);
}
}
}
}
In addition to the good points made by #chqlie, you have other areas that pose significant "anti-patters" or just plain "code-smells". The most vexing is your mixing of 1-based rows and columns with 0-based array indexing. In C, all indexing is 0-based. When you write functions manipulating arrays, all indexing should be 0-based. Not only does this make your code easier to follow and maintain, it removes the risk of an off-by-one error associated with mixing 1-based and 0-based indexing.
If you must take 1-based coordinates from the user, then map 1-based indexing to 0-based indexing before you call your array manipulation function. If you don't do it at the point of input, then make it clear to anyone maintaining your code that an indexing changes is occurring. A simple commented function will do, e.g.
/* convert 1-based rows/cols to 0-based indexes */
int toindex (int rc)
{
return rc ? rc - 1 : rc;
}
and call:
/* DANGER mixing 1-based & 0-based indexes !!! */
find_neighborhood (board, toindex (3), toindex (3));
Don't use MagicNumbers in your code. (e.g. 6). This limits your code to a single arrays size requiring picking though all loop and array declarations and recompiling your code just to handle a change of array size. Instead:
#define ROWS 6 /* if you need a constant, #define one (or more) */
#define COLS ROWS
void draw_board (const char board[ROWS][COLS]);
void find_neighborhood (const char board[ROWS][COLS], int row, int col);
This impacts how you write you reading in draw_board() as well, e.g.
void draw_board(const char board[ROWS][COLS])
{
fputs (" ", stdout); /* don't use MagicNumbers */
for (int i = 0; i < ROWS; i++) /* create your headings */
printf ("%2d", i + 1); /* from defined constants */
fputs ("\n ", stdout);
for (int i = 0; i < 2 * COLS - 1; i++)
putchar ('-');
putchar ('\n');
for (int i = 0; i < ROWS; i++) {
printf (" %d|", i);
for (int j = 0; j < COLS; j++) {
printf (j ? " %c" : "%c", board[i][j]);
}
putchar ('\n');
}
}
You have another subtle issue with your declaration of board as char board[6][6] and then your use of the const qualifier in your function parameter lists. Pointers to arrays with different qualifiers are incompatible in ISO C. C11 Standard - 6.7.6.1 Pointer declarators(p2). This is the result of array/pointer conversion on a 2D array resulting in a pointer-to-array of actual type char (*)[6]. Try it, enable full warnings with -Wall -Wextra -pedantic (or /W3 on VS)
As for a "more-elegant" ways to write find_neighborhood() your though of nested loops and bounds checks at the edges is as good as any other approach. You started out in that direction, and other than writing a set of if...else if...else if...else conditionals, it probably a good choice. Eliminating your 1-based/0-based problem it could be written as:
/* all array manipulation functions should use 0-based indexes */
void find_neighborhood (const char board[ROWS][COLS], int row, int col)
{
printf ("\nThe neighbors of '%c' are:\n\n", board[row][col]);
for (int i = row ? row - 1 : row; i <= (row < ROWS - 1 ? row + 1 : row); i++) {
for (int j = col ? col - 1 : col; j <= (col < COLS - 1 ? col + 1 : col); j++) {
if (i == row && j == col)
fputs (" ", stdout);
else
printf (" %c", board[i][j]);
}
putchar ('\n');
}
}
Putting it altogether, you would have:
#include <stdio.h>
#define ROWS 6 /* if you need a constant, #define one (or more) */
#define COLS ROWS
void draw_board (const char board[ROWS][COLS]);
void find_neighborhood (const char board[ROWS][COLS], int row, int col);
/* convert 1-based rows/cols to 0-based indexes */
int toindex (int rc)
{
return rc ? rc - 1 : rc;
}
int main() {
const char board[ROWS][COLS] = { /* avoid global variables */
{ '0','0','0','0','0','0' },
{ '0','1','2','3','0','0' }, /* pointers to arrays with */
{ '0','4','P','5','0','0' }, /* different qualifiers are */
{ '0','6','7','8','0','0' }, /* incompatible in ISO C */
{ '0','0','0','0','0','0' },
{ '0','0','0','0','0','0' },
};
draw_board(board);
/* DANGER mixing 1-based & 0-based indexes !!! */
find_neighborhood (board, toindex (3), toindex (3));
}
void draw_board(const char board[ROWS][COLS])
{
fputs (" ", stdout); /* don't use MagicNumbers */
for (int i = 0; i < ROWS; i++) /* create your headings */
printf ("%2d", i + 1); /* from defined constants */
fputs ("\n ", stdout);
for (int i = 0; i < 2 * COLS - 1; i++)
putchar ('-');
putchar ('\n');
for (int i = 0; i < ROWS; i++) {
printf (" %d|", i);
for (int j = 0; j < COLS; j++) {
printf (j ? " %c" : "%c", board[i][j]);
}
putchar ('\n');
}
}
/* all array manipulation functions should use 0-based indexes */
void find_neighborhood (const char board[ROWS][COLS], int row, int col)
{
printf ("\nThe neighbors of '%c' are:\n\n", board[row][col]);
for (int i = row ? row - 1 : row; i <= (row < ROWS - 1 ? row + 1 : row); i++) {
for (int j = col ? col - 1 : col; j <= (col < COLS - 1 ? col + 1 : col); j++) {
if (i == row && j == col)
fputs (" ", stdout);
else
printf (" %c", board[i][j]);
}
putchar ('\n');
}
}
Example Use/Output
$ ./bin/board_neighbors
1 2 3 4 5 6
-----------
0|0 0 0 0 0 0
1|0 1 2 3 0 0
2|0 4 P 5 0 0
3|0 6 7 8 0 0
4|0 0 0 0 0 0
5|0 0 0 0 0 0
The neighbors of 'P' are:
1 2 3
4 5
6 7 8
When you look for a "more elegant" way of doing anything, in the end you will get a fair amount of opinion built in. Let me know if you have further questions.
There are multiple issues in the code:
find_neighborhood(board[6][6], 3, 3); is incorrect: you should write this instead:
find_neighborhood(board, 3, 3);
in find_neighborhood, the definition int rows = sizeof(board); initializes rows to the size of a pointer, not the number of rows in the matrix. You should use explicit constants or pass the dimensions as extra arguments.
find_neighborhood() performs many tests... But that's the core of the question.
row_number, column_number and board should not be global variables. It is confusing that some functions use the global variables and others take them as arguments (with the same name).
Here is a modified version:
void find_neighborhood(char board[6][6], int row, int col) {
for (int j = max(0, row - 1); j <= min(row + 1, 6); j++) {
for (int i = max(0, col - 1); i <= min(col + 1, 6); i++) {
if (j != row || i != col) {
printf("The neighbor of p is: %c\n", board[j][i]);
}
}
}
}
There is an elegant way to address your objective: you can define board as an 8x8 array where the first and last rows and columns are always empty. The active part of the board has index values in the range 1..6.
Here is a modified version with this approach:
#include <stdio.h>
#include <stdlib.h>
void draw_board(const char board[8][8]);
char mark_board(char board[8][8], char mark, int row, int col);
void find_neighborhood(char board[8][8], int row, int col);
int main() {
int row_number, column_number;
char board[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, '0','0','0','0','0','0', 0 },
{ 0, '0','1','2','3','0','0', 0 },
{ 0, '0','4','P','5','0','0', 0 },
{ 0, '0','6','7','8','0','0', 0 },
{ 0, '0','0','0','0','0','0', 0 },
{ 0, '0','0','0','0','0','0', 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
draw_board(board);
find_neighborhood(board, 4, 4); // trying to find neighbors of char p
return 0;
}
void draw_board(const char board[8][8]) {
printf(" 1 2 3 4 5 6\n");
printf(" -----------\n");
for (int i = 1; i <= 6; i++) { // rows
printf("%i| ", i); // row number to be printed
for (int j = 1; j <= 6; j++) { // columns
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void find_neighborhood(char board[8][8], int row, int col) {
char save = board[row][col];
board[row][col] = 0;
for (int j = row - 1; j <= row + 1; j++) {
for (int i = col - 1; i <= col + 1; i++) {
if (board[j][i] != 0) {
printf("The neighbor of p is: %c\n", board[j][i]);
}
}
}
board[row][col] = save;
}
I have 2D array, I need to write a function to find which row has the biggest sum, and if there is more than one row with the same sum, I need to print no particular max. This is what I wrote so far:
int find_max_sum(int b[N][N])
{
int row_sum = 0;
int row_max = -1;
int i,j,k;
int counter=0;
for(int i =0;i<N;i++)
{
row_sum = 0;
for (j = 0; j < N; ++j)
{
row_sum += b[i][j] ;
}
if(row_max < row_sum)
{
row_max = row_sum;
}
}
for (i = 0; i < N; i++)
{
for (j= 0;j< N;j++)
{
if(k=row_max);
counter++;
}
}
if (counter>1)
return(printf("No unique max.\n"));
else
return row_max;
}
Now I need help with the counter thing, and if the function is int how can it return prints? Is it possible?
Here's an example.
#include <stdio.h>
#include <stdbool.h>
#define N 2
#define NO_UNIQUE -1
int find_max_sum(int b[][N])
{
int row_sum, i, j;
int row_max = -1;
bool unique = false;
for (i = 0; i < N; ++i) {
row_sum = 0;
for (j = 0; j < N; ++j)
row_sum += b[i][j];
if (row_max < row_sum) {
row_max = row_sum;
unique = true;
} else if (row_max == row_sum)
unique = false;
}
if (unique)
return row_max;
else {
printf("No unique max.\n");
return NO_UNIQUE;
}
}
int main(void)
{
int b[N][N] = {1, 2, 3, 4};
printf("Max sum is %d\n", find_max_sum(b));
return 0;
}
I suggest you to use a third variable (let's call it rowsWithMaxCount) to store the amount of rows with the current max value such that:
if you find a row with a new maximum then rowsWithMaxCount = 1
if you find a row such that row_max == row_sum then ++rowsWithMaxCount
otherwise rowsWithMaxCount is unaffected
This will save you from looping the bidimensional array, which is a waste of code since you can obtain all the information you need with a single traversal of the array.
"returning a printf" doesn't make any sense and it's not possible, if you declare the function to return an int then you must return an int. Consider using a special value to signal the caller that there is no unique maximum value. Eg, assuming values are always positive:
static const int NO_UNIQUE_MAX = -1;
int find_max_sum(int b[N][N]) {
...
if (counter > 1)
return NO_UNIQUE_MAX;
...
}
But this will prevent you from returning the not-unique maximum value. If you need to return both then you could declare a new type, for example
struct MaxRowStatus {
int value;
int count;
};
So that you can precisely return both values from the function.
You may be over-thinking the function, if I understand what you want correctly. If you simply want to return the row index for the row containing a unique max sum, or print no unique max. if the max sum is non-unique, then you only need a single iteration through the array using a single set of nested loops.
You can even pass a pointer as a parameter to the function to make the max sum available back in your calling function (main() here) along with the index of the row in which it occurs. The easiest way to track the uniqueness is to keep a toggle (0, 1) tracking the state of the sum.
An example would be:
int maxrow (int (*a)[NCOL], size_t n, long *msum)
{
long max = 0;
size_t i, j, idx = 0, u = 1;
for (i = 0; i < n; i++) { /* for each row */
long sum = 0;
for (j = 0; j < NCOL; j++) /* compute row sum */
sum += a[i][j];
if (sum == max) u = 0; /* if dup, unique 0 */
if (sum > max) /* if new max, save idx, u = 1 */
max = sum, idx = i, u = 1;
}
if (u) { /* if unique, update msum, return index */
if (msum) *msum = max;
return idx;
}
fprintf (stderr, "no unique max.\n");
return -1; /* return -1 if non-unique */
}
(note: if you don't care about having the max sum available back in the caller, simply pass NULL for the msum parameter)
A short test program could be the following. Simply uncomment the second row to test the behavior of the function for a non-unique max sum:
#include <stdio.h>
#include <stdlib.h>
enum { NCOL = 7 };
int maxrow (int (*a)[NCOL], size_t n, long *msum)
{
long max = 0;
size_t i, j, idx = 0, u = 1;
for (i = 0; i < n; i++) { /* for each row */
long sum = 0;
for (j = 0; j < NCOL; j++) /* compute row sum */
sum += a[i][j];
if (sum == max) u = 0; /* if dup, unique 0 */
if (sum > max) /* if new max, save idx, u = 1 */
max = sum, idx = i, u = 1;
}
if (u) { /* if unique, update msum, return index */
if (msum) *msum = max;
return idx;
}
fprintf (stderr, "no unique max.\n");
return -1; /* return -1 if non-unique */
}
int main (void) {
int a[][7] = {{ 0, 9, 3, 6, 4, 8, 3 },
/* { 3, 9, 2, 7, 9, 1, 6 }, uncomment for test */
{ 6, 1, 5, 2, 6, 3, 4 },
{ 4, 3, 3, 8, 1, 2, 5 },
{ 3, 9, 2, 7, 9, 1, 6 }},
maxidx;
long sum = 0;
size_t nrow = sizeof a/sizeof *a;
if ((maxidx = maxrow (a, nrow, &sum)) != -1)
printf (" max sum '%ld' occurs at row : %d (0 - indexed).\n",
sum, maxidx);
return 0;
}
Example Use/Output
For the unique sum case:
$ ./array2Drow
max sum '37' occurs at row : 3 (0 - indexed).
non-unique case:
$ ./array2Drow
no unique max.
Look it over and let me know if you have any questions, or if I misinterpreted your needs.