Issues with repeated key checking with getch() - c

I am having issues with repeating key checking using a function that utilizes getch().
Here is a code example:
static char g_keybuffer[256];
_Bool IsKeyDown(char c)
{
char ch;
if(kbhit())
ch = getch();
if(ch == -32 || ch == 224)
{
ch = getch();
}
g_keybuffer[ch] = 1;
if(g_keybuffer[c] == 1)
{
g_keybuffer[c] = 0;
return 1;
}
return 0;
}
/*
*
*/
int main(int argc, char** argv) {
while(1)
{
if(IsKeyDown('a'))
{
printf("Test\n");
}
if(IsKeyDown('a'))
{
printf("Hello\n");
}
else if(IsKeyDown('b'))
{
printf("World\n");
}
Sleep(100);
}
return (EXIT_SUCCESS);
}
I know why the problem occurs. When a key is pressed, kbhit is true once per loop, and sets ch to the character retrieved from the buffer. When IsKeyDown is used, if it is equal to the parameter, the key in the buffer g_keybuffer is set equal to zero to avoid having a key be "down" infinitely. The problem with this is if you want to check if the same key is down more than once, only the first instance of IsKeyDown will be ran, with the rest being invalid due to the g_keybuffer of the key now being 0.
Does anyone know how I can change IsKeyDown to give it the ability to check the same key multiple times per looping? I'm stuck.

Your problem is because you are setting g_keybuffer[c] to 0 after you get a hit for the key state. I'm guessing you have done this to avoid getting the same result twice - but that is just a workaround. The only way to do what you want to do properly is to choose a library that is actually made to capture the keyboard state.
Most graphics libraries have functions for capturing keyboard states. I don't know of any solutions thought that don't involve a little overhead if you are just writing a small program.

Related

Variable loses its value C

