kbhit and multiple calls on function - c

While making a asteroid shooter, I came around using _kbhit() and kbhit(). I'm no expert, but here is the problem I think I'm having:
int run = 1;
int main() {
while(run){
if(GetUserInput() == 2)
printf("W");
if(GetUserInput() == 1)
printf("S");
Sleep(50);
}
}
int GetUserInput(){
if(kbhit()){
char c = _getch();
if(c == 's')
return 2;
if(c == 'w')
return 1;
}
else
return 0;*
}
So, what I think is happening, it does the first check on GetUserInput(), and because of the nature of getch(), the keyboard is read from the buffer and discarded? Anyways, I store the value in c and should return appropriately. But it only does the first check. Is it because there is no more input on the buffer after the first check (in the main() function)?

Your problem is that you're trying to read once for every key you're interested in with this code:
if(GetUserInput() == 2)
printf("W");
if(GetUserInput() == 1)
printf("S");
For example, I press 'S', you read the key, check if the return value is 2 and it is not. Then you try to read another key, but I haven't pressed one, so the second check for 'S' also fails.
To fix this you need to perform all of your tests on the value you get from GetUserInput().
int val = GetUserInput();
if(val == 2)
printf("W");
else if(val == 1)
printf("S");
You don't need to use else if, but once you've found a match it makes no sense to keep checking if all of your checks are mutually exclusive. You might consider using a switch statement and an enum instead of hardcoded magic values, or even return the key value directly if one is pressed and a sentinel value like 0 that won't match any of the keys you're interested in.
Here is a complete example that works for me:
#include <conio.h>
#include <stdio.h>
int GetUserInput()
{
if (_kbhit())
{
char c = _getch();
switch (c)
{
case 's':
case 'S':
return 2;
case 'w':
case 'W':
return 1;
case 'x':
case 'X':
return -1;
}
}
return 0;
}
int main()
{
for (;;)
{
int c = GetUserInput();
switch (c)
{
case 1:
printf("W");
break;
case 2:
printf("S");
break;
case -1:
return 0;
}
}
return 0;
}

Related

Trouble getting a switch function to loop properly

I'm writing a program to 'encrypt' an inputted string of text by using a switch statement to correlate the given character with a symbol, and output that symbol in the place of the character. I put it in a while loop, the idea being that it would loop the full switch function each time until the received character is EOF. On a guess, I believe it is looping through just the first character, because I don't advance the getchar() statement, but I'm not sure how to do that so any help would be greatly appreciated. I say this because if I use return instead of break, it closes the while loop and only takes that first letter, if I use a break then it spams the first 'encrypted' char.
#include <stdlib.h>
#include <stdio.h>
/* C program to encrypt a given text message, assuming all lowercase */
int main() {
int Input, Encrypted;
printf("Please type your message\n");
Input = getchar();
while (Input != EOF) {
switch (Input) {
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'");break;
return 0;
}
}
return 0;
}
The simplest solution would be to remove the line
Input = getchar();
and to replace the line
while (Input != EOF) {
with:
while ( (Input=getchar()) != EOF && Input != '\n' ) {
Alternatively, if you find this while condition too confusing, you could also use an infinite loop, instead, like this:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
switch ( c )
{
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'"); break;
}
}
return 0;
}
Note that most character sets (such as ASCII) store the characters a to z consecutively. With these character sets, you don't need the long switch statement. Instead, you can simplify it to the following:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
const char map[] = "!##$%^&*`~-_=+[{]};:|,<.>'";
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
if ( 'a' <= c && c <= 'z' )
putchar( map[c-'a'] );
}
return 0;
}

Incorrect coding with respect to logic written

