Why won't for loop terminate? - c

My function:
int checkSE(disk board[][SIZE], disk hypotheticalDisk)
{
int i;
int j;
int row;
int col;
int player;
int opponent;
int checkSEflag;
player = hypotheticalDisk.type;
(player == 0) ? (opponent = 1) : (opponent = 0);
row = hypotheticalDisk.pos.row;
col = hypotheticalDisk.pos.col;
checkSEflag = 0;
for (i = row + 2, j = col + 2; ((i < SIZE) && (j < SIZE) && (checkSEflag == 0)); i++, j++)
{
if (board[i][j].type == player)
{
for (--i, --j; board[i][j].type == opponent; i--, j--)
{
if (i == row && j == col)
{
checkSEflag = 1;
break;
}
}
}
printf("\n%d and %d and %d", i, j, checkSEflag);
}
return checkSEflag;
}
My output:
2 and 3 and 0
2 and 3 and 0
2 and 3 and 0
2 and 3 and 0
2 and 3 and 0
.
.
.
And it keeps on going...
I want both i and j to increase until they are equal to SIZE (SIZE predefined to be 8) or until checkSEflag is assigned to be equal to 1.
It looks like the values of i and j just aren't being changed...
I tried taking them out of the loop conditions and instead placed them
in the loop body, though that didn't change anything.
I doubt the post increment operators just decided to not work so I must be doing something wrong, any ideas of what that may be?

These two lines:
for(i = row+2, j = col+2; ((i < SIZE) && (j <SIZE) && (checkSEflag == 0)); i++, j++)
...
for(--i, --j; board[i][j].type == opponent; i--, j--)
so, you are both incrementing and decrementing (i,j); try sprinkling printfs around these and see if you are both incrementing and decrementing i,j on each iteration...

Related

C, 2D Array, How to find specific number in all 8 directions

