String comparision in if statement generates some warnings - c

I'm trying to make a calculator, but my if statement generates some warnings. I am also new to C.
int main(){
float num1;
float num2;
char input[5];
printf("Hello my name is baymax\n");
printf("Enter either add, sub, mult, div:\n");
scanf("%4s", input);
printf("Enter first number\n");
scanf("%f", &num1);
printf("Enter second number\n");
scanf("%f", &num2);
if(input == 'add'){
printf("%.1f + %.1f = %.1f",num1, num2, num1+num2);
....
}
return 0;
}
If the string entered is add, it should add the two numbers. But I get the following warnings when compiling:
calculator.c:19:14: warning: multi-character character constant [-Wmultichar]
if(input == 'add'){
^
calculator.c:19:11: warning: comparison between pointer and integer
('char *' and 'int')
if(input == 'add'){

You have two problems with that code: The first is that 'add' is a multi-character literal, and not a string. A string would use double-quotes like "add".
The second problem is that you can't use equality comparison to compare string, as that will compare the pointers and not the contents of the strings. To compare strings you need to use strcmp.
if (strcmp(input, "add") == 0) { ... }

Here strcmp (http://linux.die.net/man/3/strcmp) is your friend
You need
if (strcmp(input, "add") == 0) ...
PS: Look up the manual page for scanf - It does return a value that you should check

I suppose that this is the line that warns you
if(input == 'add')
In C strings are a derived type, not a native type as int, float, char, etc, so you cannot use them directly.
You have to use a function to compare strings. There are many functions that works on string in the standard library (defined in string.h). They all start with str prefix (well almost all, see manuals).
In your specific case you need strcmp() to compare strings, that will return 0 if they are equal:
if(strcmp(input, "add") == 0)

Related

How do I deal with string input in C?

I'm just practicing C and I would like to make a simple Login program with a username and a password... here is my code:
int main(){
char uname, passwd;
printf("Enter your username: ");
scanf("%c", uname);
printf("Enter your password: ");
scanf("%c", passwd);
printf(" \n");
if (uname == "waw" && passwd == "wow"){
printf("You have logged in\n");
} else {
printf("Failed, please try again\n");
}
return 0;
}
And then I got this error when I try to compile it
log.c: In function ‘main’:
log.c:7:10: warning: format ‘%c’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
scanf("%c", uname);
^
log.c:9:10: warning: format ‘%c’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
scanf("%c", passwd);
^
log.c:13:14: warning: comparison between pointer and integer
if (uname == "waw" && passwd == "wow"){
^
log.c:13:33: warning: comparison between pointer and integer
if (uname == "waw" && passwd == "wow"){
^
1) Don't read (scan) into a char. You need a string. Use format specifier %s instead of %c
2) Use strcmp to compare string values
Try this:
#include <stdio.h>
int main(){
int res;
char uname[40]; // char arrays instead of single char
char passwd[40];
printf("Enter your username: ");
res = scanf("%39s", uname); // Set a maximum number of chars to read to
// 39 to avoid overflow
if (res != 1) exit(1); // Error on stdin. End program
printf("Enter your password: ");
res = scanf("%39s", passwd);
if (res != 1) exit(1); // Error on stdin
printf(" \n");
// Use strcmp to compare values of two strings.
// If strcmp returns zero, the strings are identical
if ((strcmp(uname, "waw") == 0) && (strcmp(passwd, "wow") == 0)){
printf("You have logged in\n");
} else{
printf("Failed, please try again\n");
}
return 0;
}
There is no string data type in C programming language. Strings in C are represented as array of characters.
In C, char is a data type to represent a character. So, all you need to do is declare a array of char data type to represent a string in C. Each element in that array will hold a character of your string.
Also, operators in C like ==, !=, +=, + are defined for build-in data types in C and since, there is no operator overloading in C, you can't use these operators with your C-String as C-Strings are not build-in data type in C programming language.
Note: C-Strings are actually Null-terminated array of char data types. That means, last character in any C-String in C will be used to store a Null Character ('\0') which marks the end of the string.
The Header file <string.h> has predefined functions that you can use to operate on C-String(Null-terminated array of char data type). You can read more about it over here.
So, your program should look like:
#include <stdio.h>
#include <string.h>
#define CSTR_MAX_LEN 100
int main()
{
char uname[CSTR_MAX_LEN+1]; //An extra position to store Null Character if 100 characters are to be stored in it.
char passwd[CSTR_MAX_LEN+1];
printf("Enter your username: ");
scanf("%s", uname);
printf("Enter your password: ");
scanf("%s", passwd);
// Use strcmp to compare values of two strings.
// If strcmp returns zero, the strings are identical
if ((strcmp(uname, "waw") == 0) && (strcmp(passwd, "wow") == 0)){
printf("You have logged in\n");
} else{
printf("Failed, please try again\n");
}
return 0;
}
Remember, the correct format specifier to handle C-Strings are %s in C programming language. So, i have to change your scanf() function call. Also, i have used strcmp() function which is declared in header file <string.h> (i have included this header file in the above program). It returns numeric zero if strings match. You can read more about it above here. Also, have a look at strncmp() which is safer version of strcmp(). Also, remember that it can lead to undefined behavior if you try to access any array out of it's bound. So, it would be good idea to include checking in your program. As, someone included in their answer you can change my scanf() function call to:
scanf("%100s", uname);
It avoids to read more than 100 characters in array uname as it is allocated only to store 100 characters(excluding the Null character).
This is how you can do it with milkstrings
tXt ask(tXt prmp) {
printf("%s ?",prmp) ;
return(txtFromFile(stdin)) ; }
void main(void) {
tXt user = ask("user") ;
if ( strcmp(txtConcat(user,"/",ask("password"),NULL),"waw/wow") == 0)
printf("You have logged in\n");
else
printf("Failed, please try again\n");
}
First of all, you have declared uname and passwd as single characters, but you want to read strings. So you need to define the maximum length for each one and declare them as following:
char [X] uname; //where X is the maximum length for uname, for instance 25
char [Y] passwd; //where Y is the maximum length for passwd, for instance 20
Accordingly, your scanf() function should then be modified to :
scanf("%s", uname);
scanf("%s", passwd);
Apart from that, you need strcmp() to compare a string with a value. Change your if statement to :
if ( (strcmp(uname, "waw") == 0) && (strcmp(passwd, "wow") == 0) ) {
printf("You have logged in\n");

Generating a dice game - C Programming

I'm following a tutorial on youtube and was doing a dice generator.
It basically print out 3 dice result and sum out the dice result.
After which, the user will look at the sum, and based on the sum, the user going to guess whether the next roll is going to be higher,lower, or the same.
Below is my code, suppose, when I typed 'yes', it should be doing the code inside the if statement. However, it went straight to the else statement. Can someone please tell me what's wrong?
int answer;
int guess;
int diceRoll4 = 0;
printf("Would you like to guess your next dice? Y/N \n");
scanf(" %c", &answer);
if (answer == 'yes' ){
printf("What is your guess?\n");
printf("please key in your number \n");
scanf(" %d", &guess);
if (guess > diceRoll4 ){
printf(" You got it wrong, too high!");
}
else if (guess < diceRoll4){
printf(" You got it wrong, too low!");
}
else {
printf("You got it right");
}
}
else{
printf("Thanks for playing");
}
First of all, answer should be an array of chars in order to hold a string. Change
int answer;
to
char answer[10]; //Or any other reasonable size
Secondly, since you want to scan a string and not a character, change
scanf(" %c", &answer);
to
scanf("%9s", answer);
The 9 will scan a maximum of 9 characters (+1 for the NUL-terminator at the end), thus preventing buffer overflows.
I've removed & as %s expects a char* while &answer will give a char(*)[10]. Name of an array gets converted into a pointer to its first element char*, exactly what %s expects. The above scanf is thus equivalent to
scanf("%9s", &answer[0]);
Thirdly, comparing two strings using == compares pointers and not the actual content in them. Use strcmp from string.h instead. It returns 0 when both its arguments hold the same content. Change
if (answer == 'yes' ){
to
if (strcmp(answer, "yes") == 0){
Double quotes are used to denote a NUL-terminated string(char*), which is exactly what strcmp expects, while single quotes, as in your code, is a multi-character literal whose value is implementation-defined.
'yes' is a multi-byte character whose behaviour is implementation-defined.
What you probably want is to read and compare a single char:
if (answer == 'y' ){
or read a whole string and compare:
char answer[128];
scanf("%s", answer);
if ( strcmp(answer,"yes") == 0 ){
...
}
Notice that I changed the type of answer and used %s to read a string.
If you do not want to read in a string, but only a single char where the user can answer either Y or N, you should change int answer; to char answer;. You can then go on using your original scanf()-call. You will still need to change
if (answer == 'yes')
to
if (answer == 'Y')
If you want the user to either type in y or Y you could user toupper() from ctype.h and change your if-condition to if (toupper(answer) == 'Y').
To test the equality you have to use strcmp. If the returning value is 0 it means that they are equal.
if (strcmp(answer, "yes") == 0) {
// ...
} else {
// ...
}
Notes:
Using just answer == 'yes' it test the equality of pointers not value. This is the reason why enters only in else.
Because answer is int you have to change to an array
char answer[15]
As #Sathya mentioned you are reading just a char %c for reading a string you have to use %s
scanf("%s", answer);
Instead of 'yes' which is multi-character character constant change to "yes" that is an array of char with \0 at the end, more informations here.
this line:
if (answer == 'yes' ){
has several problems.
1) the definition of 'answer' is 'int' but the scanf is inputting a single character
2) answer could be compared with 'y' or 'n' but not to a array of char.
3) since the scanf only input a single char
and you/the user input 'yes',
only the first character was consumed,
so the 'es' are still in the input buffer
4) note the the single character could be anything, except white space.
the leading space in the format string would consume any white space.
so the user could input say 'y' or 'Y'
these are different characters
however, using the toupper() macro from ctypes.h
would mean only a 'Y' would need to be compared
5) if you decide to read a string,
then 'answer' needs to be a character array,
say: char answer[10];
and the scanf needs to have a max length modifier
on the associated "%s" input/conversion parameter
so as to avoid the user overflowing the input buffer
and the comparison would be via the strcmp() function
6) always check the returned value (not the parameter value)
from scanf to assure the operation was successful
7) diceRoll4 and guess can never be a negative number
so the variable definitions should be unsigned
and the associated scanf() for guess should use
something like "%u"
8) on the printf() format strings, always end them with '\n'
so the sting will be immediately displayed to the user,
otherwise, they will only be displayed
when a input statement is executed or the program exits