The program needs to execute until 'q' is pressed. But the below code what I wrote it is only executing whichever case is first and then stops executing further cases. Ex: case 1.if my input is p, q, then only p case is executed, not the q.
case 2.if my input is g, q, then only g case is executed, not the q.
int main()
{
int i,n,cnt;
char value[10]={0,0,0,0,0,0,0,0,0,0};
int index; float values,Max;
int *val;
bool quit=false;
float num[10]={1.500, 2.200, 7.300, 9.200, 7.400, 7.500, -8.000, 1.500, 12.000, 0.000};
for(i=0;i<20;i++)
{
scanf("%c",&value[i]);
if(value[i]=='r')
{
scanf("%d", &index);
scanf(", %3f",&values);
}
if((value[i] =='p')|(value[i] =='q')|(value[i] =='r')|(value[i] =='g')|(value[i] =='s'))
{
cnt++;
}
}
for(i=0;i<cnt;i++)
{
while(!quit)
{
switch(value[i])
{
//printf("Command (p/g/r/s/q):");
case 'p':
{
printf("Command (p/g/r/s/q):");
printValues(&num,10);
return;
}
case 'g':
{
printf("Command (p/g/r/s/q):");
Max= largestElement(&num,10);
printf("Max=%0.3f",Max);
return;
}
case 'r':
{
printf("Command (p/g/r/s/q):");
replaceElement(&num,index,values);
printValues(&num,10);
return;
}
case 's':
{
printf("Command (p/g/r/s/q):");
sortOnValue(&num,10);
printValues(&num,10);
return;
}
case'q':
{
printf("Command (p/g/r/s/q):");
quit= true;
break;
}
default:
{
printf("help");
return;
}
}
}
}
return 0;
}
Within most of your case blocks you probably want break rather than return to exit the switch. At the moment you are returning frommain() and consequently exiting the program. break transfers control to the end of the switch and your program can then continue.
The case 'q' block would then have a return to exit the program.
Few problems here.
for(i=0;i<20;i++) you are accessing out of bound so your loop should be
for(i=0;i<10;i++).
You need to add ' ' in the format string to consume new line character (\n).
`scanf(" %c",&value[i]);`
You are using | operator instead of || hence your if should be.
if((value[i] =='p')||(value[i] =='q')||(value[i] =='r')||(value[i] =='g')||(value[i] =='s'))
{
cnt++;
}
You are using return instead of break in your switch case.
change this
case 'p':
{
printf("Command (p/g/r/s/q):");
printValues(&num,10);
return;
}
to
case 'p':
{
printf("Command (p/g/r/s/q):");
printValues(&num,10);
break;
}
Your while(!quit) inside the for loop is not useful and will lead to infinate loop when used break statement inside switch case. Hence remove the while(!quit) and change your for loop as below.
for(i=0;i<cnt&&!quit;i++)
side note:: It is high time for you
learn-how-to-debug-small-programs

Working with .txt in VS2008 in C

I wrote some program which overwrites some text in .txt file and put the overwritten one in another output.txt... But it's constantly saying that the file can't be opened. What should I do?
#include <stdio.h>
#include <ctype.h>
int main()
{
FILE *ul=fopen("hexbr.txt","r"),*iz=fopen("bitovi.txt","w");
int i;
char ch;
if ((!ul)||(!iz)) { printf("Neuspesno otvaranje datoteke!");return 0; }
while((ch=fgetc(ul))!=EOF)
{
if ((isdigit(ch)) || (c>='A' && c<='F'))
{
if (isalpha(ch))
switch(ch)
{
case 'A': { fputc('1',iz);fputc('0',iz);fputc('1',iz);fputc('0',iz);continue; }
case 'B': { fputc('1',iz);fputc('0',iz);fputc('1',iz);fputc('1',iz);continue; }
case 'C': { fputc('1',iz);fputc('1',iz);fputc('0',iz);fputc('0',iz);continue; }
case 'D': { fputc('1',iz);fputc('1',iz);fputc('0',iz);fputc('1',iz);continue; }
case 'E': { fputc('1',iz);fputc('1',iz);fputc('1',iz);fputc('0',iz);continue; }
case 'F': { fputc('1',iz);fputc('1',iz);fputc('1',iz);fputc('1',iz);continue; }
}
for(i=0;i<4;i++)
{
fputc((ch & 0X8)?'1':'0',iz);
ch<<=1;
}
}
else fputc(ch,iz);
if (ch=='\n') { ch=fgetc(ul);fputc(ch,iz); }
}
fclose(ul);
fclose(iz);
return 0;
}
The program did not compile without error, there is a pair of typos here, c should be ch:
... (c>='A' && c<='F') ...
Apart from that the program almost works, and the output file (created in the same folder as the executable) is readable.
There is a mistake in trying to handle newline chars, which mistakenly causes the next (printing) char to be passed through and not converted to binary. I left newline and return to be passed through like other non-hex chars.
Other than that, the handling of A..F is clumsy. I suggest trapping them like this:
while((ch=fgetc(ul))!=EOF)
{
if ((isdigit(ch)) || (ch>='A' && ch<='F'))
{
if (isalpha(ch))
ch -= 7;
for(i=0;i<4;i++)
{
fputc((ch & 0X8)?'1':'0',iz);
ch<<=1;
}
}
else fputc(ch,iz);
}
And you might want to check and convert the lower case a..f too.

