Double ask for input if wrong input is given - c

My functions:
//Check Character Case(Upper/Lower Case). If Upper Convert to Lower Case.
char checkLetterCase(char letter){
if(letter >= 65 && letter <= 90){
letter = tolower(letter);
return letter;
}
else if(letter >= 97 && letter <= 122){
return letter;
}
else{
return 0;
}
}
//Add the Specified Letter by Creating a New Node in the Letter List defined
void addLetter(letterListT *letListHead, char letter){
letterListT *newNode;
newNode = (letterListT *)malloc(sizeof(letterListT));
//Check Case(lowe/upper)
letter = checkLetterCase(letter);
//This may only occur on user input
while(letter == 0){
printf("Guess a letter: ");
scanf("%c", &letter);
letter = checkLetterCase(letter);
}
newNode->letter = letter;
newNode->nxt = letListHead->nxt;
letListHead->nxt = newNode;
}
My call in main:
addLetter(unusedLetList, i=0);
and this is my outpun on run:
Guess a letter: 6
Guess a letter: Guess a letter: t
and my question is: why when i put a non character i get the "Guess a letter" message twice?

Because after pressing <enter>, there's an extra newline character that is not (yet) consumed by scanf(). Make a call to getchar() to get rid of that:
letter = checkLetterCase(letter);
if (letter == 0) getchar();
By the way, your checkLetterCase() function is broken on non-ASCII systems. Use this instead:
#include <ctype.h>
char checkLetterCase(char letter)
{
return isalpha(letter) ? letter : 0;
}

A little suggest about avoiding nasty things with buffers, just don't use scanf.You could use it and clean the buffer, of you could use fgets.
I suppose that you could learn how to use it by reading the manual, but I'll make you an example:
while(letter == 0)
{
char buffer[10];
printf("Guess a letter: ");
fgets(buffer,10,stdin);
if(strlen(buffer)==2)
letter = checkLetterCase(buffer[0]);
}

Related

Is there a way to check the uppercase and isalpha case for strings in an array?