I'm working on this project where a user has to guess a word (wordToGuess) and he has a number of attempts.
The problem is that the variable "wordToGuess" loses its value when the code arrives in the point marked ("HERE LOSES ITS VALUE). I don't know how to solve this problem, I've tried in many ways. Thank u for your help!
(checkExistence is a function that checks if the word is present in the dictionary)
void newGame(node* head){
char wordToGuess[10];
char attempt[10];
int numberOfAttempts = 0;
if (scanf("%s" , wordToGuess) != 1){
printf("error1");
}
getchar();
if (scanf("%d", &numberOfAttempts) != 1){
printf("error2");
}
getchar();
while(numberOfAttempts > 0){
if (scanf("%s", attempt) != EOF){
if (attempt[0] != '+'){
if (checkExistence(head, attempt) == false){
printf("not_exists\n");
}else{
if (strcmp(wordToGuess, attempt) == 0){
printf("ok\n");
return;
}else{
//code
numberOfAttempts--;
}
}
}else{
if (attempt[0] == '+' && attempt[1] == 's'){
//HERE LOSES ITS VALUE
}else if (attempt[0] == '+' && attempt[1] == 'i'){
//other code
}
}
}else{
printf("ko");
return;
}
}
return;
}
Here a test case:
2rj9R (wordToGuess)
18 (numerAttemps)
DP3wc (attempt)
7PGPU (attempt)
2rz9R (attempt)
+print_list (from this point I lose the value of wordToGuess)
2rj9R (attempt)
As the others have point, you're probably causing a buffer overflow in your attempt buffer which overwrites your wordToGuess buffer since your attempt and wordToGuess buffer is stored like this in your memory:
<attempt buffer> | <word To Guess>
You have two possible fixes for this (as the comments have said...):
A little fix would be to set a limit of how many characters should be read from stdin to scanf like this:
scanf("%9s" , wordToGuess) // you need 9, because your buffer can store up to
// 10 bytes but don't forget that `scanf` is also
// addinng `\0` for you!
and don't forget to flush the rest of the user input if you want that the user should be only able to insert at most 9 characters!
Increase the buffer size of your attempt (and wordToGuess) buffer but also add those read-limits for scanf which is described in the first point.
At the indicated point of the code where wordToGuess appears to lose its value, it is a dead variable. If you're looking at optimized code in a debugger, you may find that the variable doesn't exist there any more.
At a given point in a program, a dead variable is one which is never used past that point. All control flows out of that point reach the termination of that code, without ever using the variable again. Simple example:
{
int x = 3;
// x is live here: there is a next reference
printf("%d\n", x);
// x is now dead: it is not referenced after the above use
printf("foo\n");
}
In the generated code, the compiler may arrange to re-use the resources tied to a dead variable as soon as it is dead: give its register and memory location to something else.
In the debugger, if we put a breakpoint on the printf("foo\n") and try to examine x, we might get a strange result.
To have the best chance of seeing the expected result (that x still exists, and is retaining its most recent value), we have to compile with optimizations disabled.

Using a for-loop in C to test the return value of a function

I'm pretty new to coding and especially to C, so I decided to take the CS50 course as an introduction to the language. I just finished watching the first lecture on C and, as a means to test my knowledge on the subject, I attempted to write a short little program. Also I am using the course's library for the get_int() function.
The goal is to test the user's input and check if it's less or equal to ten. If it matches the parameters, the program should print the "Success!" message and exit; otherwise, it should ask for input again. If the input value is over 10, the program responds just as expected, but if you input a value of 10 or less, it ends up asking you for input one more time before actually exiting. I think it's probably something with the "for" loop, but I just can't figure it out.
My code:
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
int check_for_value();
int main()
{
for(check_for_value(); check_for_value() != 1; check_for_value())
{
printf("Failed!\n");
}
exit(0);
}
int check_for_value()
{
int i = get_int("Your value: \n");
if(i <= 10)
{
printf("Success!\n");
return 1;
}
else
{
printf("Try again!\n");
return 0;
}
}
That isn't doing exactly what you think it is. In your for loop, each time you write check_for_value(), it is going to call that function. So it will call it the first time and the return value will not matter. It will call it again for the middle statement and then the value will matter because you are comparing the output to not equal to 1. And then again it will call the function in the third statement, where again it won't matter. Usually for something like this, you would use a while loop instead. An example below:
int ret = check_for_value();
while(ret != 1) {
printf("Failed\n");
ret = check_for_value();
}
printf("Success\n");
Technically a for loop can work too as the following:
for(int ret = check_for_value(); ret != 1; ret = check_for_value()) {
printf("Failed\n");
}
The for loop can look very simply
for ( ; !check_for_value(); )
{
printf("Failed!\n");
}
In such a case it is better to use the while loop
while ( !check_for_value() )
{
printf("Failed!\n");
}
As for your for loop
for(check_for_value(); check_for_value() != 1; check_for_value())
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
then the underlined calls of the function are not tested.
Also bear in mind that such a definition of a for loop
for(int ret = check_for_value(); ret != 1; ret = check_for_value()) {
printf("Failed\n");
}
is a very bad style of programming. There is redundant records of the function calls. The intermediate variable ret is not used in the body of the loop. So its declaration is also redundant. Never use such a style of programming.
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )
and the statement
exit( 0 );
is redundant.

C - segmentation fault when comparing integers