Assigning char array based on the value of char in C

I'm trying to assign a specific value of char array (or string) through conditionals depending on the value of char.
Suppose c is a char declared before the code with a specific value of some sort.
char fruit[];
if (c == 'R') {
fruit[] = "Red";
}
else if (c == 'Y') {
fruit[] = "Yellow";
}
else if (c == 'G') {
fruit[] = "Green";
}
else if (c == "B") {
fruit[] = "Blue";
}
This code is obviously wrong but should give an idea on what I'm trying to do.
I am either planning to use a correct version of this for a simple program or have to go through around four times more conditionals to manually print the said string values which would be an immense pain.
char *color; // for modern compilers, should be const char *color
switch (c)
{
case 'R': color = "Red"; break;
case 'Y': color = "Yellow"; break;
case 'G': color = "Green"; break;
case 'B': color = "Blue"; break;
default: color = "<unknown>"; break;
}
I took exception at illogical variable names so renamed fruit to color, but this approach is one way to achieve what I think you are asking.
The best way to do this would be to use a switch statement, but you'll first need to tell the compiler how big you want fruit[] to be, if you're not going to allocate it dynamically based on the character you detect.
Unless you're going to be dealing with fruits that have colors with really long names, I'd say 16 characters is enough for a demonstration. Hence:
#include <stdio.h>
#include <string.h>
void fruity_printer(char c) {
char fruit[16] = { 0 }; // initialize your arrays!
Now, a simple switch statement on char c
switch (c) {
case 'R':
strcpy(fruit, "Red");
break;
// add more cases as needed
default: // what happens if we don't have a case for it?
strcpy(fruit, "Rainbow");
break;
}
printf("The fruitabulous color is: %s\n", fruit);
return;
}
Note that I've used strcpy() here, because I'm sure that I know that I'll be writing within bounds of the destination. You'd never just arbitrarily copy something where the length wasn't known at compile time like that, you'd use strncpy() instead, which takes another argument for length.
Things you'll also want to do is convert c in the fruity printer to either upper or lower, so you don't have to deal with both cases.
Another way would be to allocate your memory dynamically, but the semantics of figuring out what it should be are still best served by just using a simple switch.
You can use switch case to that:
#include<stdio.h>
#include<string.h>
int main (int argc, char *argv[])
{
char c;
char fruit[100];
printf("Enter the character: ");
scanf(" %c",&c);
switch(c)
{
case 'R' : strcpy(fruit,"Red"); break;
case 'Y' : strcpy(fruit,"Yellow"); break;
case 'G' : strcpy(fruit,"Green"); break;
case 'B' : strcpy(fruit,"Blue"); break;
default : puts("No color");
}
printf("%s\n",fruit);
}

Case label does not reduce to an integer constant in C?

