Whenever I run my code I get a message: Segmentation fault: 11
My question is why this message is popping up. I have done some research prior to this and have tried to fix it but I still have the same message pop up. Please review my code!
To give some context to my code: The goal of this program is to implement the Connect Four game between a computer and a human player. Functions are to be implemented in the file connect4_functions.c. Forward declarations of these functions are in the file connect4_functions.h. connect4.c contains the main () functions.
The code (connect4_functions.c) is below:
#include "connect4_functions.h"
int print_welcome(void) // PROBLEM: returnerer alltid 1
{
printf ("*** Welcome to the Connect Four game!!! ***\n");
printf ("Would you like to make the first move [y/n]: ");
if (getchar() == 'N' || getchar() == 'n') return 2;
else return 1;
while (getchar()!= '\n');
}
void display_board(int board[][BOARD_SIZE_VERT])
{
int i, j;
for (i = BOARD_SIZE_VERT-1; i >= 0; i--)
{
for (j = 0; j < BOARD_SIZE_HORIZ; j++) printf ("+---");
printf ("+\n");
for (j = 0; j < BOARD_SIZE_HORIZ; j++)
{
switch (board[j][i])
{
case 0: printf ("| "); break;
case 1: printf ("| O "); break;
case 2: printf ("| X "); break;
}
}
printf ("|\n");
} // end for
for (j = 0; j < BOARD_SIZE_HORIZ; j++) printf ("+---");
printf ("+\n");
for (j = 1; j <= BOARD_SIZE_HORIZ; j++) printf (" %d ", j);
printf ("\n");
} //end function display_board
int random_move(int board[][BOARD_SIZE_VERT], int computer_num)
{
int m = (rand() % BOARD_SIZE_HORIZ) + 1;
if (!is_column_full(board,m))
{
update_board(board,m,computer_num);
return m;
}
else return random_move(board,computer_num);
}
int player_move(int board[][BOARD_SIZE_VERT], int player_num)
{
int m;
printf ("Please enter your move: ");
scanf ("%d", &m);
while (getchar() != '\n');
if ( 0 > m || m > BOARD_SIZE_HORIZ)
{
printf ("Not a valid move. Enter a column number!\n");
return player_move(board, player_num);
}
if (is_column_full(board, m))
{
printf ("This column is full. Try again!\n");
return player_move(board, player_num);
}
update_board(board,m,player_num);
return m;
}
bool check_win_or_tie(int board[][BOARD_SIZE_VERT], int last_move)
{
int m, count = 0;
if (check_winner(board, last_move))
{
printf("Player %c won!\n", ( check_winner(board,last_move) == 1 ? '1' : '2' ) );
return true;
}
for (m = 0; m < BOARD_SIZE_HORIZ; m++) if ( is_column_full(board, m) ) count++;
if (count == BOARD_SIZE_HORIZ)
{
printf ("Tie game!\n");
return true;
}
else return false;
}
bool is_column_full(int board[][BOARD_SIZE_VERT], int m)
{
return (board[m-1][BOARD_SIZE_VERT-1]);
}
void update_board(int board[][BOARD_SIZE_VERT], int m, int player_num)
{
int i;
for ( i = 0; i < BOARD_SIZE_VERT ; i++)
{
if (!board[m-1][i])
{
board[m-1][i] = player_num;
return;
}
}
}
int check_winner(int board[][BOARD_SIZE_VERT], int last_move)
{
int i, row, count;
// Find row
for (row = 0; row < BOARD_SIZE_VERT; row++)
{
if (board[last_move-1][row]) count++;
}
row = count;
printf ("row = %d\n", row);
// Vertical
for (i = 0; i < BOARD_SIZE_VERT; i++)
{
if (board[last_move-1][i] == board[last_move-1][row]) count++;
else count = 0;
if (count == 4) return board[last_move-1][row];
else return 0;
}
count = 0; // reset
// Horizontal
for (i = 0; i < BOARD_SIZE_HORIZ; i++)
{
if (board[i][row] == board[last_move-1][row]) count++;
else count = 0;
if (count == 4) return board[last_move-1][row];
else return 0;
}
count = 0; // reset
return 0;
}
The code for connect4_functions.h (cannot be changed) is below:
#ifndef CONNECT4_FUNCTIONS
#define CONNECT4_FUNCTIONS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define BOARD_SIZE_HORIZ 7
#define BOARD_SIZE_VERT 6
int print_welcome(void);
void display_board(int board[][BOARD_SIZE_VERT]);
int random_move(int board[][BOARD_SIZE_VERT], int computer_num);
int player_move(int board[][BOARD_SIZE_VERT], int player_num);
bool check_win_or_tie(int board[][BOARD_SIZE_VERT], int last_move);
bool is_column_full(int board[][BOARD_SIZE_VERT], int m);
void update_board(int board[][BOARD_SIZE_VERT], int m, int player_num);
int check_winner(int board[][BOARD_SIZE_VERT], int last_move);
int best_move(int board[][BOARD_SIZE_VERT], int computer_num);
#endif
The code for connect4.c (also cannot be changed) is below:
#include "connect4_functions.h"
int main()
{
int board[BOARD_SIZE_HORIZ][BOARD_SIZE_VERT] = { {0} };
int player_num, computer_num;
int last_move;
/* Ask Alice if she wants to go first */
player_num = print_welcome();
if (player_num == 1) computer_num = 2;
else computer_num = 1;
/* If Alice wants to go first, let her make a move */
if (player_num == 1)
{
display_board(board);
last_move = player_move(board,player_num);
display_board(board);
}
/* The main loop */
while (1)
{
/* Make a computer move, then display the board */
last_move = random_move(board,computer_num);
printf("Computer moved in column: %d\n", last_move);
display_board(board);
/* Check whether the computer has won */
if (check_win_or_tie(board,last_move)) return 0;
/* Let Alice make a move, then display the board */
last_move = player_move(board,player_num);
display_board(board);
/* Check whether Alice has won */
if (check_win_or_tie(board,last_move)) return 0;
} /* end of while (1) */
} /* end of main() */
Also, if you would like to see the original pdf it is linked below:
Link to pdf
The output is:
*** Welcome to the Connect Four game!!! ***
Would you like to make the first move [y/n]: y
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
1 2 3 4 5 6 7
Please enter your move: 4
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | O | | | |
+---+---+---+---+---+---+---+
1 2 3 4 5 6 7
Computer moved in column: 1
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| X | | | O | | | |
+---+---+---+---+---+---+---+
1 2 3 4 5 6 7
row = -355898527
Segmentation fault: 11
(If you have any questions about the context or purpose please don't hesitate to ask!)
Not having actually run the code, I believe the issue may be that count is not initialized in check_winner:
int check_winner(int board[][BOARD_SIZE_VERT], int last_move)
{
int i, row, count;
// Find row
for (row = 0; row < BOARD_SIZE_VERT; row++)
{
if (board[last_move-1][row]) count++;
}
row = count;
// WHAT IF IT EXITS THE for () WITHOUT board[last_move-1][row] being non-zero?
// HINT: count can be anything!
printf ("row = %d\n", row);
You then use row as an access into an array, and boom! You've accessed memory outside your permissions.
In the check_winner function you don't initialise the variable count. I get an unitialised variable runtime error, yet if I continue ahead a couple of lines later you then set:
row = count;
Which in my case is setting row to -858993459;
A couple of lines down in that same function you write:
if (board[last_move - 1][i] == board[last_move - 1][row]) count++;
// You use "row", an initialised variable as the index
// for the second subscript operator of board.
And that's where I get:
Access violation reading location 0x0000005663E82BB4. occurred
I think there should have been a warning shown about this unitialised variable. And honestly, I don't know if that's all that's wrong with it, but it looks like a pretty good game.
First of all, to be able to solve your problem, you should make sure everything that might be printed before the crash, has been printed. In this goal, you should add a fflush(stdout); instruction after each of your printing instructions
secondly, if this doesn't make clear at what place you program crashes, you should add supplementary tracing instruction inside the piece of code where it happens.
And then, when you have identified which instruction causes de crash, you should print it's variables to check if their values are what you expect.
Alternatively, you can use the assert instruction to make sure the variable values are all in the expected ranges.
Related
I'm working through the K&R C programming book, and I just completed exercise 1-13 where you print a histogram of the lengths of words that are input. My horizontal histogram is fine, but my vertical histogram has a '%' sign appearing at the end of it, and I can't figure out why that keeps happening. Here is the loop that I think is causing the issue:
for (i = 0; i < array_length; i++) {
printf("%-4d", i + 1);
}
If the array_length is 7, I will have a '%' sign after the 7th position like this:
|
| |
| |
| |
| |
| |
| | | | |
| | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
1 2 3 4 5 6 7 %
If I remove this loop, the vertical bars print fine, I just don't get the numbering below each of them.
What is going on here? As far as I can guess, the printf is running one extra time with garbage data in 'i', but I can't figure out why or how this is happening.
I'm compiling with gcc on Ubuntu, if that makes any difference.
Here is the complete code for your reference:
#include <stdio.h>
#define IN 1
#define OUT 0
#define ARRAY_SIZE 1000
int main() {
int c, current_word_length, state, i, j, current_word, largest, array_length, top;
int word_lengths[ARRAY_SIZE];
current_word_length = current_word = largest = 0;
state = OUT;
for (i = 0; i < ARRAY_SIZE; i++) {
word_lengths[i] = 0;
}
printf("Enter up to 1000 words and this program will calculate their length.\n");
printf("Please enter a newline, tab, or space before the last word entered, then EOF to print summary.\n\n");
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\t' || c == '\n') {
if (state == IN) {
word_lengths[current_word++] = current_word_length;
if (current_word_length > largest) {
largest = current_word_length;
}
current_word_length = 0;
state = OUT;
}
} else {
state = IN;
current_word_length++;
}
}
array_length = current_word;
printf("\nWord Lengths Histogram Horizontal:\n\n");
for (i = 0; i < array_length; i++) {
printf("%-4d: ", i + 1);
for (j = 0; j < word_lengths[i]; j++) {
printf("=");
}
printf("\n");
}
printf("\nWord Lengths Histogram Vertical:\n\n");
top = largest;
while (top > 0) {
for (i = 0; i < array_length; i++) {
if (word_lengths[i] >= top) {
printf("%-4c", '|');
} else {
printf("%-4c", ' ');
}
}
printf("\n");
top--;
}
for (i = 0; i < array_length; i++) {
printf("%-4d", i + 1);
}
return 0;
}
And here is what I expect to occur using this input string "Bacon ipsum dolor amet frankfurter landjaeger ham":
Enter up to 1000 words and this program will calculate their length.
Please enter a newline, tab, or space before the last word entered, then EOF to print summary.
Bacon ipsum dolor amet frankfurter landjaeger ham
Word Lengths Histogram Horizontal:
1 : =====
2 : =====
3 : =====
4 : ====
5 : ===========
6 : ==========
7 : ===
Word Lengths Histogram Vertical:
|
| |
| |
| |
| |
| |
| | | | |
| | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
1 2 3 4 5 6 7
OK, as pointed out by nos and chqrlie in the comments, I need to add a newline at the end of my program so that the shell prompt will appear on a newline AFTER the program has finished running.
Adding the putchar() call at the end of main() fixed my issue:
for (i = 0; i < array_length; i++) {
printf("%-4d", i + 1);
}
putchar('\n');
return 0;
} // end main()
I'm trying to write a function that will take the first n integers and a variable number of functions and build a table that has the number as "i" in the first column and "function(i)" in the others.
But I cannot seem to be able to pass the addresses of my functions to the table generator because I get an access violation error. What did I do wrong?
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
typedef float(*f)(float);
// Some examples of f-type functions.
float square(float x) { return x*x; };
float root(float x) { return sqrt(x); };
float timesPi(float x) { return x * 3.14; };
// Display a table with first colon being the numbers from 1 to n,
// then the other columns to be f(i)
void table(unsigned int n, unsigned int nr_functions, ...)
{
va_list func;
va_start(func, nr_functions);
for (float i = 1; i <= n; i += 1)
{
printf("\n%6.0f |", i);
for (unsigned int j = 0; j < nr_functions; j++)
{
f foo = va_arg(func, f);
printf("%6.3f |", foo(i));
}
va_end(func);
}
}
// Main function
int main()
{
table(5, 3, &square, &root, ×Pi);
system("pause");
return 0;
}
For the example above
table(5, 3, &square, &root, ×Pi);
I want to get back
1 | 1.000 | 3.140 |
2 | 1.141 | 6.280 |
3 | 1.732 | 9.420 |
4 | 2.000 | 12.560 |
5 | 2.236 | 15.700 |
You need to reuse the variable section of the argument list, which means you need the va_start() and va_end() in the right places — inside the outer loop:
void table(unsigned int n, unsigned int nr_functions, ...)
{
for (unsigned int i = 1; i <= n; i++)
{
va_list func;
printf("\n%6.0f |", (double)i);
va_start(func, nr_functions);
for (unsigned int j = 0; j < nr_functions; j++)
{
f foo = va_arg(func, f);
printf("%6.3f |", foo(i));
}
va_end(func);
}
}
Otherwise, you're marching off the end of the list, except that you called va_end() inside the loop, leading to goodness only knows what damage.
Note that the loop should use integer arithmetic — with a consequential change to the printf() — here I cast the value, but changing the format to %6d would also be sane (possibly better, in fact).
With this function, I got the output:
1 | 1.000 | 1.000 | 3.140 |
2 | 4.000 | 1.414 | 6.280 |
3 | 9.000 | 1.732 | 9.420 |
4 |16.000 | 2.000 |12.560 |
5 |25.000 | 2.236 |15.700 |
I am having difficulty understanding the logic behind drawing patterns with * and numbers in C.
For example, I am drawing this pattern:
*
* *
** **
* *
*
Some things that I understand in this programs are to take various for loops for printing * and whitespaces, but it's getting difficult to determine the conditions for them.
In the above example I think I need to draw half the triangle and the remaining is the reverse of it.
So please help me to understand the logic I should consider to draw such patterns every time.
#include<stdio.h>
#include<conio.h>
void main()
{
int i,j=0,k,l,m,o,n=6;
clrscr();
printf(" ");
for(i=0;i<=3;i++)
{
for(j=2;j>0;j--)
{
printf(" ");
for(k=0;k<=(2*i);k++)
{
printf("*");
// getch();
}
}
// getch();
printf("\n");
}
getch();
}
This is how I tried coding, I am not getting the conditions for nested for loop.
-2 -1 0 1 2
+---+---+---+---+---+
-2 | . | . | X | . | . |
+---+---+---+---+---+
-1 | . | X | O | X | . |
+---+---+---+---+---+
0 | X | X | O | X | X |
+---+---+---+---+---+
1 | . | X | O | X | . |
+---+---+---+---+---+
2 | . | . | X | . | . |
+---+---+---+---+---+
Points are not drawn if (col = 0 and abs(row) != 2) or either row or col is 2 and other is non-zero. You can implement these conditions in your code.
For(row = -2 to 2)
For(col = -2 to 2)
if ( (col = 0 and abs(row) != 2) or (abs(row) = 2 and col != 0) or (abs(col) = 2 and row != 0) )
draw space character
else
draw *
line break
#include<stdio.h>
#include<conio.h>
int main()
{
int n=3,i,j,k,l,m;
clrscr();
for(i=0;i<n;i++)
{
for(j=0;j<n-i-1;j++)
printf(" ");
for(k=0;k<=i-1;k++)
printf("*",k+1);
for(m=0;m<1;m++)
{
if(i<=0)
printf("*");
else
printf(" ");
}
for(l=i-1;l>=0;l--)
printf("*",l+1);
printf("\n");
}
for(i=0;i<n-1;i++)
{
for(j=0;j<=i;j++)
printf(" ");
for(k=0;k<n-i-2;k++)
printf("*",k+1);
for(m=0;m<1;m++)
{
if(i==1)
{}
else
printf(" ");
}
for(l=1;l>0;l--)
printf("*",l+1);
printf("\n");
}
getch();
return 0;
}
Finally I got my solution by myself.
I am writing a program that allows a user to play the game connect four against the computer. I am having trouble printing out the correct dimensions for the board. I tried using nested for loops, but the output is a little off.
Here is a part of my code:
#include <stdio.h>
#define BOARD_SIZE_VERT 6
#define BOARD_SIZE_HORIZ 7
void display_board(int board[] [BOARD_SIZE_VERT]);
int main ()
{
int board[BOARD_SIZE_HORIZ][BOARD_SIZE_VERT] = {{0}};
display_board(board);
return 0;
}
void display_board(int board[] [BOARD_SIZE_VERT])
{
int i,j;
for (i=0; i<BOARD_SIZE_HORIZ; i++) {
printf ("+---+---+---+---+---+---+---+");
printf ("\n");
for (j=0; j<BOARD_SIZE_VERT; j++)
printf ("| ");
printf("\n");
}
}
This is my output:
+---+---+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+---+---+
| | | | | |
And this is what I want it to look like:
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
void display_board(int board[] [BOARD_SIZE_VERT]){
int i,j;
for (i=0; i<BOARD_SIZE_VERT; i++) {
printf ("+");
for (j=0; j<BOARD_SIZE_HORIZ; j++)
printf("---+");
printf ("\n");
printf ("|");
for (j=0; j<BOARD_SIZE_HORIZ; j++)
printf(" |");
printf ("\n");
}
printf ("+");
for (j=0; j<BOARD_SIZE_HORIZ; j++)
printf("---+");
printf ("\n");
}
Two main problems: your loops are inverted, and you need some extra characters printed to to get the extra lines on the bottom and right. Try this:
void display_board(int board[] [BOARD_SIZE_HORIZ])
{
int row,col;
for (row=0; row<BOARD_SIZE_VERT; row++) {
printf ("+---+---+---+---+---+---+---+");
printf ("\n");
for (col=0; col<BOARD_SIZE_HORIZ; col++) {
printf ("| ");
}
printf("|\n");
}
printf ("+---+---+---+---+---+---+---+");
}
Here are the relevant changes:
I swapped the usage of the VERT/HORIZ constants in the loops. The outer loop controls the height of the board since you are printing one line at a time. The inner loop controls the number of columns in the board
Renamed i and j to the row and col so the code is more self-documenting
Added a pipe to the printf("\n"), because you need one more vertical separator line than the actual number of slots for each line
Added an extra printf("+---.... at the end, because you need one more horizontal separator than the actual number of rows
Also, I changed the array definition in the function prototype so that the first index is the row and the second is the column. If you choose to follow that, you would need to change other usages of the array in your code. For example:
int board[BOARD_SIZE_VERT][BOARD_SIZE_HORIZ] = {{0}};
Your code work very well. But you have eight "| " to display and You loops only BOARD_SIZE_VERT which worth 6. So you should increase it to 8 or add to it. Try this:
void display_board(int board[] [BOARD_SIZE_VERT]){
int i,j;
for (i=0; i<BOARD_SIZE_HORIZ - 1; i++) {
printf ("+---+---+---+---+---+---+---+");
printf ("\n");
for (j=0; j<BOARD_SIZE_VERT + 2; j++)
printf ("| ");
printf("\n");
}
printf ("+---+---+---+---+---+---+---+\n");
}
I tried making a simple tic tac toe project, and I am trying to make the AI move to random places, so that the AI just moves into any available place. However, it always makes 2 moves. I am wondering why it always makes 2 moves instead of just 1.
What I mean is, let's say the user inputs 'O' into slot 1,1.
0 1 2
+----+----+----+
0 | | | |
| | | |
+----+----+----+
| | | |
1 | | O | |
+----+----+----+
| | | |
2 | | | |
+---------------
Then the computer moves 2 moves: into slots 1,2 AND 2,0
0 1 2
+----+----+----+
0 | | | |
| | | |
+----+----+----+
| | | |
1 | | O | X |
+----+----+----+
| | | |
2 | X | | |
+---------------
So I'd like to know why this happens?
Here is my code:
void compMove(char board[][columns])
{
int randomNum, randomNum1, i, j;
bool didMove = FALSE;
srand((int)time(NULL)); //Seed the random number generator
randomNum = rand() % 3;
randomNum1 = rand() % 3;
while(board[randomNum][randomNum1] != ' ')
{
randomNum = rand() % 3;
randomNum1 = rand() % 3;
}
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
{
if(i == randomNum && j == randomNum1)
{
board[i][j] = 'X';
didMove = TRUE;
break;
}
}
if(didMove == TRUE) break;
}
}
You do not need a loop to set movement on the board.
board[randomNum][randomNum1] = 'X';
is enough to set.
And you probably call this function twice, because function plays only one move.
I suspect your checkWin function is the culprit. Probably has an = somewhere you meant to have an ==. But that's just a guess without seeing it.
Your compMove function is grossly overcomplicated, but not wrong. Here's code that does the same thing:
void compMove(char board[][columns]) {
int row, col;
/* DON'T seed RNG here; do it once in main() */
do {
row = rand() % 3;
col = rand() % 3;
} while (board[row][col] != ' ');
board[row][col] = 'X';
}