Cursor positioning by using arrow keys for getch in C - c

I am very beginner in C and would like to code something which gets name from user and rearrange it with backspace, cursor(by using arrow keys).
In the program, when user writes his name and press ESC it has to stop the program and print the name on the screen.
So far, I was able to do ESC and Backspace parts with usign getch() and their ASCII codes, but I'm having problem on moving cursor by using arrow keys when user tries to rewrite or rearrange his name.
Here is my code:
#include<stdio.h>
#include<conio.h>
int main() {
int i, k = 0;
char character;
char samplearray[100];
printf("Enter your name:\n");
while (1) {
character=getch();
if (character != 0x1B && character != 0x8 && character != 0x4B) {
samplearray[k] = character;
k++;
printf("%c", character);
}
else if (character == 0x8) { //Deleting procces in name and it works without any problem.
samplearray[k];
k--;
system("cls");
printf("Enter your name:\n");
for (i = 0; i <= k; i++) {
printf("%c", samplearray[i - 1]);
}
}
else if (character == 0x4B) { //Having a problem on this part.
samplearray[k] = character;
k--;
printf("\b\b", samplearray[k]);
}
else
break;
}
printf("\nYour name is: \n");
for (i = 0; i <= k - 1; i++) {
printf("%c", samplearray[i]);
}
getch();
return 0;
}

Related

I'm trying to make a program in C in which you can play hangman but as soon as it prints the option to guess the letter the program terminates

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;
}
}
}

masking password input in windows terminal in C

I am on Windows and have tried the following code to mask password input:
#include <stdio.h>
#include <conio.h>
int main() {
int i = 0;
char ch, password[13];
printf("\nEnter Password (Upto 12 chars.): ");
while (i < 12) {
ch = getch();
if (ch == ' ') {
--i;
} else if (ch == '\b') {
printf("\b \b");
i -= 2;
} else if (ch == '\r')
break;
else {
password[i] = ch;
printf("*");
}
++i;
}
password[i] = '\0';
printf("\nPassword: %s",password);
return 0;
}
The problem with above code is that when I have inputted no characters and I press backspace then the printed string Enter Password (Upto 12 chars.): gets its characters erased one by one. This I was able to work around by doing this Enter Password (Upto 12 chars.):\n and now it won't delete its characters. But there is another problem and that is whenever I try to close the terminal by pressing Alt+F4 the two keystrokes get considered input by getch() and I get two characters returned and displayed. I know it is my fault as the else part takes anything except \r,\b and white-space but I want help fixing it.
What I want is to be able to mask password input without any of the above problems. I have used MySQL Command-line client before and it asks for password input just fine. Anything like that or close to that would be appreciated.
I should mention this is for a University project.
Any help is appreciated
I fixed my own code. Took some inspiration from some old C++ code (not copy pasta).
It ignores whitespace, Esc key, function and arrow keys, works properly on backspace, and breaks out of the loop on hitting Tab or Enter. And now it doesn't delete characters from printf() string when hitting backspace on empty input.
The trick is to only assign input when all other if and else if conditions are not met and increment the counter in that else block only. And then when the loop ends put a '\0' at the last index of the string.
Here is the code:
#include <conio.h>
#include <stdio.h>
#define PASSWORD_LENGTH 12
int main() {
int i = 0;
char password[PASSWORD_LENGTH + 1];
int ch;
printf("\nEnter Password (Upto 12 chars.): ");
while (i < PASSWORD_LENGTH) {
ch = getch();
if (ch == ' ' || ch == 27) {
continue;
} else if (ch == '\b') {
if (i > 0) {
printf("\b \b");
--i;
} else {
continue;
}
} else if (ch == '\r' || ch == '\t') {
break;
} else if (ch == 0 || ch == 224) {
ch = getch();
continue;
} else {
password[i++] = ch;
printf("*");
}
}
password[i] = '\0';
printf("\n,%s,", password); //this can be removed as it is only for displaying output
return 0;
}

Program won't store characters in 2d array in c