I am working on a game and I ran my code and got the error "case label does not reduce to an integer constant." I think I know what this means, but how do I fix it? Here is my code:
#include<stdio.h>
#include<stdlib.h
int player_cash[3] = {50};
char job[][20] {
'A',
'B',
'C',
"Donate",
"Go to work",
"Exit"
};
int jobs;
int main()
{
while(player_cash[0] > 0) {
printf("Please type A, B, C, Donate, Go to work, or Exit\n");
switch(jobs) {
case 'A':
player_cash[0]-=5;
player_cash[1]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'B':
player_cash[0]-=5;
player_cash[2]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'C':
player_cash[0]-=5;
player_cash[3]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case "Donate":
player_cash[0]-=15; //Error here
player_cash[1]+=5;
player_cash[2]+=5;
player_cash[3]+=5;
printf("Cash donated\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case "Go to work":
player_cash[0]+=10; //Error here
printf("Work done\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case "Exit":
printf("Thanks for playing!\n\n"); //Error here
break;
default:
printf("Does not compute");
continue;
}
}
getchar();
return 0;
}
So, what I want the user to do is type in one of the options, and do the action that corresponds with it. How do I fix this?
You can't use strings as case expressions:
case "Donate":
Only integral expressions can be used, so e.g. case 'A': is OK.
Conceptually you have problems: jobs is an int, and you're testing for strings. If you want to allow the user to enter strings (more than a single character), you'll need to keep a string variable, and use something like fgets to get a full line of input.
Some of your case labels are characters (type char, indicated with 's). Those are integer constants.
Other labels are string literals (indicated with ") which have an effective type of const char *.1 Those are not integer constants and can not be used in this way.
1 For historical reasons they can often be used as if they were char *, but don't try to change them. Or else.
You cant compare string with c. "hello" == "hello" wont work as intend. switch only do simple c comparison on basic types.
switch(jobs) {
case 'A':
player_cash[0]-=5;
player_cash[1]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'B':
player_cash[0]-=5;
player_cash[2]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'C':
player_cash[0]-=5;
player_cash[3]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'D':
player_cash[0]-=15; //Error here
player_cash[1]+=5;
player_cash[2]+=5;
player_cash[3]+=5;
printf("Cash donated\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'G':
player_cash[0]+=10; //Error here
printf("Work done\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'E':
printf("Thanks for playing!\n\n"); //Error here
break;
default:
printf("Does not compute");
continue;
}
as you only read a character in getch(), you can compare this value. (but ask the user to input only one letter because he input "Donate", getch() will first read D, return, then read o, etc..)
Your job array had inconsistent initializers (mixed char and const char *)
You can't use string literals as case labels, as the char pointers are not compile time constants. Use integers:
enum jobType
{
jobA,
jobB,
jobC,
jobDonate,
jobGoToWork,
jobExit,
/* marker */
jobInvalid
};
enum jobType typeOfJob(const char* const name)
{
int i;
for (i=jobA; i!=jobInvalid; ++i)
if (0 == strcmp(jobNames[i], name))
return i;
return i;
}
Also, the player_cash was 1 element short (and was written out of bounds at index [3])
Code sample also shows how to avoid general gets badness, do some basic line-end trimming and do case insenstive comparison (stricmp on windows, IIRC): http://liveworkspace.org/code/227015a4e51126d55ca4eb1eea739b02
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int player_cash[4] = {50};
enum jobType
{
jobA,
jobB,
jobC,
jobDonate,
jobGoToWork,
jobExit,
/* marker */
jobInvalid
};
const char jobNames[][20] =
{
"A",
"B",
"C",
"Donate",
"Go to work",
"Exit"
};
enum jobType typeOfJob(const char* const name)
{
int i;
for (i=jobA; i!=jobInvalid; ++i)
#ifdef CASE_SENSITIVE
if (0 == strcmp(jobNames[i], name))
#else
if (0 == strcasecmp(jobNames[i], name))
#endif
return i;
return i;
}
const char* safer_gets()
{
static char input[1024];
char *p;
const char* t;
const char trimAt[] = "\r\n\t ";
fgets(input, sizeof(input), stdin);
for (t=trimAt; *t; ++t)
while(p = strrchr(input, *t))
*p = 0;
return input;
}
int main()
{
const char* input;
while(player_cash[0] > 0)
{
printf("Please type A, B, C, Donate, Go to work, or Exit\n");
input = safer_gets();
switch(typeOfJob(input))
{
case jobA:
player_cash[0]-=5;
player_cash[1]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobB:
player_cash[0]-=5;
player_cash[2]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobC:
player_cash[0]-=5;
player_cash[3]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobDonate:
player_cash[0]-=15;
player_cash[1]+=5;
player_cash[2]+=5;
player_cash[3]+=5;
printf("Cash donated\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobGoToWork:
player_cash[0]+=10;
printf("Work done\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobExit:
printf("Thanks for playing!\n\n");
break;
default:
printf("Does not compute");
continue;
}
}
getchar();
return 0;
}

Resources