here is a part of my code. When I run my code, it's requesting an input from user and then matching it with another integer which recorded in my structure. When user input is matching, it is working correct. But when user enters a wrong input, it gives a segmentation fault. In where, I should make changes on my code?
long int userInput,endCheck; // Input from user
int flag=0; // check for match
int status;
int c; // controlling ctrl+D
int position= 999; // position of where the user input and data matched
LABEL:
printf("\n\t---------------------------------------\n");
printf("\n\nPlease enter the student ID which you want to find(3-times CTRL+D for finish):\n");
scanf("%d",&userInput);
if( (c=getchar()) == EOF){
exit(0);
}
for(i=0;i<lines,flag==0;i++){
if(index[i].id == userInput){
position=i;
flag=1;
}else{
position=999;
}
}
if(flag==0){
printf("id not found");
}
studentInfo info; // for storing the information which we will take between determined offsets
if(position!= 999){
if ( (pos = lseek(mainFile,index[position].offset , SEEK_SET)) == -1)/*going to determined offset and setting it as starting offset*/
{ perror("classlist"); return 4; }
while ( (ret= read(mainFile,&info, sizeof(info))) > 0 ){
printf("\n\nStudent ID: %d, Student Name: %s\n\n",info.id,info.name);
break;// to not take another students' informations.
}
}
flag=0;
goto LABEL;
printf("Program is terminated");
The right way to do that loop with the unwanted comma is like this. When you find the right index[i].id you can exit the loop early by using break.
for(i=0;i<lines;i++){
if(index[i].id == userInput){
position=i;
flag=1;
break;
}
}
You don't need the else branch as position is set to 999 from the outset of the code. But really you shouldn't use position in this fashion. What if you have more than 999 records? You're already using flag to identify if you've set position to a valid value. You should replace any instance of if(position!= 999) with if(flag).
Or since position is a signed int, you could use a negative value and ditch the flag.
The reason can be the fact that you are reaching an index that doesn't exist in the end of cycle, in the moment of the "if" statement with iterator "i".
Or in the last if, where you access a "position" index of the array. Check those limits.
Also, try GDB, is useful for solving this kind of problems.

Why does an empty printf allow me to continue reading data from the stdin?

CODE
while (1)
{
keycode = key_hook();
if (keycode == SPACE || keycode == BKSPACE)
{
render_again = 1;
}
if (keycode == ESC)
break;
if (render_again)
{
render_again = 0;
render(all);
}
dprintf(1, ""); //I have no idea why this prevents the program from freezing
}
int key_hook()
{
char buffer[4];
read(0, buffer, 4);
return (*(unsigned int *)buffer);
}
Alright, so this piece of code handles redrawing of text on screen. Some rows of text are underlined or highlighted using termcaps (tputs(tgetstr("us, NULL")......). Everything prints fine but after the first redraw of the text the while apparently freezes unless a dprintf/printf is present. The key_hook function just reads 4 bytes from the stdin and converts them to an int.
When I last did work here, my version of key_hook had a loop of single byte reads. This was broken by an alarm of 1 second and logic to whether the data so far was a key prefix.
The alarm interrupted the read, and stopped freeze

Prevent output of carriage return with readline

I'm new to the Gnu Readline library.
I need to call the readline() function when the cursor is at the very last line of the console. But I need to prevent scrolling down when the Return key is pressed; so I'm looking for a way to prevent the output of the carriage return : I'm sure it's possible, but can't find the way to do it.
I tried to use my own rl_getc_function() to trap the Return key (the example below traps y and z keys, but it's just for test purposes) and treat this key in a special way:
My first idea was to run the accept-line command directly, thinking it would not output a carriage return, but actually, it does
My second idea was to redirect the output to /dev/null before calling the accept-line command; but the redirection doesn't seem to apply when the readline() function is already running.
Here is an example of my tests:
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
FILE *devnull; // To test output redirecting
int my_getc(FILE *file)
{
int c = getc(file);
// Let's test something when the 'y' key is pressed:
if (c == 'y') {
// I was thinking that calling "accept-line" directly
// would prevent the output of a carriage return:
rl_command_func_t *accept_func = rl_named_function("accept-line");
accept_func(1, 0);
return 0;
}
// Another test, when 'z' key is pressed:
if (c == 'z') {
// Try a redirection:
rl_outstream = devnull;
// As the redirection didn't work unless I set it before
// the readline() call, I tried to add this call,
// but it doesn't initialize the output stream:
rl_initialize();
return 'z';
}
return c;
}
int main()
{
devnull = fopen("/dev/null", "w");
// Using my function to handle key input:
rl_getc_function = my_getc;
// Redirection works if I uncomment the following line:
// rl_outstream = devnull;
readline("> "); // No freeing for this simplified example
printf("How is it possible to remove the carriage return before this line?\n");
return 0;
}
I'm sure I missed the right way to do it; any help would be appreciated.
I found it : the rl_done variable is made for this.
If I add this code to my my_getc() function, it works well:
if (c == '\r') {
rl_done = 1;
return 0;
}
No carriage return is then inserted, and my next printf() call displays just after the last char I typed.

Resources