I am trying to make a while - do loop to exit when the user types "exit" or "quit". For some reason that I can not understand, I simply can not make it happen. If I apply one of these conditions separately it works just fine, but I need to have both conditions simultaneously.
I searched online and I found several examples even on different programming languages, for example, (PHP) Do-While Loop with Multiple Conditions, (Python) How to do while loops with multiple conditions, (C++) Using multiple conditions in a do…while loop, etc. But no matter what procedure I am following I can make it work with both conditions simultaneously.
The ideal solution would be do add uppercase conditions also, but I can work with that later on as soon as I solve this problem.
Maybe a fresh pair of eyes see something that I am missing.
Sample of code is given below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHARACTERS 250
#define MAX_USERNAME 12
#define MAX_USERS 1024
#define MIN_REQUIRED 3
#define MAX_PORT 65536
#define MIN_PORT 1
typedef struct rec {
char username[MAX_USERNAME];
char msg[MAX_CHARACTERS];
}RECORD;
/* Usage Instructions void because we do not have any return */
int help(void) {
printf("Usage: test.c [-s <arg0>] [-s <arg1>]\n");
printf("\t-s: a string program name <arg0>\n");
printf("\t-s: a string with a Nickname maximum characters %i <arg2>\n",MAX_USERNAME);
return (1);
}
int main(int argc, char **argv) {
if ( argc < MIN_REQUIRED ) {
printf ("Please follow the instructions: not less than %i argument inputs\n", MIN_REQUIRED);
return help();
}
else if ( argc > MIN_REQUIRED ) {
printf ("Please follow the instructions: not more than %i argument inputs\n", MIN_REQUIRED);
return help();
}
else {
RECORD *ptr_record;
ptr_record = (RECORD *) malloc (sizeof(RECORD));
if (ptr_record == NULL) {
printf("Out of memory!\nExit!\n");
exit(0);
}
char username_argv[MAX_USERNAME];
memset( username_argv, '\0', sizeof(username_argv) );
if (strlen(argv[2]) > 12 ) {
printf("Maximum characters for Nickname: %i\nPlease try again!\n", MAX_USERNAME);
exit(0);
}
strcpy( username_argv, argv[1] );
strncpy( (*ptr_record).username, username_argv, sizeof(username_argv) );
printf("Username pointer: %s\n", (*ptr_record).username);
do {
printf("Please enter your MSG: \n");
scanf ("%s", (*ptr_record).msg);
printf("User MSG: %s\n", (*ptr_record).msg);
//} while ((strcmp((*ptr_record).msg,"exit") != 0) || (strcmp((*ptr_record).msg, "quit") != 0));
//} while (strcmp((*ptr_record).msg, "exit") || strcmp((*ptr_record).msg, "quit") != 0);
//} while ((strcmp((*ptr_record).msg,"exit")) || (strcmp((*ptr_record).msg, "quit")) != 0);
//} while ((*ptr_record).msg != "quit" || (*ptr_record).msg != "exit");
} while (((*ptr_record).msg != exit) || ((*ptr_record).msg != ));
free(ptr_record);
return 0;
} /* End of else */
} /* End of main() */
Try:
} while ((strcmp((*ptr_record).msg,"exit") != 0) &&
(strcmp((*ptr_record).msg,"quit") != 0));
You want NOT (A OR B), not NOT A OR NOT B. Remember De Morgan's laws that say that NOT (A OR B) is the same as NOT A AND NOT B.
Using || is wrong as you will always have at least one condition (operand of ||) or another to be true.
Imagine you string is "exit" then:
(strcmp((*ptr_record).msg,"exit") != 0)
is false
but
(strcmp((*ptr_record).msg,"quit") != 0)
is true.
It means 0 || 1 which yields 1. Same (in the opposite) for the "quit" string (1 || 0 which yields 1). For other strings, both operand of || will be 1 and 1 || 1 yields 1.
It doesn't work, because you want to do the loop while the string is different from "exit" and the string is different from "quit".
If you use an OR, the condition will always be true, because the string can't have both values at the same time.
do {
printf("Please enter your MSG:\n");
scanf ("%s", (*ptr_record).msg);
printf("User MSG: %s\n", (*ptr_record).msg);
} while ((strcmp((*ptr_record).msg, "exit") != 0) && (strcmp((*ptr_record).msg, "quit") != 0));
All of the lines in your example use the logical OR operator || to test both conditions. Try to use the logical AND operator, &&, instead.
The problem with OR is that the way you've got it set up, the condition will always pass, so the application will never quit. If the user typed "quit", then the condition passes because he/she didn't type "exit". Likewise, if the user typed "exit", then he/she didn't type "quit", so the condition still passes. And, of course, if he/she didn't type either one, then the condition passes. That doesn't leave you with any way out of the loop.
Try out this. You should use the && operator because both the conditions need to be true to continue.
do {
printf("Please enter your MSG: \n");
scanf ("%s", (*ptr_record).msg);
printf("User MSG: %s\n", (*ptr_record).msg);
} while (((*ptr_record).msg != "exit") && ((*ptr_record).msg != "quit"));
Related
I have been working on a program that will check the eligibility of a password.
In order for password to be eligible it needs to have at least: one uppercase letter; one number; and one dollar sign.
My program does the work checking for the requirements and determining whether the password is good to go or not.
The barrier I'm having right now is that I've tried to make program run until:
User quits the program by typing "quit";
Or if user types the correct form of required password.
In order to run such a repetitive process I have decided to use the do-while loop. In order for program to determine that it is time to break out, I have used the following command:
do {...} while (passwordInput != "quit" || passwordClearance != 1);
Unfortunately my program still runs even if the password was correct.
Please give me a clue how do I break out from repetitive process when it is good to go.
// challenge:
// build a program that checks when user enters a password for an uppercase letter, a number, and a dollar sign.
// if it does output that password is good to go.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char passwordInput[50];
int digitCount = 0;
int upperCharacterCount = 0;
int dollarCount = 0;
int passwordClearance = 0;
do {
printf("Enter you password:\n");
scanf(" %s", passwordInput);
for (int i = 0; i < strlen(passwordInput); i++) {
if (isdigit(passwordInput[i])) {
digitCount++;
//continue;
} else
if (isupper(passwordInput[i])) {
upperCharacterCount++;
//continue;
} else
if (passwordInput[i] == '$') {
dollarCount++;
//continue;
}
}
if ((dollarCount == 0) || (upperCharacterCount == 0) || (digitCount == 0)) {
printf("Your entered password does not contain required parameters. Work on it!\n");
} else {
printf("Your entered password is good to go!\n");
passwordClearance = 1;
}
} while (passwordInput != "quit" || passwordClearance != 1);
return 0;
}
In order for program to determine that it is time to break out, I have
used the following command:
do{...} while(passwordInput != "quit" || passwordClearance != 1);
Unfortunately my program still runs even if the password was correct.
There are two problems with that:
The logic is wrong. The while expression evaluates to true, causing the loop to cycle, if either of the component relational expressions evaluates to true. Thus, to exit the loop, both must be false. You want && instead of || so that the loop exits if either one of the expressions is false.
passwordInput != "quit" will always evaluate to true because you are comparing two distinct pointers. To compare the contents of array passwordInput to the contents of the array represented by "quit", you sould use the strcmp() function.
You cannot compare strings with passwordInput != "quit", you must use strcmp() and include <string.h>. Also change the test on passwordClearance that seems incorrect:
do {
...
} while (strcmp(passwordInput, "quit") != 0 || passwordClearance != 0);
I am supposed to be "fixing" code given to me to make it display the correct number of visible characters in a file (spaces too). The correct number is supposed to be 977. I have never dealt with files before and I don't understand what I need to do to display the correct number.
* Driver Menu System for Homework
* Andrew Potter - Mar 5, 2019 <-- Please put your name/date here
*/
#include <stdio.h>//header file for input/output -
#include <stdlib.h>
#include <ctype.h>
// since you will place all your assigned functions (programs) in this file, you do not need to include stdio.h again!
int menu(void); //prototype definition section
void hello(void);
void countall(void);
int main(void)
{
int selection = menu();
while(selection != 99) {
switch(selection) {
case 1:
hello();
break;
case 2:
countall();
break;
case 3:
break;
case 4:
break;
default:
printf("Please enter a valid selection.\n");
}
selection = menu();
}
return 0;
}
int menu(void) {
int choice;
printf("***************************\n");
printf(" 1. Hello \n");
printf(" 2. Countall\n");
printf(" 3. \n");
printf(" 4. \n");
printf("99. Exit\n");
printf("Please select number and press enter:\n");
printf("***************************\n");
scanf("%d", &choice);
getchar();
return choice;
}
void hello(void) {
printf("Hello, World!!!\n");
}
//*****Andrew 5/1/19*****
#define SLEN 81 /* from reverse.c */
/* original header: int count(argc, *argv[]) */
void countall(void)
{
int ch; // place to store each character as read
FILE *fp; // "file pointer"
long unsigned count = 0;
char file[SLEN]; /* from reverse.c */
/*Checks whether a file name was included when run from the command prompt
* The argument count includes the program file name. A count of 2 indicates
* that an additional parameter was passed
if (argc != 2)
{
printf("Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
* The following uses the second parameter as the file name
* and attempts to open the file
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
} */
/*************************************
Code from reverse.c included to make the program work from within our IDE
*************************************/
puts("Enter the name of the file to be processed:");
scanf("%s", file);
if ((fp = fopen(file,"rb")) == NULL) /* read mode */
{
printf("count program can't open %s\n", file);
exit(EXIT_FAILURE);
}
/* EOF reached when C realizes it tried to reach beyond the end of the file! */
/* This is good design - see page 573 */
while ((ch = getc(fp)) != EOF)
{
if (isprint(ch)) {
count++;
}
else if (isprint(ch)) {
count++;
}
putc(ch,stdout); // same as putchar(ch);
count++;
}
fclose(fp);
printf("\nFile %s has %lu characters\n", file, count);
}
I expected I would get the correct number of visible characters using the combination of isprint and isspace but I usually get 2086.
The assignment directions are: "Word identifies 977 characters including spaces. Your current countall() believes there are 1043. Make the corrections necessary to your code to count only the visible characters and spaces! (Hint: check out 567 in your textbook.)" Before I edited any code the count was 1043, now i am getting 2020. I need 977.
isprint() returns a Boolean result - zero if the character is not "printable", and non-zero if it is. As such isprint(ch) != '\n'makes no sense. Your complete expression in the question makes even less sense, but I'll come on to that at the end.
isprint() on its own returns true (non-zero) for all printable characters, so you need no other tests. Moreover you increment count unconditionally and in every conditional block, so you are counting every character and some twice.
You just need:
if( isprint(ch) )
{
count++;
}
putc( ch, stdout ) ;
While your code is clearly an incomplete fragment, it is not clear where or how your are reading ch. You need a getc() or equivalent in there somewhare.
while( (ch = getc(fp)) != EOF )
{
if( isprint(ch) )
{
count++;
}
putc( ch, stdout ) ;
}
It is not clear whether you need to count all whitespace (including space, tab and newline) or just "spaces" as you stated. If so be clear that isprint() will match space, but not control characters newline or tab. isspace() matches all these, but should not be counted separately to isprint() because 'space' is in both white-space and printable sets. If newline and tab are to be counted (and less likely; "vertical tab") then:
while( (ch = getc(fp)) != EOF )
{
if( isprint(ch) || isspace(ch) )
{
count++;
}
putc( ch, stdout ) ;
}
Another aspect of C that you seem to misunderstand is how Boolean expressions work. To test a single variable for multiple values you must write:
if( var == x || var == y || var == z )
You have written:
if( var == x || y || z )
which may make sense in English (or other natural language) when you read it out aloud, but in C it means:
if( var == (x || y || z ) )
evaluating (x || y || z ) as either true or false and comparing it to var.
It is probably worth considering the semantics of your existing solution to show why it actually compiles, but produces the erroneous result it does.
Firstly,
isprint(ch) != '\n' || '\t' || '\0'
is equivalent to isprint(ch) != true, for the reasons described earlier. So you increment the counter for all characters that are not printable.
Then here:
isspace(ch) == NULL
NULL is a macro representing an invalid pointer, and isspace() does not return a pointer. However NULL will implicitly cast to zero (or false). So here you increment the counter for all printable characters that are not spaces.
Finally, you unconditionally count every character here:
putc(ch,stdout); // same as putchar(ch);
count++;
So your result will be:
number-of-non-printing-characters +
number-of-printing-characters - number-of-spaces +
total-number-of-characters
which is I think (2 x file-length) - number-of-spaces
Finally note that if you open a text file that has CR+LF line ends (conventional for text files on Windows) in "binary" mode, isspace() will count two characters for every new-line. Be sure to open in "text" mode (regardless of the platform).
From isprint():
A printable character is a character that occupies a printing position on a display (this is the opposite of a control character, checked with iscntrl).
and
A value different from zero (i.e., true) if indeed c is a printable character. Zero (i.e., false) otherwise.
So that function should be sufficient. Please note that you have to make sure to feed all these is...() functions from <ctype.h> unsigned values. So if you use it with a value of uncertain origin, better cast to char unsigned.
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char const *filename = "test.txt";
FILE *input = fopen(filename, "r");
if (!input) {
fprintf(stderr, "Couldn't open \"%s\" for reading. :(\n\n", filename);
return EXIT_FAILURE;
}
long long unsigned count = 0;
for (int ch; (ch = fgetc(input)) != EOF;) {
if (isprint(ch))
++count;
}
fclose(input);
printf("Count: %llu\n\n", count);
}
If I wasn't lucky enough to guess which characters you want to be counted, have a look at ctype.h, there is a table.
if ((ch == '\t') || isprint(ch))
count++;
If you want to handle tabs differently (maybe to count how many spaces they use):
if (ch == '\t') {
/* Do smth */
} else if (isprint(ch)) {
count++;
}
This should be enough.
This is my code.The user enters a string and if the input is 1,2 or * it displays error.The problem is that the condition is satisfied for all the numbers of which the first digits are 1,2 amd 3.(11,12,22...).I used also strlen and sizeof function to count the digits and create a condition that works but when i printed strlen the output was 1 for every number.
I don't understand if the problem is my multiple conditions or the use of scanf
Here is my code
#include < stdio.h >
int main (void)
{
char choice;
int i=0;
do
{
scanf("%s", &choice);
while(choice !='1' && choice !='2' && choice !='*' )
{
printf("error");
scanf("%s",&choice);
}
}while (choice !='0');
return 0;
}
I would be very thankful for any help. I am quite new in programming, so forgive me if the question is stupid.
I propose you the following code:
#include <stdio.h>
#include <string.h>
int main (void)
{
char choice[201];
do
{
scanf("%200s", choice);
if (strcmp(choice, "1") == 0 ||
strcmp(choice, "2") == 0 ||
strcmp(choice, "3") == 0)
printf("error");
} while (strcmp(choice, "0") != 0);
return 0;
}
%s waits for a char * argument, your &choice was right, but scanf will write a whole string at the address pointed to, which can (will) contain more than one char. By giving the address of a char variable, you provided it with the room for only one char.
You can't compare strings with a comparison operator, you have to use, for example, the strcmp function, which returns 0 if it's two argument do match and non-zero otherwise.
If I properly understood your intent, there is no need for two nested while loop. The two scanf calls aren't needed either.
The 200 in the %200s scanf format string, limits the number of chars which will be written in the array you have provided the address of.
This array is of size 201 to account for the extra '\0' byte, terminating C strings.
To write properly this code, one should test the return of scanf, to check if something has been parsed with success.
Please refer to the man page of scanf to see how to check if the parsing went successfully.
You've declared choice as a char object - it's only large enough to store a single character value. If you're entering a string like "123" on input, only the leading '1' is stored to choice and the remaining input is written to memory immediately following choice, which may cause a runtime error if you clobber anything important.
If you want to read and store the input as a string of characters, then you need to declare choice as an array of char, sized to hold at least one more character than the maximum input size - IOW, if you expect the maximum string to be 3 characters long, then choice must be declared as char choice[4];.
If you want to read and store the input as an integer, then you must declare choice as int instead of char, and you need to use the %d conversion specifier instead of %s.
Consider using fgets to obtain input, then parse with sscanf. Using int choice allows you to distinguish between 1 and 11...
#include <stdio.h>
int main( void) {
char input[99] = "";
int choice = 0;
do {
printf ( "Enter 0 to quit\n");
if ( fgets ( input, sizeof input, stdin)) {
if ( 1 == sscanf ( input, "%d", &choice)) {
if ( choice == 1 || choice == 2 || choice == 3) {
printf ( "error\n");
}
else {
printf ( "you entered %d\n", choice);
}
}
else {
if ( 0 == strcmp ( input, "*\n")) {
printf ( "error\n");
}
//sscanf could not parse an int
choice = -1;
}
}
else {
break;// fgets failed
}
} while ( choice != 0);
return 0;
}
the following proposed code:
cleanly compiles
only calls scanf() once per each outer loop
prompts the user for the desired input
and now the code:
#include <stdio.h> // scanf(), printf(), perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
int main (void)
{
char choice;
do
{
printf( "enter 0:" );
if( 1 != scanf(" %c", &choice) )
{
perror( "scanf failed" ); // to stderr:
// enclosed text + reason OS thinks it failed
exit( EXIT_FAILURE ); // once failed, it will continue to fail
// so exit program with error indication
}
// implied else, scanf successful
// what about other user inputs?
if(choice !='1' && choice !='2' && choice !='*' )
{
printf("error\n"); // trailing '\n'
// so immediately displayed on terminal
// note: should use: 'fprintf( stderr, ... )'
// because error messages should
// be output to 'stderr', not 'stdout'
}
} while (choice !='0');
return 0;
} // end function: main
I am writing a program for fun (not for school), and am having a hard time figuring out why the scanf function isn't executing on every iteration of my loop - I've toyed with both 'for' loops and 'while' loops.
I know that depending on how I write the scanf function (i.e. scanf("%s", &variablename); VS scanf("%99[^\n]s", &variablename);) makes a difference, but I have tried everything and I'm desperate!
When I do a printf check on my input from the scanf, on every iteration it is only intaking one string per iteration, so if I enter two words in my first input, then it takes two iterations to process - one word per. Here is the segment of code I'm describing:
int main(void){
int tries = 0;
int score = 0;
char question[100];
char useranswer[100];
const char *phrase = {"our favorite saying\0"};
printf("\nQuestion #3 (10 points): What is our secret saying?\n");
sleep(1);
tries = 1;
while (tries<=3){
printf("YOUR ANSWER:");
scanf("%s[^\n]", useranswer);
if(strncmp(useranswer, phrase, 15) != 0){
printf ("Nope, try again!\n");
printf("You have used %d out of 3 tries!\n", tries);
if (tries == 2){
printf("Here's your final hint:xxx...\n");
}
if (tries == 3){
printf("You didn't get it. The answer is: our favorite saying!\n");
}
tries++;
}
if (strncmp(useranswer, phrase, 15) == 0){
printf("Damn, you're good. Well done.\n");
score += 10;
break;
}
}
The output of this code is:
Question #3 (10 points): What is our secret saying?
YOUR ANSWER:our favorite saying
Nope, try again!
You have used 1 out of 3 tries!
YOUR ANSWER:Nope, try again!
You have used 2 out of 3 tries!
Here's your final hint:xxx...
YOUR ANSWER:Nope, try again!
You have used 3 out of 3 tries!
You didn't get it. The answer is: our favorite saying!
(It only allowed me to input once, and I typed "our favorite saying".)
In comments you could find why your format specifier in scanf doesn't work.
An alternative is to use fgets instead, maybe in an helper function which takes care of some of the corner cases that can arise while reading user input:
#include <ctype.h>
char *read_line( char *buf, size_t n, FILE *pfin )
{
ssize_t length = 0;
int ch;
if ( !buf || n == 0 )
return NULL;
/* Consume trailing control characters, like '\0','\n', '\r', '\f'...
but also '\t'. Note that ' ' is not skipped. */
while ( (ch = fgetc(pfin)) != EOF && iscntrl(ch) ) { }
if ( ch == EOF )
return NULL;
/* At least one char is printable */
*buf = ch;
++length;
/* Read from file till a newline or up to n-2 chars. The remaining chars
are left in the stream buffer. Return NULL if no char is read. */
if ( fgets(buf + 1, n - 1, pfin) )
{
/* Trim the string to the first control character */
while ( !iscntrl(buf[length]) )
{
++length;
}
buf[length] = '\0';
}
return buf;
}
I'd change the following logic too. OP uses strncmp(useranswer, phrase, 15) multiple times, but that magic number 15 is lower then phrase's size so it ends up comparing only a substring.
while ( tries <= 3 ) {
printf("YOUR ANSWER:");
if ( !read_line(useranswer, sizeof useranswer, stdin) ) {
printf("Error: Unexpected end of input.\n");
exit(EXIT_FAILURE);
}
if( strcmp(useranswer, phrase) == 0 ) {
printf("Damn, you're good. Well done.\n");
score += 10;
break;
} else {
printf ("Nope, try again!\n");
printf("You have used %d out of 3 tries!\n", tries);
if (tries == 2) {
printf("Here's your final hint:xxx...\n");
}
if (tries == 3) {
printf("You didn't get it. The answer is: our favorite saying!\n");
}
tries++;
}
}
As a final note, I found OP declaration of phrase a bit weird (maybe a typo):
const char *phrase = {"our favorite saying\0"};
// string literals are already ^^ null terminated...
While we can use a simple array declaration, like:
const char phrase[] = "our favorite saying";
Consider also what values sizeof phrase returns in those two different cases.
Thanks to #chux for all the valuable hints and the interesting links provided:
https://stackoverflow.com/a/27729970/4944425
https://stackoverflow.com/a/28462221/4944425
And to #Dmitri for having pointed out in his comment that once we are sure that both the strings are null terminated, we can use strcmp instead of strncmp.
Here is my code:
#include "game.h"
#define LINEINPUT 30
int loadMainMenu(void);
void playGame()
{
Cell board[BOARD_HEIGHT][BOARD_WIDTH];
char input[LINEINPUT + EXTRA_SPACES];
printInstructions();
while( getchar() != '\n' );
initialiseBoard(board);
while(TRUE)
{
displayBoard(board, NULL);
printf("At this stage of the program, only two commands are acceptable:\n");
printf("load <g>\n");
printf("quit\n");
fgets(input, LINEINPUT , stdin);
if(input[strlen(input) - 1] != '\n')
{
printf("BUFFER OVERFLOW\n");
readRestOfLine();
EXIT_FAILURE;
continue;
}
if(strcmp(input, "test") == 0)
{
printf("success!\n");
continue;
}
if(strcmp(input, "load 1") == 0)
{
printf("lfdsfsdfoad");
loadBoard(board, BOARD_1);
continue;
}
if(strcmp(input, "load 2") == 0)
{
loadBoard(board, BOARD_2);
continue;
}
if(strcmp(input, "quit") == 0)
{
loadMainMenu();
break;
}
}
}
i have cut it down so that it doesn't take up too much space. I was editing some of it this morning trying to fix things up and somehow, it doesnt read my inputs anymore. Well it does read my inputs but doesnt use strcmp to check if input matches and run the functions in the if statements. It was working fine previously but i did not change anything much.
As evidenced by your first if statement, fgets() returns strings with the \n line ending present. You'll want to either strip off that character, or add it to the strings you're testing against.