I am facing some problem here. Whenever I run this code it asks me about name and date of birth. When I give it, it asks me again until I press Ctrl+D. I want this process to be stop after one time and instead it asks me, do you want to continue? If I say yes then it repeat the loop and again ask me one more time. How to do this? I tried but failed.
int main(void){
const char *listing[] = {"Name", "Date of birth"};
char data[2][51];
int done = 0;
FILE *fp;
fp = fopen("/home/bilal/Documents/file.txt", "w+");
while (!done){
for (int i = 0; i < 2; i++){
printf("Enter your %s: ", listing[i]);
if (scanf(" %50[^\n]", data[i]) != 1){
done = 1;
break;
}
}
if (!done){
fprintf(fp, "%s %s\n", data[0], data[1]);
}
}
fclose(fp);
return 0;
}
If I'm interpreting your post correctly, after the first prompt for name and [then] DOB, you want to inject a "Shall I continue?" question.
Here's the refactored code:
#include <stdio.h>
int
domore(void)
{
char buf[51];
int moreflg = -1;
while (moreflg < 0) {
printf("Shall I continue (y/n)? ");
if (scanf(" %50[^\n]", buf) != 1)
break;
switch (buf[0]) {
case 'y':
case 'Y':
moreflg = 1;
break;
case 'n':
case 'N':
moreflg = 0;
break;
}
}
if (moreflg < 0)
moreflg = 0;
return moreflg;
}
int
main(void)
{
const char *listing[] = { "Name", "Date of birth" };
char data[2][51];
int done = 0;
int again = 0;
FILE *fp;
#if 0
fp = fopen("/home/bilal/Documents/file.txt", "w+");
#else
fp = fopen("/tmp/file.txt", "w+");
#endif
while (!done) {
if (again) {
if (! domore())
break;
}
again = 1;
for (int i = 0; i < 2; i++) {
printf("Enter your %s: ", listing[i]);
if (scanf(" %50[^\n]", data[i]) != 1) {
done = 1;
break;
}
}
if (!done) {
fprintf(fp, "%s %s\n", data[0], data[1]);
}
}
fclose(fp);
return 0;
}
scanf() returns the count of parameters successfully matched and formatted, or EOF (-1) in case of an invalid input.
So, the expressions,
char data[1][50]={0};
int val=0;
int count = scanf(" %50[^\n]", data[0]); // 1 parameter to scan and format
will return 1, for a single formatted item.
To get more than 1, you have to scan in, and successfully format more than one item:
count = scanf(" %50[^\n] %d", data[0], &val); //2 parameters to scan and format.
(The return value here will be 2 if successful.)
So, if you change your loop exit criteria to match these expectations, your loop will exit properly.
if (scanf(" %50[^\n]", data[i]) == 1){//now 'done' will be set to true (1)
^^
Edit: Illustrates concepts described above:
(Note, uncomment your file functions, I did not need them for this illustration.)
Program loops until both 'name' and 'date of birth' are captured into a 2D character array. Loop exit criteria uses count of successful, single parameter scanf calls:
int main(void){
const char *listing[] = {"Name", "Date of birth"};
char data[2][51];
int done = 0;
int count = 0;//added to allow visibility of return value of scanf function.
FILE *fp;
//fp = fopen("/home/bilal/Documents/file.txt", "w+");
while (done != 2){
for (int i = 0; i < 2; i++){
printf("Enter your %s: ", listing[i]);
count = scanf(" %50[^\n]", data[i]);
if (count != EOF){
done += count;
// 'break' is not needed here, let the loop leave naturally
}
}
}
if (done == 2)//moved outside of loop because both variables
{ //need to be populated before printing
;//fprintf(fp, "%s %s\n", data[0], data[1]);
}
//fclose(fp);
return 0;
}
The scanf function returns the number of input items success‐fully matched and assigned. So when you type something from the keyboard, the return value of this function is always 1 in your case (you try to input the string, then every character from the keyboard is added to your string).
You can use fgets then compare with the string that content only the enter character "\n" when you want to quit the loop.
printf("Enter your %s: ", listing[i]);
if (strcmp(fgets(data[i], 51, stdin), "\n") == 0){
done = 1;
break;
}
With this code, if you want to quit the while loop, you just have to hit only ENTER.
Related
The program isn't printing after giving me the first chance to guess.
#include <stdio.h>
#include <string.h>
int main() {
char menu;
int c = 0, flag = 0, life = 8;
printf("\nWelcome to Hangman!!!");
printf("\nThis is a game of hangman.");
printf("Player 1 enters a random word and the other has to guess it.");
printf("You get 8 lives in total i.e. you can have a maximum of 8 wrong guesses.");
printf("\n");
printf("Press n for new game\n");
printf("Press q to quit\n");
printf("\n");
scanf("%c", &menu);
int i = 0, j = 0;
char w[20], ch;
if (menu == 'q') {
printf("Exiting...");
printf("Thanks for playing");
}
else if (menu == 'n') {
printf("Player 1 enters a word\n");
scanf("%s", w);
int len = strlen(w);
for (int i = 0; i < len; i++) {
toupper(w[i]);
}
printf("\e[1;1H\e[2J");
char arr[len - 1];
for (int i = 0; i < len - 1; i++) {
arr[i] = '_';
printf("%c", arr[i]);
}
printf("\n");
while (life != 0) {
for (int i = 0; i < len - 1; i++) {
if (arr[i] == '_') {
flag = 1;
break;
}
else {
flag = 0;
}
}
if (flag == 0) {
printf("You Won!!\n");
printf("You Guessed The Word: %s", w);
break;
}
else {
char ans;
printf("Enter a letter between A-Z");
scanf("%c", ans);
toupper(ans);
for (int j = 0; j < len; j++) {
if (ans == w[j]) {
arr[j] = ans;
c++;
}
}
if (c == 0) {
life--;
}
c = 0;
for (int j = 0; j < len; j++) {
printf("%c", arr[j]);
}
printf("\n Lives Remaining= %d \n", life);
}
}
if (life == 0) {
printf("\n You Lost!!! \n");
printf("The Word Was: %s", w);
}
}
else {
printf("Invalid Character");
}
}
Output:
Welcome to Hangman!!!
This is a game of hangman.Player 1 enters a random word and the other has to >guess it.You get 8 lives in total i.e. you can have a maximum of 8 wrong >guesses.
Press n for new game
Press q to quit
n
Player 1 enters a word
Hello
Enter a letter between A-Z
PS C:\Users\arora\Desktop\Programs\C>
There are quite a few problems with your program. Here are the major ones:
You want to use use space prefix in the format string for scanf(" %c", ...) to ensure previous newlines are ignored.
scanf("%c", ans); should be &ans. It causes scanf() to fail rendering the remain of the program non-interactive. Without input from the user the core game logic doesn't work.
Here are some of the other issues:
#include <ctype.h>.
(not fixed) Consider changing the menu logic so 'q' quits, and any other letter starts a game.
Game prompt contains long lines that are hard to read for the player(s).
You use a printf() per line which makes it hard to read. Use a single call and multi-line strings as input.
Try to branch your code less by making use of early return. It makes it easier to read.
Check the return value of scanf(). If it fails then whatever variable it read doesn't have a well defined value.
Ensure that scanf() read no more than 19 bytes into a 20 byte array w. It takes a little macro magic to generate the 19 so I didn't make this change but it's a good idea to #define constants for magic values like the 20.
arr is not \0 terminated (len-1). Most c programmers expect a string so it's not worth the confusion to save 1 byte.
Use a function or macro for the ANSI escape to clear the screen.
Eliminate unused variables i, j.
Reduce scope of variables (declare variables close to where you use them).
The calculation of the flag variable is cumbersome.
(not fixed) The prompt "Enter a letter between A-Z" is somewhat ambiguous. Suggest "... between A and Z".
It's generally a good idea to leave user input as you read. If you care about the repeated toupper() you can create a copy of the user input with letters in upper case, and create another variable to hold the upper case version of the player's guess. This avoid you saying things like you entered the word "BOB" when the actual input was "bob".
You attempt to use toupper() to convert each letter to upper case but don't assign the result to anything so it does not do anything constructive.
Consider some functions to document what each your code does. I added some comments for now.
(mostly not fixed) Consider using better variable names (c, w, arr, flag).
(not fixed) Should you reject a word with your magic '_' value? In general should you validate that the word is reasonable (a-z, len > 0, len < 20)?
(not fixed) Consider, in arr, just storing if a letter was correctly guess (boolean). When evaluating the state show the letter from w if it is already guessed otherwise the _.
(not fixed) If you guess a correct letter again, it's considered a good guess. Should it?
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define clear() printf("\e[1;1H\e[2J")
int main() {
printf(
"Welcome to Hangman!!!\n"
"\n"
"This is a game of hangman.\n"
"Player 1 enters a random word and the other has to guess it.\n"
"You get 8 lives in total i.e. you can have a maximum of 8 wrong guesses.\n"
"\n"
"Press n for new game\n"
"Press q to quit\n"
);
char menu;
if(scanf(" %c",&menu) != 1) {
printf("scanf failed\n");
return 1;
}
switch(menu) {
case 'q':
printf(
"Exiting..."
"Thanks for playing\n"
);
return 0;
case 'n':
break;
default:
printf("Invalid Character");
return 1;
}
printf("Player 1 enters a word\n");
char w[20];
if(scanf("%19s", w) != 1) {
printf("scanf failed\n");
return 1;
}
clear();
char arr[20];
int len=strlen(w);
for(int i=0;i<len;i++) {
arr[i]='_';
}
arr[len] = '\0';
int life=8;
for(;;) {
printf("%d Lives Remaining\n", life);
// read a guess from player
for(int i = 0; i < len; i++) {
printf("%c", arr[i]);
}
printf(" Enter a letter between A-Z ");
char guess;
if(scanf(" %c", &guess) != 1) {
printf("scanf failed\n");
return 1;
}
// determine if any of the letters are in the secret word
int c = 0;
for(int i=0; i<len; i++) {
if(toupper(guess) == toupper(w[i])) {
arr[i]=guess;
c = 1;
}
}
if(c==0) {
life--;
}
// game over?
int flag = 0;
for(int i = 0; i<len; i++) {
if(arr[i]=='_') {
flag=1;
break;
}
}
if(flag==0) {
printf("You Won!!\n");
printf("You Guessed The Word: %s\n",w);
break;
}
if(life==0) {
printf("\n You Lost!!!\n");
printf("The Word Was: %s\n", w);
break;
}
}
}
I am trying to count the occurrence of character for a string.
The user has two options:
first, display the result of screen
second, to store the result in a file but the file name will be a string enter also by user
My real problem is that when in comes to scan the name of the file, it does not work.
The part of my code where count[] has integer number represents the occurrence of each character. When I tryed to debug the code it seems like scan step of out[] string array was skipped, and it got uncommon characters like ÿÿtþa.
printf("Enter 1 if you want to output data on screen\nEnter 2 to output data to file : ");
int input;
scanf("%d", &input);
if(input == 1)
{
fprintf(stdout,"%s:\n\"%s\"\n", "characters count in this string", s);
fprintf( stdout, "%-20s%-4s\n", "character", "count");
for(int j = 0; j < 26; j++)
fprintf( stdout, "%-20c%-4d\n", j+65, count[j]);
}//end of if
else if(input == 2)
{
FILE *Ptr;
printf("enter file name : ");
char out[30]= {'\0'};
scanf("%29[^\n]", out);
if( (Ptr = fopen(out,"w")) == NULL)
printf("CAN NOT OPEN FILE\n");
else
{
fprintf(Ptr,"%s:\n\"%s\"\n", "characters count in this string", s);
fprintf( Ptr, "%-20s%-4s\n", "character", "count");
for(int j = 0; j < 26; j++)
fprintf( Ptr, "%-20c%-4d\n", j+65, count[j]);
}//end of else
fclose(Ptr);
}//end of else
}//end of main
While doing some practice for an upcoming assignment I ran into a problem using fscanf and trying to throw a notice when the incorrect format is entered into the program. I'm pretty sure I have to use the return of fscanf, but can't figure out how to use it inside my while loop. Currently the program loops continuously when a value such as "a3" is entered, yet "3e" works almost fine, except it outputs the number 3 twice.
Working scanf code:
int intGet( int min, int max ) {
int input = 0;
char temp = ' ';
printf("Enter a number in between [%d-%d]: ", min, max);
if (scanf("%d%c", &input, &temp) != 2){
errorNo = 1;
return EXIT_FAILURE;
}
if (temp != '\n'){
errorNo = 2;
return EXIT_FAILURE;
}
if (input < min || input > max){
errorNo = 3;
return EXIT_FAILURE;
}
else {
printf("Read %d\n", input);
}
return EXIT_SUCCESS;
fscanf code along the same idea, which loops continuously:
int intGet( int min, int max ) {
int counterValid = 0;
int counterInvalid = 0;
int entry = 0;
int total = 0;
int input = 0;
int check = 0;
char temp = ' ';
FILE *fp;
fp = fopen("02_num.txt", "r");
if (!fp)
{
perror("fopen()");
exit(EXIT_FAILURE);
}
printf("----------------------------------------------------------\n");
printf("Entry\tInvalid\tValid\tNumber\n");
printf("----------------------------------------------------------\n");
fscanf(fp, "%*[^\n]\n"); //skips first line (min and max)
while (check != EOF){
check = fscanf(fp, "%d%c", &input, &temp);
if (check == EOF){
exit(EXIT_SUCCESS);
}
if (check != 2){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tIncorrect Format\n", entry, input);
}
if (temp != '\n'){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tExtra Characters\n", entry, input);
}
if (input < min || input > max){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tInput Number out of Range\n", entry, input);
}
else{
counterValid += 1;
entry +=1;
total += input;
printf("%d\t\t*\t%d\n", entry, input);
}
}
printf("----------------------------------------------------------\n");
entry +=1;
printf("%d\t%d\t%d\t%d\n", entry, counterInvalid, counterValid, total);
return EXIT_SUCCESS;
}
This code will then output a table that looks something like this:
*****************************************************
Entry Invalid Valid Number
1 * 32
*****************************************************
// adds invalid and valid entry totals, displays then here, adds totals of valid numbers and also outputs them here.
02_num.txt file that was being used in this code, first two numbers are the min and max, read in another function.
1 15 //min and max
23
45
67
8990
3e
12
a3
Things I have tried to work with the if/while loop:
Defining a variable to record the return value of fscanf (currently the closest):
while (check != EOF){
check = fscanf(fp, "%d%c", &input, &temp);
if (check != 2){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tIncorrect Format\n", entry, input);
}
Checking the return value in the if statement as well (scans the file twice and doesn't output properly):
while (fscanf(fp, "%d", &input) != EOF){
if (fscanf(fp, "%d%c", &input, &temp) != 2){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tIncorrect Format\n", entry, input);
}
If there is any information I am missing please let me know, i'm just a bit stuck here.. have been for the past couple days. Probably just a stupid mistake i'm missing but thanks in advance!
The problem with the loop is what you do when fscanf returns zero. Among other things, it means that if you call fscanf again with the same format string, the result is going to be zero, because the problem in the input that lead to you getting zero in the first place has not been addressed.
You need to add code for skipping the line when you get zero back from fscanf - for example, your fscanf(fp, "%*[^\n]"); fscanf(fp, "%*1[\n]");, as modified by Jonathan Leffler and chux, will work.
I'm really new to C so it would be great if someone could tell me how I can do this:
I am trying to get user input using fgets. So if the user enters the following integers:
1 2 3 4 5
How do i scan them and put them in an array of ints= [1,2,3,4,5]
Here is what I am trying to do right now: I am continuously looping and asking the user to input a number until the user does not put anything. In each iteration, I am saving the input of the user to the array
int myArray[200];
char input_str[1024];
fprintf(stdout, "Enter numbers: ");
if (fgets(input_str, sizeof(input_str), stdin) == 0){
fprintf(stderr, "Error returned from fgets()...\n");
exit(1);
}
sscanf(input_str, "%d", &n);
myArray[i]=n;
//The while loop will continue as long as the string is not null
while( input_str[0]!='\0'){
if (fgets(input_str, sizeof(input_str), stdin) == 0){
break;
}
for (i=1;i<201;i++){
sscanf(input_str, "%d", &n);
myArray[i]=n;
}
}
#include <stdio.h>
int main(void){
int myArray[200];
char input_str[1024];
int i, n = 0;
size_t full = sizeof(myArray)/sizeof(*myArray);
fprintf(stdout, "Enter numbers: ");
while(fgets(input_str, sizeof(input_str), stdin) != NULL){
char *p = input_str;
int v, len;
if(*input_str == '\n' || n == full)
break;//input end if blank line
while(1==sscanf(p, "%d%n", &v, &len)){
myArray[n++] = v;
p += len;
if(n == full)
break;
}
}
//check print
for (i=0;i<n;i++)
printf("%d ", myArray[i]);
return 0;
}
I'm currently making a dictionary program in C.
How to detect empty string on stdin ? Using search_for for my input.
void find_track(char search_for[])
{
int i;
for (i = 0; i < 5; i++) {
if (strstr(tracks[i], search_for)){
printf("The meaning of %s: %s\n",tracks[i], meaning[i]);
break;
}
}
if (!strstr(tracks[i], search_for)) {
printf("%s could not found in dictionary.\n",search_for);
}
}
Again, how do I lower cast the input using tolower function ?
int main()
{
int setloop =1;
titlemessage();
do {
char search_for[80];
char varchar;
printf("Search for: ");
fgets(search_for, 80, stdin);
if(search_for[strlen(search_for)-1]=='\n')
search_for[strlen(search_for)-1]='\0';
find_track(search_for);
printf("Press ENTER to start new search\n");
//printf("Press 'q' to exit the program\n\n");
varchar = getchar();
if (varchar == 10) {
continue;
}else {
break;
}
} while (setloop = 1);
return 0;
}
Any methods will be appreciated.
Detect empty string on stdin and tolower function in C
fgets(search_for, 80, stdin);
if(search_for[strlen(search_for)-1]=='\n')
search_for[strlen(search_for)-1]='\0';
if(strlen(search_for)==0)
{
// empty string, do necessary actions here
}
char ch;
tolower() Converts ch to its lowercase equivalent if ch is an uppercase letter and has a lowercase equivalent. If no such conversion is possible, the value returned is ch unchanged.
for(i = 0; search_for[i]; i++){
search_for[i] = tolower(search_for[i]); // convert your search_for to lowercase
}
After reading the input, potentially change each char to lower case.
// Test fgets() return value, use sizeof
if (fgets(search_for, sizeof search_for, stdin) == NULL) {
break;
}
size_t i;
for (i = 0; search_for[i]; i++) {
search_for[i] = tolower(search_for[i]);
}
// Advantage: we've all ready run through `search_for` & know its length is `i`.
// Also avoid a `[strlen(search_for)-1]` which could be -1
if ((i > 0) && (search_for[i-1] =='\n')) {
search_for[--i] = '\0';
}
// If empty line entered (OP's "detect empty string on stdin")
if (i == 0) {
break;
}
find_track(search_for);
#if 0
// Reccomedn delete this section and using the above empty line test to quit
//printf("Press 'q' to exit the program\n\n");
varchar = getchar();
if (varchar == 10) {
continue;
} else {
break;
}
#endif
// OP likel want to _test_ setloop (==), not _assign_ setloop (=)
// } while (setloop = 1);
} while (setloop == 1);