For a small project we need to make a connect four game. Our project is broken up into several parts with each week we are assigned a different part to work on.
This week we have to make up the work on the columns by this I mean we have to use a function is called get_column, and use this to read a valid column number from the user where the next piece will be played.
So we were supplied the following files connect4.h (File used to store functions), week8_object.o (ignore the name its just the current week of sem), and week8.c which is the file I am currently editing.
Note 1: The comment in the code is what the lecturer wrote for us as a note.
When I am compiling I get an error saying undeclared identifier for the if(column_full(board, col)==FALSE) statement (FALSE part). I thought this was declared in the .h file?
EDIT- After some googling I have found that people silence that error by having this in the header. Is it correct to have this in coherence with the .h file?:
#include <stdio.h>
#include "connect4.h"
#define FALSE 0
#define TRUE 1
/* get_move
Prompts the user to enter a column, then checks that
- the column is in the valid range (1-COLS)
- that the column is not full (use function column_full to check)
If an invalid column is entered, the user is reprompted until it is valid
Returns the column number between 1 and COLS
*/
int column_full ( int board[COLS][ROWS], int col ) { return TRUE;}
int get_move ( int board[COLS][ROWS] ){
int col;
printf("Please enter a column number:");
scanf("%d",&col);
if(col>=1 && col<=COLS){
if(column_full(board, col)==FALSE){
printf("You have placed a token in the %d column\n",col);
}
else{
printf("That column is full");
}
}
while(col<=0 || col>COLS){
printf("Your token has not been placed");
printf("Please enter a valid column: ");
scanf("%d",&col);
}
return(col);
}
Header file:
#ifndef CONNECT4_H
#define CONNEXT4_H 1
#define ROWS 6
#define COLS 7
// displays the board to the screen
int display_board ( int[COLS][ROWS] ) ;
// sets up the board to an empty state
int setup_board ( int[COLS][ROWS] ) ;
// Returns TRUE if the specified column in the board is completely full
// FALSE otherwise
// col should be between 1 and COLS
int column_full ( int[COLS][ROWS], int col ) ;
// prompts the user to enter a move, and checks that it is valid
// for the supplied board and board size
// Returns the column that the user has entered, once it is valid (1-COLS)
int get_move ( int[COLS][ROWS] ) ;
// adds a token of the given value (1 or 2) to the board at the
// given column (col between 1 and COLS inclusive)
// Returns 0 if successful, -1 otherwise
int add_move ( int b[COLS][ROWS], int col, int colour ) ;
// determines who (if anybody) has won. Returns the player id of the
// winner, otherwise 0
int winner ( int[COLS][ROWS] ) ;
// determines if the board is completely full or not
int board_full ( int[COLS][ROWS] ) ;
#endif
There are few issues in your code:
In get_move() function, the given condition "If an invalid column is entered, the user is reprompted until it is valid" is not been taken care. You might want to use while loop in case of invalid column entered.
column_full() in your code is called without parameters. This function takes two parameters (refer to you .h file). So, don't forget to add them in call.
You have to use return(col) to take care of "Returns the column number between 1 and COLS"
I don't want to write a code for you. It would be helpful for you in long run, if you code yourself.
Now, to answer your question:
It is perfectly fine to have nested if-else statements.
From your original code:
}; /* <<-- problem 1 */
else() {
/* ^^^^ <<-- problem 2 */
printf("That column is full");
}
Remove these and your code will compile. I won't discuss the logic issues.
So in diff notation:
--- connect4.c.orig 2015-09-19 14:34:36.743337010 -0400
+++ connect4.c 2015-09-19 14:34:23.488222720 -0400
## -24,9 +24,9 ##
if(col>=1 && col<=COLS){
if(column_full(board, col)==FALSE){
- printf("You have placed a token in the %d column\n",col);
+ printf("You have placed a token in the %d column\n",col);
}
- else(){
+ else{
printf("That column is full");
}
}
Related
So i'm very much a beginner and this is an assignment for class, but i'm not looking to have someone do the assignment for me or anything. Just help on a part i'm having trouble with.
I'm not posting my code as it's an ongoing assignment and I don't want someone to happen upon it and copy it ): But the gist of it is I need to display a menu to the user and create a switch statement. Each case has a corresponding function prototype that executes the choice the user made from the menu.
1 Enter 3 grades
2 Show average (with 3 grades) and letter grade
3 Show highest grade
4 Show lowest grade
5 Exit
I've done pretty much all of the assignment, but the one requirement I can't figure out is how to initialize the 3 grade variables to random numbers between 50 and 100, so if the user chooses menu options 2 3 or 4 first then those random #'s are what is used in my prototypes. But if the user chooses menu option 1, my functions should use the 3 values input by the user from that point until exit, or if they hit 1 again to input new values.
Since I couldnt figure it out I just had each prototype prompt the user to insert 3 grades then proceed to do its assigned task using those values.
We were also instructed to not use arrays as we havent gotten to that yet.
If no one is able to figure it out without seeing the code i'll wait until after the due date and post what I was able to do. i'm honestly just wanting to learn and my professor doesn't really post any videos or lectures (online class) so we just go off our textbook and good ol google.
Thank you to whoever can help(:
If you want a variable with a random standard value, initialize it with a random value. You can generate a random integer between two numbers using the random() function in the stdlib.h header.
Your code can be structured like this.
#include<stdlib.h>
#include<time.h>
int random_range(int start, int end) {
return start + (int) ((double) random() / RAND_MAX * (end - start));
}
int main() {
srandom(time());
int grade1 = random_range(50, 100);
int grade2 = random_range(50, 100);
int grade3 = random_range(50, 100);
...
}
Now the three grade variables are always initialized and can be used. I recommend, you also read the man page for the random() function.
Not a good idea, doing processing with some randomly assigned data simply to not do the work of controlling the user's options. Imagine that one option is to write the current record into persistent storage. Do you want to risk random valued records polluting the company's database? There are stories of "test versions" that have been released "into the wild" (on the day the coder was home with a cold, but management applied pressure to ship) that... well, that would curl your toes.
Here is a sketch whereby the user has two options only: enter the data or quit the program. Presuming valid data has been accepted, the menu features more options.
Do not process junk. It'll come back to bite you.
/* Usual header files */
int main() {
char buf[ 64 ];
int hiMenuOpt = 1;
do {
printf(
"Here's menu options\n"
"0: Quit\n"
"1: Enter data\n"
);
if( hiMenuOpt > 1 )
printf(
"2: Something\n"
"3: Something else\n"
"4: Something other\n"
);
printf( "Select 0-%d : ", hiMenuOpt );
fgets( buf, sizeof buf, stdin );
int val = strtol( buf, NULL, 10 ); // Edit fix. Thanks to Lundin
if( val < 0 || hiMenuOpt < val ) {
printf( "Bad entry\n" );
continue;
}
switch( val ) {
case 0:
hiMenuOpt = 0;
break;
case 1:
puts( "Hi from one\n" );
/* yadda yadda */
hiMenuOpt = 4;
break;
/* More stuff */
}
} while( hiMenuOpt );
return 0;
}
Here's menu options
0: Quit
1: Enter data
Select 0-1 : 1
Hi from one
Here's menu options
0: Quit
1: Enter data
2: Something
3: Something else
4: Something other
Select 0-4 :
Notice that Quit is now item 0. New menu items may be added, and old ones removed. The only constant is exiting the program. It makes sense, imo, to make that the first item on the list.
I need help with getting datapoints, x and y values from a txt file into two arrays.
Currently, the text file consists of 5 lines like:
0.116
0.118
0.12
0.122
0.124
This is my code:
#include <stdio.h>
#include <stdlib.h>
main(void)
{
FILE *inp; /* pointer to input file */
double item;
int cnt=0,y,d,i;
double array[300],swap;
/* Prepare files for input */
inp = fopen("testdoc.txt", "r");
/* Read each item */
while ( (fscanf(inp, "%lf", &item) == 1) && (!feof(inp)) ) {
array[cnt] = item;
cnt++;
}
for (int i = 0; i < cnt; i++)
{
printf("%lf\n",array[i]);
}
printf("The total number of inputs is %d",cnt);
fclose(inp); /* Close the files */
return (0);
}
This only reads the first half of the file, which are the x values. Of which output is
0.116000
0.118000
0.120000
0.122000
The total number of inputs is 4
However, I want to read a text file and store the values in two different arrays for x and y values.
The new text file will look like this
0.116,-0.84009
0.118,4.862
0.12,-1.0977
0.122,0.22946
0.124,3.3173
How do i go changing my code above to recognize the Y values after "," sign? And to add both into two arrays at once?
I tried compiling your code posted on pastebin and received an error because of a missing bracket in your while statement.
That's an easy fix.
The larger issue is in the condition of the while loop.
fscanf returns the number of input items converted and assigned on each call.
When you modified your code to return two values, the condition in the while loop fscanf(inp, "%lf,%lf", &v1,&v2) == 1 would fail and the loop will not be entered.
Please modify the while statement to (have included the missing "(" too)..
while ( (fscanf(inp, "%lf, %lf", &v1, &v2) == 2) && (!feof(inp)) )
and you should be good to go!!!
In addition it would be a good practice to include the return type of int for the main function.
The two functions are about 200 lines since its a bunch of case statements (and they do work properly) so instead of showing I'll just explain what it does. I am currently creating a game similar to checkers.
Function 1: Checks if user input a valid move. If they did not then it would print out "invalid move".
Function 2: Updates the piece that has been moved on the board and displays the new updated board.
In the main function I did a while loop so if user input an invalid move, they will be prompted again. It does that but the board would still be updated. For example: if they chose to move piece 1 to a spot that piece 3 is occupying, the board will update: piece 1's spot is now empty even though it printed out "invalid move". I do not know how to stop function 2 if function 1 printed something.
Here is what I put in the main function.
char pieceToMove, emptySpot;
int moveNumber = 0;
int piecesOnBoard = 15;
while (piecesOnBoard >= 1, ++moveNumber) {
//prompting user input
printf("%d. Enter your move:", moveNumber);
scanf(" %c %c", &pieceToMove, &emptySpot);
checkMoves(pieceToMove, emptySpot, all, the, pieces, ect);
updateBoard(all, the, pieces);
}
Have function 1 return the equivalent of a Boolean value (1 or 0 — true or false, respectively, in C) depending on whether function 1 was successful or if it failed. Check that value before deciding to run function 2 (or not).
One way to do this is define a boolean_t convenience type and kTrue and kFalse values in your header file. These are int values underneath the hood, but this makes code easier to read:
typedef enum boolean {
kFalse = 0,
kTrue
} boolean_t;
In your header file, declare that your first function function_one() will return a boolean_t:
boolean_t function_one(...); /* "..." are the arguments this function takes */
In your implementation file, you write function_one() so that it returns either kTrue or kFalse, depending on whether its work succeeds or fails:
boolean_t function_one(...) {
do_stuff();
if (some_step_fails) {
return kFalse;
}
return kTrue;
}
Again in the implementation file, write the call to function_two() so that it runs only if the return value of function_one() was kTrue:
if (function_one(...) == kTrue) {
function_two();
}
else {
fprintf(stderr, "Error: Something went wrong...\n");
}
This is the output of my program. Even though the conditions have been met, it still does not go out of the loopenter image description here
This is my program. The first while loop asks if the user owns a car.
#include <stdio.h>
#include <conio.h>
#define TRANSPORT 1
int main()
{
char PrivateVehicle;
printf("DRIVING ANF FLYING CARBON FOORPRINT \n");
printf("I. LAND \n");
printf("A. PRIVATE OWNED \n");
while (TRANSPORT==1)
{
do
{
printf("Question 1: \n");
printf("Do you have your own private vehicle? [Y/y]-Yes, [N/n]-No \n");
printf("Note: Only the letters Y, y for yes and N, n for no would be accepted \n");
scanf (" %c", &PrivateVehicle);
if (PrivateVehicle!='Y' && PrivateVehicle!='y' && PrivateVehicle!='N' && PrivateVehicle!='n')
printf("Inavlid \n");
} while (PrivateVehicle!='Y' && PrivateVehicle!='y' && PrivateVehicle!='N' && PrivateVehicle!='n');
if (PrivateVehicle=='Y'|| PrivateVehicle=='y') // should go out of the loop after condition is met
printf("Y/y\n"); //For checking
else if (PrivateVehicle=='N'|| PrivateVehicle=='n') // should go out of the loop after condition is met
printf("N/n\n"); //For checking
TRANSPORT==0;
}
printf("Out"); //For checking
printf("B. PUBLIC TRANSPORT \n");
}
You can't assign to a macro identifier with
TRANSPORT == 0;
(even when "fixing" the == with =). You need to use a variable if you need to change a value of something, e.g. int TRANSPORT = 0; instead of the #define directive.
The reason for the non-terminating loop is that after macro expansion, you have
while (1==1)
which is always true.
The symbol TRANSPORT is a preprocessor macro, it can't be changed at run-time. In fact, in the generated code there is no reference to the TRANSPORT symbol at all, it doesn't exist once the preprocessor replaces it in the code.
TRANSPORT is define as preprocessor macro - you yould change it to be a variable.
Then you'd still need to changehe evaulationTRANSPORT==0; to be an assignment TRANSPORT=0;
You mustn't use #define TRANSPORT 1, but instead int TRANSPORT = 1 or something like that.
The #define creates a macro, which is the association of an identifier
or parameterized identifier with a token string. After the macro is
defined, the compiler can substitute the token string for each
occurrence of the identifier in the source file.
I have a few issues with my syntax, it mainly says i have an errror before "struct" on the line "Struct CustomerInfo s; but i dont seem to find the problem.
My program is supposed to ask what the person would like to do first of all, they can store a record for the first option which is then stored in a structure which can be viewed by selecting the 2nd option of the menu, if they select the 3rd then they obviously quit the program.
any help would be appreciated thank you.
#include <stdio.h>
void menu();
int id,first,last;
struct CustomerInfo
{
char FirstName[15]; /* These are the varibles for the customer infomation */
char LastName[20];
int ID;
};
int main()
{ /* program starts */
int selection = 0;
void menu()
{ /* Menu loop function */
do
{ /* menu start */
printf("\n\n - What would you like to do?");
printf("\n1 - Store a customer record");
printf("\n2 - View customer Records");
printf("\n3 - Quit program");
scanf("%i", &selection);
} while (selection > 3);
printf("You have entered an incorrect value"); /* If selection is greater than 3 then end program */
return 0;
}
switch(selection)
{
/* switch statement starts */
case 1:
struct CustomerInfo s;
printf("Please enter the customers details including First name, Lastname and ID.\n\n");
printf("Enter First name: ");
scanf("%s", s.FirstName); /* Option 1: Asks to enter the customers details to store then loops back to program */
printf("Enter Last name: ");
scanf("%s", s.LastName);
printf("Enter Customer ID: ");
scanf("%s", s.ID);
void menu();
break;
case 2:
printf("\nDisplaying Infomation\n");
printf("First name: %s\n",s.Firstname); /* Option 2: Prints the customer details as listed in option 1 */
printf("Last name: %s\n",s.Lastname);
printf("Customer ID: %s\n",s.ID);
void menu();
break;
case 3: /* Option 3: Program ends if option 3 is chosen. */
break;
}
return 0;
Let's start by looking at the structure you created; next we'll try to see if it can be fixed.
I am leaving details out so we can see the big outline:
main {
struct{}
void menu(){
do {
stuff
} while (selection > 3)
printf("you have entered an incorrect value"); // if selection is > 3
}
switch(selection) {
// do something if selection is 1 or 2, exit if 3
}
There is no final closing brace in your code. I am assuming that's a copy-paste error, so I added it. Compiling with -Wall (to get warnings as well as errors reported), I get a number of errors:
sel.c:18: error: nested functions are disabled, use -fnested-functions to re-enable
sel.c: In function ‘menu’:
sel.c:31: warning: ‘return’ with a value, in function returning void
sel.c: In function ‘main’:
sel.c:38: error: expected expression before ‘struct’
sel.c:41: error: ‘s’ undeclared (first use in this function)
sel.c:41: error: (Each undeclared identifier is reported only once
sel.c:41: error: for each function it appears in.)
sel.c:61: warning: control reaches end of non-void function
Let's take those in turn:
sel.c:18: error: nested functions are disabled, use -fnested-functions to re-enable
Putting one function inside another is "nesting". It is rare that you would want to do that - it means that the function is only "visible" when you are inside the other function (a bit like local variables, but for functions). It is not standard C - it is an extension of gcc. It's almost always a bad idea to use non-standard (and thus non-portable) extensions. See http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
sel.c: In function ‘menu’:
sel.c:31: warning: ‘return’ with a value, in function returning void
When we declare a function void, we say that it will not return a value. When you have a statement like return 0; you ARE returning a value. The compiler will ignore that - but it warns that you said one thing, and did another. Just use return; without a parameter, and the warning goes away.
sel.c:38: error: expected expression before ‘struct’
sel.c:41: error: ‘s’ undeclared (first use in this function)
sel.c:41: error: (Each undeclared identifier is reported only once
sel.c:41: error: for each function it appears in.)
This is the trickiest one. You would expect that you were properly declaring a variable s in line 38 - but the compiler complains. The reason for this is explained in the excellent Q&A at
Why can't variables be declared in a switch statement?
As an aside - if you COULD declare a variable like this - what are you doing with it? Your code currently reads in values, and returns. But as soon as you leave the "scope" of the variable (in your case, since you declared s inside the switch, that would be its scope) the variable disappears (the memory that was used for it is marked "free" and will be re-used.)
sel.c:61: warning: control reaches end of non-void function
This says that you have reached the end of a function that expects to return a value, but you don't have a return someValue; type of statement. Again - this only causes a warning, since the default behavior is to return 0 if no value is given, but it's a sign that you said one thing and did another.
So far I've just explained the errors that the compiler gave. Let's look more closely at the code structure. What I think you want to do is something like this:
define customerInfo structure
define menu function
main()
repeat:
call menu, get selection
switch(selection):
case 1: create new record
case 2: display records
case 3: quit program
In order to make this work, we need to make some changes to your program. First - let's move the menu function definition outside of the main function so we have portable code. Second - if we want to be able to create multiple customer records, we need to store them in an array. Really you would want a list so you can extend indefinitely, but let's keep it simple and allow a maximum of 10 records. Then we need to improve the logic of the menu function (if selection is not 1, 2 or 3 you give a message and try again; in your current code the line
printf("You have entered an incorrect value");
doesn't get executed until you have exited the loop that tested for incorrect values… so when you finally get there, the value is valid, not invalid.
Before we actually get to writing the "correct" code, there's another thing worth noting. When you read values using scanf, you do things like:
scanf("%s", s.FirstName);
which is correct, since s.FirstName is a pointer to the start of a string. However, you allocated a finite amount of space to your string (namely, 15 characters including the terminating '\0') so if someone enters a long name, your program will crash. "Good defensive coding" demands that you catch this - use for example
scanf("%14s", s.FirstName);
This says "read no more than 14 characters". There are better tricks but at least this is a start. However, you actually make a mistake when you do
scanf("%s", s.ID);
Since ID was defined as an int, and now you are reading a string into… not just its address, but into some location that is pointed to by the value of s.ID . This is very likely to give you a segmentation error (accessing memory that "isn't yours"). You should be doing:
scanf("%d", &s.ID);
"Read an integer into the location of s.ID"
Also - in some places you use FirstName, while in others you use Firstname. Ditto LastName. Capitalization matters - when you fix other compiler errors, these will start to show up.
Since you seem to want to be able to read in more than one customer record, we need an array of records; as I said above, we have to make sure the array is available in the scope of the switch statement, and "survives" that statement (so you can do something with it). Taking all these things together gets us to something like this:
#include <stdio.h>
// define function prototype:
int menu();
struct CustomerInfo
{
char FirstName[15]; /* These are the variables for the customer infomation */
char LastName[20];
int ID;
};
int menu()
{ /* Menu loop function */
int flag = 0;
int selection;
do
{ /* menu start */
if(flag > 0) printf("You have entered an incorrect value"); /* If selection is greater than 3 then end program */
printf("\n\n - What would you like to do?");
printf("\n1 - Store a customer record");
printf("\n2 - View customer Records");
printf("\n3 - Quit program\n>> ");
scanf("%i", &selection);
flag++;
} while (flag < 10 && (selection < 0 ||selection > 3));
return selection;
}
int main(void)
{ /* program starts */
struct CustomerInfo s[10];
int selection;
int customerCount = 0;
while(1) {
int ii; // loop counter we will need later
selection = menu();
switch(selection)
{
case 1:
printf("Please enter the customers details including First name, Lastname and ID.\n\n");
printf("Enter First name: ");
scanf("%s", s[customerCount].FirstName); /* Option 1: Asks to enter the customers details to store then loops back to program */
printf("Enter Last name: ");
scanf("%s", s[customerCount].LastName);
printf("Enter Customer ID: ");
scanf("%d", &s[customerCount].ID);
customerCount++;
break;
case 2:
printf("\nDisplaying Infomation\n");
for(ii = 0; ii < customerCount; ii++) {
printf("First name: %s\n",s[ii].FirstName); /* Option 2: Prints the customer details as listed in option 1 */
printf("Last name: %s\n",s[ii].LastName);
printf("Customer ID: %d\n---\n",s[ii].ID);
}
break;
case 3: /* Option 3: Program ends if option 3 is chosen. */
return 0; // program returns
break;
}
}
}
Test output:
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 1
Please enter the customers details including First name, Lastname and ID.
Enter First name: John
Enter Last name: Smith
Enter Customer ID: 123
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 5
You have entered an incorrect value
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> -1
You have entered an incorrect value
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 1
Please enter the customers details including First name, Lastname and ID.
Enter First name: Harry
Enter Last name: Jones
Enter Customer ID: 654
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 2
Displaying Infomation
First name: John
Last name: Smith
Customer ID: 123
---
First name: Harry
Last name: Jones
Customer ID: 654
---
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 3