while(1)
{
char buff[1000];
printf("Enter the word: ");
fgets(buff, 1000, stdin);
if(!strcmp(buff, "\n"))//empty search then break the loop
{
fprintf(stderr, "Exiting the program\n");
break;
}
int error = 0;
int i = 0;
while(buff[i] != '\0')
{
if(buff[i] >= 33 && buff[i] <= 96)
{
break;
}
error = 1;
i++;
}
if(error == 0)
{
fprintf(stderr, "Please enter something containing only lower-case letters\n");
}
}
I expect the output of hello World to be Please enter something containing only lower-case letters, but I am not getting that error.
If I enter World hello I am getting the expected result which is, it prints the error message.
Is there a way to use isalpha for the whole array?
You should not hard-code letter values but use the actual values. In this problem any letter outside the range 'a' to 'z' is invalid. But it is more portable to use the library functions isalpha() and islower() because the letters values are not guaranteed to be consecutive.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
while(1) {
char buff[1000];
printf("Enter the word: ");
fgets(buff, sizeof buff, stdin);
if(!strcmp(buff, "\n")) {
fprintf(stderr, "Exiting the program\n");
break;
}
int error = 0;
int i = 0;
while(buff[i] != '\0') {
if(isalpha(buff[i]) && !islower(buff[i])) {
error = 1;
break;
}
i++;
}
if(error == 1) {
fprintf(stderr, "Please enter something containing only lower-case letters\n");
}
}
}
Program session
Enter the word: hello world
Enter the word: Hello world
Please enter something containing only lower-case letters
Enter the word: hello World
Please enter something containing only lower-case letters
Enter the word: hello, world!
Enter the word:
Exiting the program
There are library functions for checking upper and lowercase. They are called isupper and islower. Use them. Although its uncommon with 'a' being something else than 97, it may happen. If you mean the letter 'a' then use the character literal 'a' instead of the number 97. Furthermore, the letters aren't even guaranteed to be consecutive, so 'z'-'a' is not guaranteed to be evaluated to 22. However, digits are required to be consecutive so '9'-'0' will always evaluate to 9. But it is much safer to rely on library functions like isalpha and such. I wrote about encoding here: https://stackoverflow.com/a/46890148/6699433
To correct your bug, you need a proper condition. According to your question, it should print the error message if any of the characters is not either a lower case or a space. Furthermore, your code is overly complicated. Here is a solution:
int i = 0;
while(buff[i] != '\0') {
if(!(islower(buff[i]) || isspace(buff[i]))) {
fprintf(stderr, "Please enter something containing only lower-case letters\n");
break;
}
i++;
}
Is there a way to use isalpha for the whole array?
C does not have built in functionality for such things, but you can write your own mapper.
/* Apply function f on each of the elements in str and return false
* if f returns false for any of the elements and true otherwise.
*/
bool string_is_mapper(const char *str, size_t size, int (*f)(int c))
{
for(int i=0; i<size && str[i] != '\0'; i++)
if(!f(str[i])) return false;
return true;
}
Now, you can use this mapper like this:
if(string_is_mapper(str, strlen(str), isupper)
puts("All characters in str is upper case");
You can even write your own functions to plugin, as long as they fit this prototype:
int condition(int c);

Scanning character caused problem in devC

So my code does the following:
Ask what's the option
If option is 1: Scan some numbers
If option is 2: Print those numbers
After each option, ask if user wanted to continue choosing (Y/N)
This is my main code
while(yesnocheck==1)
{
printf("What's your option?: ");
scanf("%d",&b);
switch(b){
case 1:
printf("How many numbers?: ");
scanf(" %d",&n);
a=(struct sv*)malloc(n*sizeof(struct sv));
for(int i=0;i<n;i++)
scanf("%d",&((a+i)->num));
break;
case 2:
for(int i=0;i<n;i++)
printf("%d\n",(a+i)->num);
break;
}
yesnocheck==yesnochecker();
}
And this is the yesnochecker function:
int yesnochecker()
{
char yesorno;
printf("Do you want to continue? (Y/N)");
while(scanf("%s",&yesorno))
{
if(yesorno=='Y')
return 1;
if(yesorno='N')
return 0;
printf("*Wrong input. Please reenter (Y/N): ");
}
}
So on dev C++, my code won't run correctly. After it's done option 1, when I enter "Y" then choose option 2, case 2 will display some weird numbers. However it works well on online C compilers.
And then, when I change the char yesorno in yesnochecker() function to char yesorno[2] and treat it as a string, the code does work.
Can someone shed some light?
It is a bad idea to read a char c with scanf("%s", &c);. "%s" requires a buffer to store a string. The only string which fits into a char is an empty string (consisting only of a terminator '\0' – not very useful). Every string with 1 character requires 2 chars of storage – 1 for the character, 1 for the terminator ('\0'). Providing a char for storage is Undefined Behavior.
So, the first hint was to use the proper formatter instead – "%c".
This is better as it removes the Undefined Behavior. However, it doesn't solve another problem as the following sample shows:
#include <stdio.h>
int cont()
{
char c; do {
printf("Continue (y/n): ");
scanf("%c", &c);
printf("Input %c\n", c);
} while (c != 'y' && c != 'n');
return c == 'y';
}
int main()
{
int i = 0;
do {
printf("Loop iteration %d.\n", ++i);
} while (cont());
/* done */
return 0;
}
Output:
Loop iteration 1.
Continue (y/n): y↵
Input 'y'
Loop iteration 2.
Continue (y/n):
Input '
'
Continue (y/n): n↵
Input 'n'
Live Demo on ideone
WTH?
The scanf("%c") consumes one character from input. The other character (inserted for the ENTER key) stays in input buffer until next call of any input function.
Too bad, without ENTER it is hard to confirm input on console.
A possible solution is to read characters until the ENTER key is received (or input fails for any reasons). (And, btw., getc() or fgetc() can be used as well to read a single character.):
#include <stdio.h>
int cont()
{
int c;
do {
int d;
printf("Continue (y/n): ");
if ((c = fgetc(stdin)) < 0) {
fprintf(stderr, "Input failed!\n"); return 0;
}
printf("Input '%c'\n", c);
for (d = c; d != '\n';) {
if ((d = fgetc(stdin)) < 0) {
fprintf(stderr, "Input failed!\n"); return 0;
}
}
} while (c != 'y' && c != 'n');
return c == 'y';
}
int main()
{
int i = 0;
do {
printf("Loop iteration %d.\n", ++i);
} while (cont());
/* done */
return 0;
}
Output:
Loop iteration 1.
Continue (y/n): y↵
Input 'y'
Loop iteration 2.
Continue (y/n): Hello↵
Input 'H'
Continue (y/n): n↵
Input 'n'
Live Demo on ideone
Please, note, that I changed the type for the read character to int. This is because getc()/fgetc() return an int which is capable to store any of the 256 possible char values as well as -1 which is returned in case of failing.
However, it isn't any problem to compare an int with a character constant (e.g. 'y'). In C, the type of character constants is just int (SO: Type of character constant).

Convert Lowercase Letters to Uppercase in C Language

I'm working on a simple piece of program to incorporate into a larger program. I'm following what my professor has already taught.
#include <stdio.h>
int main()
{
char letter;
printf("Please Enter a Lower Case Letter:");
scanf("%s", letter);
if (letter >= 'a' && letter <= 'z')
letter = letter - 'a' + 'A';
printf("%s", letter);
return 0;
}
The initial 'Please Enter a Lowercase Letter:' appears but after inputting a letter the return is (null). Any help is appreciated.
Maybe try getchar() instead of scanf(). Links to C reference for getchar() and scanf()
#include <stdio.h>
int main()
{
char letter;
printf("Please Enter a Lower Case Letter:");
letter = getchar();
if (letter >= 'a' && letter <= 'z')
letter = letter - 'a' + 'A';
printf("%c", letter);
return 0;
}
scanf("%s", letter); will read a string and copy it to the memory letter points to so pass the pointer of letter instead (scanf("%s", &letter);).
Also use %c instead of %s if you only need one character otherwise scanf can write some unwanted bytes to adjacent memory.
Likewise for the last printf line.

Difficulty using scanf for input

Can someone help me to solve my problem? I have a problem with %[^\n]. When I try to enter a false input the program loop the warning that I wrote, but if I use %s and I enter my string the next statement is not working properly.
#pragma warning (disable:4996)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("input name [1..30 char]: ");
scanf("%[^\n]", name); fflush(stdin);
if ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) {
flag = 1;
}
else {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z)\n");
}
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
else {
flag1 = 1;
}
} while (flag == 0 || flag1 == 0);
do {
printf("Input phone number[6..12 digits]: ");
scanf("%s", number); fflush(stdin);
for (i = 0; i < strlen(number); i++) {
if (number[i] >= '0' && number[i] <= '9') {
flag2 = 1;
}
else {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9)\n");
}
if (strlen(number) >= 6 && strlen(number) <= 12) {
flag3 = 1;
}
else {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits\n");
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
getchar();
return 0;
}
Oh by the way, the problem might simply be that the scanf call leaves the newline in the buffer, and if you loop and try again the first character seen will be the newline and scanf should not read any thing.
There are two things you should do: First check what scanf returns, it should return 1 if it read a string. Secondly you should tell scanf to discard any possible leading white-space by adding a space first in the format string: " %[^\n]".
Most scanf formats automatically skips leading white-space, but not when using the "%[" or "%c" formats.
Also, to not worry about writing out of bounds of the array, you should add a length modifier to make sure that scanf doesn't read more input than it can write: " %29[^\n]". If the length of the string is 29 after this, then you should probably read until you reach the end of the line, character by character.
Here is your program fixed:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
// In case you need this -- not needed for this case
void discard_input()
{
char c;
while( ( c = getchar() ) != '\n' && c != EOF );
}
void remove_trailing_newline(char * s)
{
char * ch = s + strlen( s ) - 1;
while( ch != s ) {
if ( *ch == '\n' ) {
*ch = 0;
break;
}
--ch;
}
return;
}
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("\nInput name [1..30 char]: ");
fgets( name, 30, stdin );
remove_trailing_newline( name );
flag1 = flag = 1;
if ( !isalpha( name[ 0 ] ) ) {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z), found: %s\n", name );
}
// impossible
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
} while (flag == 0 || flag1 == 0);
do {
printf("\nInput phone number[6..12 digits]: ");
fgets( number, 12, stdin );
remove_trailing_newline( number );
flag2 = flag3 = 1;
int len_phone = strlen( number );
for (i = 0; i < strlen(number); i++) {
if ( !isdigit( number[ i ] ) ) {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9), found:'%s'\n", number);
}
if ( len_phone < 6 || len_phone > 12) {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits, found: %d\n", len_phone );
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf( "Name: '%s'\n", name );
printf( "Phone: '%s'\n", number );
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
return 0;
}
You can find the program here.
The fixings are more or less interesting, I enumerate they here:
At first, I thought that the problem was that the trailing new line was being left in the input buffer. fflush(stdin) is actually undefined behaviour in C, since the fflush() function is there for output streams. Anyway, I included the code in question 12.26b of the comp.lang.c FAQ, since I think it is interesing to have it as reference. Then, I decided to change scanf() with fgets(). This is due to the scanf() taking spaces as delimiters, so you wouldn't be able to write a complete name, i.e., name and surname. Remember that gets() is not an option, since it writes the input past the limit of the buffer. Actually, fgets() solves this by letting us define a limit of chars to read. The problem is that fgets() also includes the '\n' in the buffer, so, that's why I included the remove_trailing_newline() function. Tricky, isn't it?
You added a condition to check whether the name input had more than thirty chars. Actually, this is impossible to check in your program. First of all, fgets() will read 29 chars + the final char mark (0). Secondly, if you were actually allowing to input more than 30 chars, then the input would be written past the size of the buffer, which is undefined behaviour (crashes in most cases). You would have to use something more complex, like std::string in C++, and then check its length. Or maybe use a third party expandable string for C. Or roll out your own expandable string...
You can decide whether there is an alphabetic char or a digit by using isalpha(c) and isdigit(c) functions.
When you are going to use a value many times, such as strlen(name), then you should precompute it and store it in a local variable. Though a good compiler (its optimizer) will detect this situation and solve it for you, you never know which compiler is going to compile your code, and how advanced it is. Also, there is nothing wrong making things easier for the optimizer.
When you have a situation in which you set a flag for signaling an error condition, it is easier to set it to the "no error" value before checking anything, and solely in case of an error, set it to the "error" value. This will be easier to read, and therefore, to understand.
Hope this helps.

Accented/umlauted characters in C?

I'm just learning about C and got an assignment where we have to translate plain text into morse code and back. (I am mostly familiar with Java so bear with me on the terms I use).
To do this, I have an array with the strings for all letters.
char *letters[] = {
".- ", "-... ", "-.-. ", "-.. ", ".", "..-." etc
I wrote a function for returning the position of the desired letter.
int letter_nr(unsigned char c)
{
return c-97;
}
This is working, but the assignment specifications require the handling of the Swedish umlauted letters åäö. The Swedish alphabet is the same as the English with these three letters in the end. I tried checking for these, like so:
int letter_nr(unsigned char c)
{
if (c == 'å')
return 26;
if (c == 'ä')
return 27;
if (c == 'ö')
return 28;
return c-97;
}
Unfortunately, when I tried testing this function, I get the same value for all of these three: 98. Here is my main, testing function:
int main()
{
unsigned char letter;
while(1)
{
printf("Type a letter to get its position: ");
scanf("%c", &letter);
printf("%d\n", letter_nr(letter));
}
return 0;
}
What can I do to resolve this?
The encoding of character constants actually depend on your locale settings.
The safest bet is to use wide characters, and the corresponding functions. You declare the alphabet as const wchar_t* alphabet = L"abcdefghijklmnopqrstuvwxyzäöå", and the individual characters as L'ö';
This small example program works for me (also on a UNIX console with UTF-8) - try it.
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main(int argc, char** argv)
{
wint_t letter = L'\0';
setlocale(LC_ALL, ""); /* Initialize locale, to get the correct conversion to/from wchars */
while(1)
{
if(!letter)
printf("Type a letter to get its position: ");
letter = fgetwc(stdin);
if(letter == WEOF) {
putchar('\n');
return 0;
} else if(letter == L'\n' || letter == L'\r') {
letter = L'\0'; /* skip newlines - and print the instruction again*/
} else {
printf("%d\n", letter); /* print the character value, and don't print the instruction again */
}
}
return 0;
}
Example session:
Type a letter to get its position: a
97
Type a letter to get its position: A
65
Type a letter to get its position: Ö
214
Type a letter to get its position: ö
246
Type a letter to get its position: Å
197
Type a letter to get its position: <^D>
I understand that on Windows, this does not work with characters outside the Unicode BMP, but that's not an issue here.
In general encoding stuff is quite complicated. On the other hand if you just want a dirty solution specific to your compiler/platform than add something like this to your code:
printf("letter 0x%x is number %d\n", letter, letter_nr(letter));
It will give hex value for your umlauts. Than just replace in if statements your letter with number.
EDIT You say that you are always getting 98 so your scanf got 98 + 97 = 195 = 0x3C from console. According to this table 0x3C is start of UTF8 sequence for common LATIN SMALL LETTER N WITH Something in Latin1 block. You are on Mac OS X ?
EDIT This is my final call. Quite hackery but it works for me :)
#include <stdio.h>
// scanf for for letter. Return position in Morse Table.
// Recognises UTF8 for swedish letters.
int letter_nr()
{
unsigned char letter;
// scan for the first time,
scanf("%c", &letter);
if(0xC3 == letter)
{
// we scanf again since this is UTF8 and two byte encoded character will come
scanf("%c", &letter);
//LATIN SMALL LETTER A WITH RING ABOVE = å
if(0xA5 == letter)
return 26;
//LATIN SMALL LETTER A WITH DIAERESIS = ä
if(0xA4 == letter)
return 27;
// LATIN SMALL LETTER O WITH DIAERESIS = ö
if(0xB6 == letter)
return 28;
printf("Unknown letter. 0x%x. ", letter);
return -1;
}
// is seems to be regular ASCII
return letter - 97;
} // letter_nr
int main()
{
while(1)
{
printf("Type a letter to get its position: ");
int val = letter_nr();
if(-1 != val)
printf("Morse code is %d.\n", val);
else
printf("Unknown Morse code.\n");
// strip remaining new line
unsigned char new_line;
scanf("%c", &new_line);
}
return 0;
}
Hmmm ... at first I'd say the "funny" characters are not chars. You cannot pass one of them to a function accepting a char argument and expect it to work.
Try this (add the remaining bits):
char buf[100];
printf("Enter a string with funny characters: ");
fflush(stdout);
fgets(buf, sizeof buf, stdin);
/* now print it, as if it was a sequence of `char`s */
char *p = buf;
while (*p) {
printf("The character '%c' has value %d\n", *p, *p);
p++;
}
Now try the same with wide characters: #include <wchar.h> and replace printf with wprintf, fgets with fgetws, etc ...

Resources