How to use char data type with if in C?

The code is,
#include <stdio.h>
#include <string.h>
main()
{
int a, b, s;
char ch;
LOOP:
printf("enter digits \t");
scanf("%d %d", &a, &b);
s = a + b;
printf("\n answer is %d", s);
printf("\n add another no.? (yes/no) : \t");
scanf("%c", &ch);
if (ch == "yes")
goto LOOP;
if (ch == "no")
printf("\n Okay bye !!! ");
exit(0);
return 0;
}
Can someone tell why this ain't working? When it asks:
Add another no.?
I cant type anything, I type but nothing gets print.
Thx in advanced.
First if you want to store "yes" you will need a char array, not a single char.
Then you can not compare char arrays with string literals like this: ch == "yes", you have to use "string compare", strcmp or strncmp.
"yes" is a char*(or pointer to char), which can't be compared using ==. In this case you need to use the library function strncmp() which compares two strings. Also a char is a data type which typically holds one byte of information in which case a single char cannot contain the 3 character string "yes". In your use of scanf to populate &ch, ch will end up only containing the first char of the input due to char's size.
Your code says to input 1 for yes and 0 for no, whereas you are checking for ch=="yes" and ch =="no".
You can initialize an integer, say, int choice; and then:
printf("\n add another no.? 1 for yes / 0 for no : \t");
scanf("%i", &choice);
if (choice == 1)
goto LOOP;
if (choice == 0){
printf("\n Okay bye !!! ");
exit(0);
}
NOTE that the exit(0) should be inside the if() statement, i.e. between {curly brackets}. When we don't use {curly brackets} with if() statement, only the first piece of code after the if(), that is printf(); in this case, is taken with the if().
Secondly, if you want to use yes and no instead of 1 and 0, then in that case you cant compare a string with == operator. To compare two string you use strcmp function, which returns 0 if the strings are same and some positive or negative value if not same. (that's why we have to use ! operator with strcmp, so that in case strings are same, and the strcmp return 0, !0 becomes 1 which means true and if statement is executed.)
We initialize ch, a string as char ch[5]; and then:
printf("\n add another no.? yes for yes / no for no : \t");
scanf("%s", ch);
if (!strcmp(ch,"yes"))
goto LOOP;
if (!strcmp(ch,"no")){
printf("\n Okay bye !!! ");
exit(0);
}

how to control input data format (C)?

anyone knows an efficient way to check out the format of an scanf'ed data?
e.g. if I try to read an integer and I type a character, how would you do to tell the program that is not correct?
You can check if scanf() succeeds, it returns the number of successful conversions it performed.
You should always check this, before relying on the result since if it failed the variable(s) might contain undefined data leading to undefined results if referenced.
You can use if to check, and re-try with a different conversion specifier on failure:
if(scanf("%d", &x) == 1)
printf("got integer %d\n", x);
else if(scanf("%c", &y) == 1)
printf("got character '%c'\n", y);
else /* more attempts */
Of course it can become troublesome if there are "sub-matches", so the order can matter. It's also way better to split the input processing into two steps for the above:
Read a full line of input using fgets()
Use sscanf() to parse the line
That way you avoid problems due to the input being streamed in:
char line[128];
if(fgets(line, sizeof line, stdin) != NULL)
{
int x;
char y;
if(sscanf(line, "%d", &x) == 1)
printf("got integer %d\n", x);
else if(sscanf(line, "%c", &y) == 1)
printf("got character '%c'\n", y);
}
Note that if you wanted to scan for both an integer and a float, it can still become troublesome since a typical float (such as "3.1416") begins with what is a legal integer. For those cases you can use the strtoXXX() family of functions, which let you check the remainder after doing the conversion.
As you have mentioned in the question that you are playing with numbers and chars only there is a very simple solution as follows
//while reading a char
scanf("%c",&temp);
if(!((temp >= 65 && temp <= 90) || (temp >= 97 && temp <= 122)))
printf("Only characters are allowed!\n");
hope this helps!
scanf("%s", &c);
if(!atoi(c)) puts("You have entered a character");
if(atoi(c) != 0) puts("You have entered an integer");
Scanner sc = new Scanner (System.in);
try {
// assume that the input from the user is not an integer,
// in that case the program cannot convert the input (which is a String) into
// an integer. Because of this situation it'll jump to the 'catch' part of the
// program and execute the code.
int input = Integer.valueOf(sc.nextInt);
// if the input is an integer lines below the above code will be executed.
// Ex. "int x = ( input + 10 ) "
}
catch (Exception ex) {
System.out.println("Invalid input, please retry!");
// if you want to get more information about
// the error use the 'ex' object as follows.
System.out.println(ex);
}

Comparing input character to an array of ints in C

I am kinda new to C and I am having trouble using If statements to compare character input from the user to an int stored in an array.
Eg:
int i[2] = {1,2};
char input[3];
printf("Select option:");
fgets(input,3,stdin);
if(strcmp(*input,i[0]) == 0)
printf("1 chosen");
if(strcmp(*input,i[1]) == 0)
printf("2 chosen");
When compiling I get a warning for both compare statements saying:
warning: passing argument 1 of 'strcmp' makes pointer from integer without cast
warning: passing argument 2 of 'strcmp' makes pointer from integer without cast
I understand that this maybe because Im comparing non-string elements, but how will I cast them then compare them?
When executing I get:
Segmentation fault(core dumped)
Can somebody help?
Nobody yet has explained why what you are doing is incorrect, apart from saying that it is "wrong".
A string in C is just a bunch of consecutive characters in memory, where the last character in the string has a value of zero. You can store a string in a char array, or you can point to somewhere in memory by using a char pointer (char*).
When you input a decimal number, you are reading individual characters that happen to be in the range '0' through to '9', maybe prefixed by an optional '-'. You read these as a string, and if you want to treat them as integers you need to convert them to an integer data type (instead of a series of char values).
That's where something like atoi helps, although it is no longer fashionable. You should use strtol. [There is a whole family of these functions for dealing with unsigned, long long, or combinations thereof, as well as double and float types].
That tackles roughly half of your question. Now, you are using strcmp and expecting it to work. There are a couple of things wrong with what you are doing. The major error is that you can't treat an integer as a string. If you really want to use string comparison, you have to convert the integer to a string. That means you do the reverse of what strtol does.
That's a bigger discussion, and in your case it is not the correct way so I won't go into it. But I'd like to point out that, all things being equal, you are sending the wrong types to strcmp. It expects two char* pointers (const char *, really). What you have done is dereferenced your input pointer to a char for the first element, and then pass an int for the second.
strcmp(*input,i[0])
A pointer is basically just a number. It gives the memory address of some data. In this case, the data is expected to be char type (single bytes). The strcmp function is expecting valid memory addresses (stuff that's actually in your stack or heap). But what you give it is *input (the value of the first character in your input string) and i[0] (the number 1).
Those compiler warnings were telling you something quite important, you know! =)
So, just for completeness (although others have answered this already), you should forget the string comparisons (and make a mental note to learn more about strings in C), and do this:
int value = strtol( input, NULL, 10 );
if( value == i[0] )
printf("1 chosen");
if( value == i[1] )
printf("2 chosen");
There are other ways to go about this. I could talk about how to convert single-digit numbers from a string, but I think I have already ranted for long enough. Hope this is of some help.
Apart from the various methods listed as answers to your qn.
Why don't you take the user input as int??
#include<stdio.h>
int main()
{
int i[2] = {1,2};
int input;
printf("Select option:");
scanf("%d",&input);
if(input==i[0])
printf("1 chosen");
if(input==i[1])
printf("2 chosen");
return 0;
}
You must use scanf instead of fgets:
int input;
printf("Select option:");
scanf("%d", &input);
if (input == i[0])
etcetera.
See http://en.wikibooks.org/wiki/C_Programming/Simple_input_and_output#Input_using_scanf.28.29
Better convert input char to int using atoi function.
http://www.cplusplus.com/reference/cstdlib/atoi/
int i[2] = {1,2};
char input[3];
int opt=0;
printf("Select option:");
fgets(input,3,stdin);
opt = atoi(input);
if(opt== i[0])
printf("1 chosen");
if(opt == i[1])
printf("2 chosen");
You need to compare the input string vs. some known strings. But you're comparing the first character vs. some ints. strcmp() will do what you need if you pass it the right arguments: two strings.
here you are trying to compare a string to an integer using strcmp:
if(strcmp(*input,i[0]) == 0)
that won't work.
you could do that way:
const char *numbers[2] = {"1", "2"};
char input[3];
printf("Select option:");
fgets(input,3,stdin);
if(strcmp(*input, numbers[0]) == 0)
printf("1 chosen");
if(strcmp(*input, numbers[1]) == 0)
printf("2 chosen");
where you compare two strings, instead of comparing a number to a string
or you could convert the input string to an int using sscanf or atoi
int i[2] = {1,2};
char input[3];
int num;
printf("Select option:");
fgets(input,3,stdin);
sscanf(input, "%d", &num);
if(num == i[0])
printf("1 chosen");
else if(num == i[1])
printf("2 chosen");
i didn't compile them though, maybe there's sth which i am missing but that's the general idea
Use atoi. it will convert your string to integer
int i[2] = {1,2};
char input[3];
printf("Select option:");
fgets(input,3,stdin);
if(atoi(input)==i[0]))
printf("1 chosen");
if(atoi(input)==i[1]))
printf("2 chosen");

Resources