I am creating a program where I insert a number of sentences and the program outputs them in order. I have finished the program, but when I run it it seems like the characters I input into the array aren't displayed or stored correctly, getting as a result random letters instead of the full sentence. Here is the code of the program:
char ch;
int i,j,k;
int nothing = 0;
int count = 1;
char lines[5][256];
int length[256];
int main() {
printf("Please insert up to a max of 5 lines of text (Press enter to go to next line and twice enter to stop the program):\n");
i = 0;
while (i<5){
j = 0;
ch = getche();
if (ch == '\r'){
if(i!= 0){
break;
}
printf("You have not inserted anything, please insert a line:");
i=-1;
}
if(ch != '\r'){
lines[i][j]=ch;
while (ch!='\r'){
ch = getche();
lines[i][j] = ch;
j++;
}
}
printf("\n");
i++;
}
for (k=i ; k > 0; k--){
printf("\tphrase %i :", count);
for ( j =0 ; j <= length[k]; j++){
printf("%c",lines[j][k]);
}
count++;
printf("\n");
}
return 0;
}
How can I get the characters to be stored and displayed correctly? Any help is appreciated, thank you!!
There are numerous problems with your code. I'll try and summarise here, and give you improved code.
Fist, some changes that I made to get this to compile on my system:
Changed getche() to getchar() (getche() does not appear to be available on Ubuntu).
I took out the section about re-entering a string, and just focused on the rest (since the logic there was slightly broken, and not relevant to your question). It will still check for at least one line though, before it will continue.
I had to change the check for \r to \n.
I changed your length array to size 5, since you'll only have the lengths of maximum 5 strings (not 256).
Some problems in your code:
You never updated the length[] array in the main while loop, so the program never knew how many characters to print.
Arrays are zero indexed, so your final printing loops would have skipped characters. I changed the for parameters to start at zero, and work up to k < i, since you update i after your last character in the previous loop. The same with j.
Your reference to the array in the printing loop was the wrong way around (so you would've printed from random areas in memory). Changed lines[j][k] to lines[k][j].
No need for a separate count variable - just use k. Removed count.
The nothing variable does not get used - removed it.
#include <stdlib.h>
#include <stdio.h>
char ch;
int i,j,k;
char lines[5][256];
int length[5];
int main()
{
printf("Please insert up to a max of 5 lines of text (Press enter to go to the next line and twice enter to stop the program):\n");
i = 0;
while (i<5)
{
j = 0;
ch = getchar();
if ((ch == '\n') && (j == 0) && (i > 0))
{
break;
}
if (ch != '\n')
{
while (ch != '\n')
{
lines[i][j] = ch;
j++;
ch = getchar();
}
}
length[i] = j;
printf("\n");
i++;
}
for (k = 0; k < i; k++)
{
printf("\tPhrase %i : ", k);
for (j = 0; j < length[k]; j++)
{
printf("%c", lines[k][j]);
}
printf("\n");
}
return 0;
}

Vigenere's cipher in C several problems

I have made program which encrypts and decrypts Vigenere's cipher but I have several problems.
Here is one: First letter of sentence is encrypted incorrectly.
Second one: After sentence I have letter K. I think that's because of space but I don't know how to fix it.
And third problem: There are no spaces in encrypted sentence I know ages ago when Vigenere's cipher was used there were no spaces but I would like to have groups of 5 letters if that's possible.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv) {
char message[100];
int choice;
int i, j;
char pass[33];
int value;
char repeat = 1;
while (repeat == 1) {
printf("Enter operation\n");
printf("Encrypt - 1 \n");
printf("Decrypt - 2\n");
scanf("%d", &choice);
if (choice == 1) {
printf("Please enter message to encrypt\n");
while (getchar() != '\n');
fgets(message, 100, stdin);
printf("Enter password\n");
scanf("%s", &pass);
for (i = 0, j = 0; i < strlen(message); i++, j++) {
if (message[i] == ' ')
continue;
if (j >= strlen(pass)) {
j = 0;
}
if (!isupper(message[i])) {
value = (((message[i]) - 97) + ((pass[j]) - 97));
}
if (!islower(message[i])) {
value = (((message[i]) - 65) + ((pass[j]) - 65));
}
printf("%c", 97 + (value % 26));
}
printf("\nWould you like to repeat? [1/0]\n");
scanf("%d", &repeat);
} else
if (choice == 2) {
printf("Enter message do decrypt\n");
while (getchar() != '\n');
fgets(message, 100, stdin);
printf("Zadejte heslo\n");
scanf("%s", &pass);
for (i = 0, j = 0; i < strlen(message); i++, j++) {
if (message[i] == ' ')
continue;
if (j >= strlen(pass)) {
j = 0;
}
if (!isupper(message[i])) {
value = (((message[i]) - 96) - ((pass[j]) - 96));
}
if (!islower(message[i])) {
value = (((message[i]) - 64) - ((pass[j]) - 64));
}
if (value < 0) {
value = value * -1;
}
printf("%c", 97 + (value % 26));
}
printf("\nWould you like to repeat? [1/0]\n");
scanf("%d", &repeat);
}
}
return (EXIT_SUCCESS);
}
[
The main problem in your code is you apply the translation to characters with incorrect tests: you should translate uppercase letters is you have indeed an uppercase letter, not if you don't have a lowercase character. As coded, non letters are translated twice.
Change the code to:
if (islower((unsigned char)message[i])) {
value = (((message[i]) - 'a') + ((pass[j]) - 'a'));
}
if (isupper((unsigned char)message[i])) {
value = (((message[i]) - 'A') + ((pass[j]) - 'a'));
}
Also make sure you use character constants instead of hard-coded ASCII values and make the password lowercase.
In the deciphering case, the offsets seem incorrect. You should be using 'A' and 'a' too.
First things first, the message corruption. If you add a few printf() statements in the loop that is doing the encryption, you should be able to get an idea what is going wrong. You can always comment them out, or remove them altogether, anytime later.
That K on the end could be the encrypted \n that would have been read in with the message.
To display the encrypted message in groups of five characters, keep a count of how many characters you have actually displayed (make sure the instruction to increase the count is located where it will get skipped if the character is not displayed); and when this reaches 5, display a space and reset the counter to zero.

How can I replace getchar();?

#include <stdio.h>
int main (void)
{
int n;
printf("Give the number of words you want to input.");
scanf("%d",&n);
int letters[n],i,j,count,key,k;
char str[100];
//Scans each word, counts it's letters and stores it in the next available
//position in "letters" array.
for (i=0;i<n;i++)
{
j=0;
printf("Give the next word.");
do{
str[j] = getchar();
j++;
}while (str[j-1]!='\n');
str[j-1] = '\0';
letters[i] = j;
}
//Compacts the data by figuring out which cells have the same number of letters
for (i=0;i<n;i++)
{
key = letters[i];
count = 0;
for (j=i+1;j<=n;j++)
{
if (key==letters[j])
{
count += 1;
letters[j] = 0;
}
}
letters[i] = count;
}
//creates a histogram
i=0;
do{
printf("%d|",i);
for (j=1;j<=letters[i];j++)
{
printf("*");
}
printf("\n");
i++;
}while ((i<=n));
return 0;
}
I understand that getchar(); reads, the first enter (\n) , user hits, to give the amount of words he wants to input, and thus expects one less word.
Also, I get an infite loop for some reason at the end. Any help and ideas would be appreciated. Thanks in advance.
Change the first block of your code to look like this:
(test the output of getchar, and continues only if not EOF)
for (i=0;i<n;i++)
{
j=0;
printf("Give the next word.");
do{
a = getchar();
if(a >= 0)
{
str[j] = a;
j++;
}
else break;
}while (str[j-1]!='\n');
str[j-1] = '\0';
letters[i] = j;
}
But regarding your question: How can I replace getchar();? Have you considered using scanf()?
EDIT
Here is a simple example of using scanf() and printf() to prompt for input and then display input. It will allow user to input entire words or sentences (up to 80 characters) until 'q' is entered. Not exactly what you are doing, but you should be able to adapt it to your code... (run this)
int main(void)
{
char buf[80]={""};
while( strcmp(buf, "q") != 0) //enter a 'q' to quit
{
buf[0]=0;
printf("enter string:\n");
scanf("%s", buf);
printf("%s\n", buf);
}
}
Wouldn't it be easier to update the letter count in the first loop?
memset(letters, 0, n);
for (i=0;i<n;i++)
{
char* s = str;
int j=0;
printf("Give the next word.");
do{
*s = getchar();
++j;
}while (*(s++)!='\n');
s[-1] = '\0';
letters[j-1]++;
}
As a result the second loop will be unnecessary.
The following two lines have the wrong end condition; should be <n, not <=n. Currently they retrieve an uninitialized array element. Since you declared str as a local variable, that element is typically populated with garbage, i.e. a very big random number. That might explain why it takes extreme long (but possibly not forever) for the last loop to finish.
for (j=i+1;j<=n;j++)
}while ((i<=n));
Also, I assume line n of the histogram should contain the number of words that have n letters? That's not what you're doing right now.
letters[i] = count;
That line should have been:
letters[key] = count;
But to make that work, you should not overwrite the same array letters; you must declare a new array for your histogram, otherwise the second loop will destroy its own input.
By the way, str seems totally redundant. Is it there for debugging purposes?

Resources