You are allowed to enter only 0 and 1 as values in the arrays. Then in place of all elements having a value of 0, enter the number of elements with a value of 1 around that element in all eight directions. And on the end print the 2d array and the values with 1 change to *.
Here is an example how it's supposed to look like:
Here is my code
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n,m;
scanf("%d%d", &n, &m);
int a[n][m];
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
scanf("%d", &a[i][j]);
if(a[i][j]==1){
a[i][j]=9;
}
}
}
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
int counter=0;
if(a[i][j]==9){
printf("*\t");
}else if(a[i][j]==0){
if(a[i+1][j+1]==9 && i!=n && j!=m) counter++;
if(a[i-1][j-1]==9 && i!=0 && j!=0) counter++;
if(a[i+1][j-1]==9 && i!=n && j!=0) counter++;
if(a[i-1][j+1]==9 && i!=0 && j!=m) counter++;
if(a[i][j+1]==9 && j!=m) counter++;
if(a[i][j-1]==9 && j!=0) counter++;
if(a[i+1][j]==9 && i!=n) counter++;
if(a[i-1][j]==9 && i!=0) counter++;
a[i][j]=counter;
counter=0;
printf("%d\t", a[i][j]);
}
}
printf("\n");
}
return 0;
}
You have UB (undefined behavior).
With (e.g.):
if (a[i + 1][j + 1] == 9 && i != n && j != m)
Then, a is always fetched, even if i or j is out of range.
To fix this, reorder the terms:
if (i != n && j != m && a[i + 1][j + 1] == 9)
Now, if either i or j is out of range, then the if will be "short circuited": (i.e. _short circuit evaluation) and the a value will not be fetched.
But, your program output is incorrect. You're coding everything out longhand. It makes it hard to debug (i.e. which lines have a bug).
What wasn't explicitly described was that you are summing the non-zero values in a 3x3 kernal around a given zero point.
The hardcoding doesn't scale too well. Suppose the kernal had to be 100x100. Would we code up 10,000 lines of code?
It's much easier to debug if we refactor to use for loops. And, to use more descriptive names instead of i/j/m/n:
n hgt
m wid
i y*
j x*
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc,char **argv)
{
int hgt, wid;
int counter;
FILE *xf;
--argc;
++argv;
if (argc > 0)
xf = fopen(*argv,"r");
else
xf = stdin;
if (xf == NULL) {
perror(*argv);
exit(1);
}
fscanf(xf,"%d%d", &hgt, &wid);
int a[hgt][wid];
for (int ycur = 0; ycur < hgt; ycur++) {
for (int xcur = 0; xcur < wid; xcur++) {
int val;
fscanf(xf,"%d", &val);
if (val == 1)
val = 9;
a[ycur][xcur] = val;
}
}
for (int yctr = 0; yctr < hgt; yctr++) {
for (int xctr = 0; xctr < wid; xctr++) {
if (a[yctr][xctr] == 9) {
printf("*\t");
continue;
}
counter = 0;
for (int yoff = -1; yoff <= 1; yoff++) {
int ycur = yctr + yoff;
if (ycur < 0)
continue;
if (ycur >= hgt)
continue;
for (int xoff = -1; xoff <= 1; xoff++) {
int xcur = xctr + xoff;
if (xcur < 0)
continue;
if (xcur >= wid)
continue;
counter += (a[ycur][xcur] == 9);
}
}
printf("%d\t",counter);
}
printf("\n");
}
return 0;
}
Here is the program output for your sample input:
* 1 1 2 *
2 2 2 * 3
* 1 2 * 2
Not sure what the question is, but there are bugs in the code -
you are accessing out of array boundaries by doing, for example, this:
if(a[i-1][j-1]==9 && i!=0 && j!=0)
When i and j are zeros you are reading the value of a[-1][-1]. Changing the order of conditions and checking i and j first would guard against such an access.
Same happens when you access the "borders" of the matrix.
And, the "i!=n && j!=m" condition is always true within the loops - you iterate as long as i<n and j<m.
But aside of that, some of these accesses in fact read from within the array, but from a wrong location.
Here is an example that shows that:
Given the matrix of 2x2
0 1
1 0
This is the result your code produced:
2 *
* 3
Where obviously, '3' is wrong.
Why it happened?
The 2D array is in fact stored as a 1D array in memory, like this:
0 1 1 0 // this is your data
0 1 2 3 // this is the index in the array (offset from the array start)
And each element is located at an offset of row*columns+column from the array start (i.e. this is the formula to find the index in 1D array given i and j).
When you count the '1'-neighbours for the last element (a[1][1] in this example), you count the two obvious results (at a[1][0] and a[0][1]), but then you hit this condition:
if(a[i-1][j+1]==9 && i!=0 && j!=m)
For this last cell, i is 1 and j is 1, so the second part of the condition is true.
But what about a[i-1][j+1]==9 ?
This references a memory at row*columns+column, right? I.e. (i-1)*2+(j+1), because that's what you tried to access. Substituting i and j with 1 and 1, and you get offset 2 in the 1D array above.
Which is 1 in the input matrix (or actually 9 since you've replaced it).
So you count it twice.
Guarding better against "stepping out" of the matrix (but not necessarily out of the actual array) will solve this bug.

optimizing C code with imbedded for loops

void evolve(board prv, board nxt){
int i, j;
int n;
printf("\rGeneration %d\n", generation++);
if (printLazy == 1){
lazyPrint(prv);
for (j=0; j < WIDTH; ++j) {
for (i = 0; i < HEIGHT; ++i) {
n = neighbors(prv, i, j);
if (prv[i][j] && (n == 3 || n == 2))
nxt[i][j] = true;
else if (!prv[i][j] && (n == 3))
nxt[i][j] = true;
else
nxt[i][j] = false;
}
}
}
** Some asked me to add the neighbors method so
static int neighbors (board b, int i, int j) {
int n = 0;
int i_left = max(0,i-1);
int i_right = min(HEIGHT, i+2);
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int ii, jj;
for (ii = i_left; ii < i_right; ++ii) {
for (jj = j_left; jj < j_right; ++jj) {
n += b[ii][jj];
}
}
return n - b[i][j];
}
So I am working on optimizing this so that it will go faster and I'm stuck on how to optimize this more. Here's what I have so far
void evolve(board prv, board nxt) {
register int i, j;
int n;
bool next;
printf("\rGeneration %d\n", generation++);
if (printLazy == 1){
lazyPrint(prv);
}
for (j=0; j < WIDTH; ++j) {
for (i = 0; i < HEIGHT; ++i) {
n = neighbors(prv, i, j);
if (prv[i][j])
if (n == 2)
next = true;
else if (n == 3)
next = true;
else
next = false;
else
if(n == 3)
next = true;
else
next = false;
nxt[i][j] = next;
}
}
}
Is there a better way to do this or are there any resources or videos y'all recommend?
Thanks, any help is appreciated.
Some ideas Inline your function neighbors(). Or turn it into a macro. Tidy up the conditional. To unroll the inner loop replace every use of i with the literal values so your code looks like :
for (j =0;.......
n = fun(prev, 0 ,j);
If.....
n = fun(prev, 1, j);
if......
and so on.
If the value of HEIGHT was let's say 100, then you get a code explosion of 100 function calls and 100 compound conditionals. Even worse if you unroll the outer loop.
If n was limited to say 8 neighbors, use a lookup table
bool foo[2][8] = { [1][2] = true, [1][3] = true, [0][3] = true };
for (j=0; j < WIDTH; ++j) {
for (i = 0; i < HEIGHT; ++i) {
n = neighbors(prv, i, j);
nxt[i][j] = foo[prv[i][j]][n];
}
}
A common weakness is the neighbors(prv, i, j) function itself. One trick to to oversize the 2D array by 1 on all four sides and populate the edge with false so neighbors() can always check 8 neighbors as it is never used on the edge/corners.
Making sure the 2nd dimension is a power of 2 helps also - simplifies index calculation. So if the original array way 12*11, make the new array (1+12+1)*(1+11+1+4) or 14*16.

Pascal's triangle in C weird output

I'm trying to write a program to display Pascal's triangle up to a user-inputted number of levels. We aren't allowed to use the factorial method. My current code is this:
#include <stdio.h>
void trianglePrint(const int numLevels);
int main() {
int numLevels;
printf("Please enter how many levels of Pascal's Triangle you would
like to see: ");
scanf("%d", &numLevels);
trianglePrint(numLevels);
return 0;
}
void trianglePrint(const int numLevels) {
int pascalTriangle[28][28];
int i, j;
for (i = 0; i < numLevels; ++i) {
for (j = 0; j <= i; ++j) {
if (i == 0 || i == 1 || j == 0 || j == numLevels) {
pascalTriangle[i][j] = 1;
printf("%d ", pascalTriangle[i][j]);
}
else {
pascalTriangle[i][j] = pascalTriangle[i - 1][j - 1] +
pascalTriangle[i - 1][j];
printf("%d ", pascalTriangle[i][j]);
}
}
printf("\n");
}
}
We're only supposed to be able to go up to 28 levels, which is why I am using an array of size 28 in both dimensions.
This works fine for about 6 levels of the triangle, but for larger levels it gives really large integers. I assumed it was due to uninitialized arrays, but I'm not sure. Does anyone know where the error is?
If you change
if (i == 0 || i == 1 || j == 0 || j == numLevels)
to
if (i == 0 || i == 1 || j == 0 || j == i)
(thanks to Melpomene), then all accesses to your array end up on already intiailised members.
That solves the strange numbers.
Output:
Please enter how many levels of Pascal's Triangle you would like to see: 6
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
Process returned 0 (0x0) execution time : 2.264 s
Press any key to continue.
Note:
Also initialising an array is a wise precaution. You could initialise with values which help finding an error, instead of hiding it, e.g. 42.
The problem is that you haven't set pascalTriangle[i - 1][j] before you use it to compute pascalTriangle[i][j] in the else clause.
Try the code
void Pascal(int n)
{
int arr[n][n];
for (int i = 0; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
// First and last values in every row are 1
if (i == j || j == 0)
arr[i][j] = 1;
else // Other values are sum of values just above and left of above
arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
printf("%d ", arr[i][j]);
}
printf("\n");
}
}

8 Queens puzzle with recursive deep search

I'm trying to solve the 8 queens puzzle problem in C. I'm having problems with the recursive search. The program is supposed to start at a given column:
execute(tabuleiro,8,0);
Where the 8 is the number of columns in the board, and 0 is the start column.
This works when I start at column 0. When I send any other column number to the recursive search, the program just counts to the last column. For example, if I choose to start the search from the number 5 column, the code search from the column 5 to 7, after this it should search from 0 to 4, but it doesn't do that.
If I do this:
execute(tabuleiro,8,3);
It fills in only the last 5 colummns, and does not return to column 0 to finish the solution:
Also, how can I select the initial position for the queen in this code? Like I said before, the column is assigned in the code, but I'm not sure how to pick the correct column.
The code has 3 functions: one is to display the board, a second to check if the move is legal (so one queen doesn't attack the other), and the last one to place one queen and recur for the remainder of the board.
#include <stdlib.h>
#include <windows.h>
int sol = 0;
void viewtab(int tab[][8], int N)
{
int i,j;
for( i = 0; i < N; i++)
{
for( j = 0; j < N; j++)
{
if(tab[i][j] == 1)
printf("R\t");
else
printf("-\t");
}
printf("\n\n");
}
printf("\n\n");
system("pause");
printf("\n");
}
int secury(int tab[][8], int N, int lin, int col)
{
// this function is to check if the move is secury
int i, j;
// attack in line
for(i = 0; i < N; i++)
{
if(tab[lin][i] == 1)
return 0;
}
//attack in colune
for(i = 0; i < N; i++)
{
if(tab[i][col] == 1)
return 0;
}
// attack in main diagonal
//
for(i = lin, j = col; i >= 0 && j >= 0; i--, j--)
{
if(tab[i][j] == 1)
return 0;
}
for(i = lin, j = col; i < N && j < N; i++, j++)
{
if(tab[i][j] == 1)
return 0;
}
// attack in main secondary
for(i = lin, j = col; i >= 0 && j < N; i--, j++)
{
if(tab[i][j] == 1)
return 0;
}
for(i = lin, j = col; i < N && j >= 0; i++, j--)
{
if(tab[i][j] == 1)
return 0;
}
// if arrive here the move is secury and return true
return 1;
}
void execute(int tab[][8], int N, int col)
{
int i;
if(col == N)
{
printf("Solution %d ::\n\n", sol + 1);
viewtab(tab, N);
sol++;
return;
}
for( i = 0; i < N; i++)
{
// check if is secury to put the queen at that colune
if(secury(tab, N, i, col))
{
// insert the queen (with 1)
tab[i][col] = 1;
// call recursive
execute(tab, N, col + 1);
// remove queen (backtracking)
tab[i][col] = 0;
}
}
}
int main()
{
int i, j, tabuleiro[8][8];
for (i = 0; i < 8; i = i + 1)
for (j = 0; j < 8; j = j + 1) tabuleiro[i][j] = 0;
execute(tabuleiro,8,0);
return 0;
}
The search always stops in the rightmost column because you specifically tell it to stop there:
void execute(int tab[][8], int N, int col)
{
int i;
if(col == N)
{
printf("Solution %d ::\n\n", sol + 1);
viewtab(tab, N);
sol++;
return;
}
Look at your termination condition: you check the current column against the highest column number, and stop there.
If you want to go back to column 0, you have to change your loop logic. For instance, let col reach N, at which point you reset it to 0, and let it continue until you hit the original value. Another way is to continue until the count of placed queens is N.
You choose the initial point in the same way: you pick the first one and make your recursive call. If that eventually results in a solution, you print it. If not, your top-most call continues to the next row (line) of the board and puts the first queen there.
This is already in your main logic. Just make sure that secury will return true when the board is empty, rather than false or throwing an error.
A. You can place the first Queen at (0,0).
B. And begin the search also from (0,0).
C. I do not see any need to start looking for some other index.
Successfully!!

C convert for loop into a while loop and recursion

I'm doing another exercise and I have to :
"Write a recursive function to print all solution to the eight queens chess problem, return the number of solutions and the function prototype must be : int function(void)
To work around the no argument rule I used static variables.
I've done it (with google's help), and it works, but they don't allow to use for loops and for some reason I can't manage to convert the last two for loops to while loops.
It' driving me crazy, it should be easy! I think it's the recursion that mess it up...
Here's the working function :
int function()
{
static int count = 0;
static int col = 0;
const int n = 8;
static int hist[8] = {10, 10, 10, 10, 10, 10, 10, 10};
int i1 = 0;
if (col == n) {
count++;
while (i1++ < n)
{
putchar('0' + hist[i1-1] + 1);
}
putchar('\n');
}
for (int i = 0; i < n; i++) {
int j = 0;
for (j = 0; j < col && !(hist[j] == i || (hist[j] - i) == col - j || -(hist[j] - i) == col - j); j++);
if (j < col) {
continue;
}
hist[col] = i;
col++;
function();
col--;
}
return count;
}
And I tried to convert the two last for loops to while loops like this :
int i = 0;
while (i < n)
{
int j = 0;
while (j < col && !(hist[j] == i || (hist[j] - i) == col - j || -(hist[j] - i) == col - j))
{
j++;
}
if (j < col) {
continue;
}
hist[col] = i;
col++;
function();
col--;
i++;
}
But it doesn't work, is there more the for loops than it seems ? I'm new to recursion, I thought I got it but it seems I was wrong...
I ran the code and found the problem. It is with the line
if (j < col) {
continue;
}
since this isn't a continue statement that goes to a for loop, you have to increment i in this condition as well.
if (j < col) {
i++; // add this line
continue;
}
You can change the first loop to
while(i++<n)
and it works fine.

Resources