How do I deal with string input in C? - 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");

Related

'scanf_s' function doesn't work well in my C project

My code:
#include <stdio.h>
int main() {
char words[30];
printf("Please typing text under 30 text!:");
scanf_s("%s", words);
printf("text: %s \n", words);
return 0;
}
The error I get:
Missing integer argument to 'scanf_s' that corresponds to coversion
specifier '2', 'scanf_s' not enough arguments passed for format string
Consider using fgets instead if you're simply reading everything into a string buffer. It's simpler and more portable:
char buffer[31]; // 1 extra for the zero terminator
printf("Please enter text with less than %zu characters\n", sizeof(buffer) - 1);
if (!fgets(buffer, (int)sizeof(buffer), stdin)) {
puts("Failed to read input");
} else {
// use input
}
As you can see in the scanf_s documentation:
specifiers each expect two arguments (the usual pointer and a value of
type rsize_t indicating the size of the receiving array, which may be
1 when reading with a %c into a single char)
I.e. for each argument you want scanf_s to parse, you need to pass its size.
Also scanf family return the number of arguments parsed, and you should check it to find out if it actually succeeded.
In your case change the scanf_s line to:
int n = scanf_s("%s", words, sizeof(words));
if (n != 1)
{
// handle error
}
Note that sizeof(words) works here because it is an array allocated on the stack. If you allocate it as a pointer with malloc family you'll need to pass the right size (because then sizeof will return the size of the pointer itself).
Try this code:
#include <stdio.h>
int main() {
char words[30];
printf("Please typing text under 30 text!:");
scanf_s("%s", words,30);
printf("text: %s \n", words);
return 0;
}
Also, you could put sizeof(words) instead of 30 as someone suggested (note that this is only possible if you are working with static memory).
If you are using scanf_s, I think you want to ensure to read n symbols.
Someone already suggested you to use fgets. Another possible solution is to use memcpy (you will read the exact bytes):
#include <stdio.h>
int main() {
char words[30];
char words2[30];
printf("Please typing text under 30 text!:");
scanf("%s", words);
memcpy(words2,words,sizeof(char)*30);
words2[sizeof(char)*30]='\0';
printf("text: %s \n", words2);
return 0;
}

How to check when you scanf that you get only integer (like 2) and not integer followed by char (like 2c)

I'm trying to scanf an integer to see if it's legal in my program. However, if I input a number followed by a char it still treats it as legal number (my guess is that it only refers to the integer while saving the char in the buffer). Assume I can only use scanf and not something else (since that's what we've leraned). Also, if I input only a char it automatically casts it to an integer. This is what I have tried so far, with the help of what I saw here -
int number_of_numbers;
char number='\n';
printf("Enter size of input:");
if (scanf("%d%c",&number_of_numbers, &number)>=1 && number!='\n')
{
printf("Invalid size");
return 0;
}
How can I identify when I scanf only an integer or an integer followed by a char or just a char?
Thanks!
If you enter "only a character" it does not "automatically cast it to an integer". It does not accept any input at all, as shown by scanf returning 0, but that situation escapes your test.
But the answer to your question is: with difficulty when using scanf.
Here is a way to do it getting the input with fgets. It will tolerate any amount of whitespace before or after the number, but not any letters.
The reason for the space before %c is to instruct it to filter any leading whitespace. This is automatic anyway for %d, but not for %c. Then if there are no readable characters, nothing will be read into extra. If there is at least one character (apart from whitespace) then the sscanf conversion count will be incorrect.
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
int number_of_numbers = 0;
while(number_of_numbers >= 0) {
bool success = false;
char str[100];
if(fgets(str, sizeof str, stdin) != NULL) {
char extra;
if(sscanf(str, "%d %c", &number_of_numbers, &extra) == 1) {
success = true;
}
}
if(success) {
printf("Success: %d\n\n", number_of_numbers);
} else {
printf("Invalid size\n\n");
}
}
return 0;
}
Program session:
123
Success: 123
123a
Invalid size
123 a
Invalid size
123 9
Invalid size
a
Invalid size
-1
Success: -1
The reasons for using fgets are
it doesn't "stall" if there is invalid input: it has already been read.
if there is a mistake, the string can easily be dumped and another one requested.

String comparision in if statement generates some warnings

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)

Want to make c program app for bank

I have made the structure, but I'm stuck at the last point where I have to perform if/else coding. This is my very first program, using some tutorials on web.
The code is below:
#include<stdio.h>
#include<conio.h>
int main()
{
char fName;
char mName;
char lName;
int dob;
int branch;
int brcode;
char * pbprint;
printf("\tWELCOME TO BANK OF KANPUR :: ONE HAND ROLE TO YOUR SUCCESS");
printf("\n\n\n Customer Detail Form");
printf("\n ---------------------");
printf("\n\n\tCustomer Entity ");
printf("\n ");
printf("\n\n\n Customer's First Name : ");
scanf("%s", &fName);
printf("\n Customer's Middle Name : ");
scanf("%s", &mName);
printf("\n Customer's Last Name : ");
scanf("%s", &lName);
printf("\n\n\tDate of Birth ");
printf("\n ");
printf("\n\n\nDate[DD] : ");
scanf("%d", &dob);
printf("\nMonth[MM] : ");
scanf("%d", &dob);
printf("\nYear[YYYY] : ");
scanf("%d", &dob);
printf("\n\n\tBranch Details ");
printf("\n ");
printf("\n\n\nBranch Code : ");
scanf("%d", &brcode);
printf("\n\n\tPrinter ");
printf("\n ");
printf("\n\n\nWould You Like Us To Print Your Passbook [Y/N] : ");
scanf("%s", &pbprint);
// please help how to make if else statement here
// how to make the condition when if I enter yes it should show your
// printing is done else your printing is not done.
getchar();
return 0;
}
You are reading a string from console. If I understood, a simple way is to check only the first char from the string. You can do this:
if ( (pbprint[0] == 'Y') || (pbprint[0] == 'y') )
{
printf("your printing is done");
}
else
{
printf("your printing is not done");
}
The user is usually very creative, so you can choose how smart and versatile your input interface should be.
First of all change your variable declaration from char to char array, as you want strings to be entered. I am considering maximum you will enter 19 characters in strings so you variable declaration will look as below:
char fName[20];
char mName[20];
char lName[20];
char pbprint; // This is just character as you want single character input
You can change your taking character input as below:
printf("\n\n\nWould You Like Us To Print Your Passbook [Y/N] : ");
scanf(" %c",&pbprint); // Notice whitespace in the format string
if((pbprint == 'Y') || (pbprint == 'y')) // now you can do single character comparison
{
printf("Yes");
}
else
{
printf("No");
}
I hope this helps you to take single character input
Issue #1: You need to set aside space to store string data. The char datatype only allocates space for a single character value ('A', 'j', etc.). Strings are sequences of char values followed by a single 0-valued byte, so you need to set aside arrays of char large enough to hold a name plus the 0 terminator.
So, your name variables need to be declared as arrays of char:
#define NAME_LEN 30 // make this as big as you need
char fName[NAME_LEN + 1]; // Add a space for the 0 terminator
char mName[NAME_LEN + 1];
char lName[NAME_LEN + 1];
To read these using scanf, you would write
scanf( "%s", fName ); // note no & operator
The %s conversion specifier expects its corresponding argument to be a pointer to the first element of an array of char. Under most circumstances, an array expression (such as fname in the call above) will automatically be converted to a pointer, so you don't need to use the & operator in this case.
For safety's sake, you should check the result of the scanf call; it will return the number of successful conversions and assignments (0 if none of the conversions are successful), or EOF if it sees an end-of-file or error condition. You should also specify the maximum number of characters to be read within the conversion specifier; otherwise, if you type in more characters than your destination array is sized to hold, scanf will happily attempt to store those extra characters in the memory past the end of your array, leading to anything from corrupted data to a smashed stack to an outright crash:
if ( scanf( "%30s", fName ) == 1 ) // expect one successful conversion and assignment
{
// successfully read fName
}
else
{
// problem during read
}
Unfortunately, the length has to be "hard coded" into the conversion specifier. You can get around this by using some less-than-intuitive preprocessor macros:
#define S2(x) #x // surrounds x with double quotes
#define S1(x) S2(x) // causes x to be expanded before being passed to S2
#define E1(x) x // causes x to be expanded
#define FMT(x) S1(%E1(x)s) // writes a %xs conversion specifier, where
// x is the max length
Then you can write something like
if ( scanf( FMT(NAME_LEN), &fName ) == 1 )
which will expand out to
if ( scanf( "%30s", &fName ) == 1 )
The S2 and E1 macros look redundant, but they are necessary; you want to "expand" the argument x before applying the # operator to it. If we wrote
#define S1(x) #x
#define FMT(x) S1(%xs)
...
if ( scanf( FMT(NAME_LEN), &fName ) == 1 )
it would expand out to
if ( scanf( "%xs", &fName ) == 1 )
which is not what we want.
Issue #2: Simply declaring a pointer does not set aside storage for the thing you are pointing to. The declaration
char * pbprint;
creates the pointer variable pbprint, but it doesn't allocate any memory for the thing we want to point to. In this particular case, if all you want to store is a y or n value, then declare pbprint as a regular char and read using the %c conversion specifier, like so:
#include <ctype.h>
...
char pbprint;
...
if ( scanf( " %c", &pbprint ) == 1 ) // note leading blank in format string
{
if ( tolower( pbprint ) == 'y' ) // convert to lower case for comparison
{
// show print output
}
else
{
// don't show print output
}
}
else
{
// error on input
}
The leading blank before the %c conversion specifier is necessary to skip over any leading whitespace in the input stream; otherwise, you risk picking up a newline character from a previous entry, which isn't what you want here.
We also use the tolower library function (declared in ctype.h) to convert the input character to lower case for comparison. That way we don't have to write distinct branches for lowercase and uppercase letters.

Using the scanf() function

I intend to modify each other letter of a particular string. But for the purposes of this program none of that occurs. So far I've grabbed a string from the user and stored it in userinput and intend to print it.
#include <stdio.h>
#include <string.h>
int main(void) {
char userinput[256] ="";
printf("Enter somthing to change:\n");
scanf("%s", &userinput);
printf("%s\n", userinput);
int k = 2; // This is just here to do something every time k is even
int j = strlen(userinput);
for (int i = 0; i < j; i++) {
if(k % 2 == 0) {
printf("%s", userinput[i]);
k++;
}
else {
printf("%s", userinput[i]);
k++;
}
}
}
The strlen() function however does not work on the userinput. I figure this is because strlen() is supposed to take the address of the first char of a string and then iterate until reaching a null char but scanf doesn't actually create a null char.
I couldn't figure out a way of adding the '\0' after the string without first knowing the length of the string.
How would I go about accessing the length of a stored character sequence if it's stored in an array?
This:
scanf("%s", &userinput);
should be:
scanf("%s", userinput);
The address of operator & is unrequired, and incorrect. Arrays decay to the address of their first element when passed to a function. scanf("%s") will append a null terminating character so it is unnecessary to explicitly insert one.
To prevent potential buffer overrun specify the maximum number of characters that scanf() should write to userinput. This should be one less than the size of userinput, leaving room for the terminating null character:
scanf("%255s", userinput);
The incorrect format specifier (which is undefined behaviour) is being used to print the characters of userinput: use %c not %s. This:
printf("%s", userinput[i]);
must be:
printf("%c", userinput[i]);
Change
scanf("%s", &userinput);
to
scanf("%s", userinput);
The & operator is not required in the case of String capture. The scanf() automatically appends the null character('\0') to the end of the string so int j = strlen(userinput); should work.
If you still want to calculate the length without this function efficiently here is the link How to calculate the length of a string in C efficiently?
Change this
scanf("%s", &userinput);
with
scanf("%s", userinput);
we have to use addresses for scanf:
If we will scan into an int a then we have to call scanf() with the address of a => &a
If we will scan into a double a then we have to call scanf() with the address of a => &a
But If we will scan data into with pointer (memory address) int *a; or char array char a[50]; then we have to call scanf() with the pointer or with the array without adding &
From the scanf() page
Depending on the format string, the function may expect a sequence of
additional arguments, each containing a pointer to allocated storage
where the interpretation of the extracted characters is stored with
the appropriate type. There should be at least as many of these
arguments as the number of values stored by the format specifiers.
Additional arguments are ignored by the function. These arguments are
expected to be pointers: to store the result of a scanf operation on a
regular variable, its name should be preceded by the reference
operator (&) (see example).
You're confused about types, as others have indicated. Using scanf and printf when you're confused about types is dangerous!
scanf("%s", &userinput);
The type of &userinput is char (*)[256], but scanf expects %s to correspond to a char *. Since the type expected and the type given differ and aren't required to have the same representation, the behaviour is undefined.
I figure this is because strlen is supposed to take the address of the
first char of a string and then iterate until reaching a null char but
scanf doesn't actually create a null char.
Wrong. scanf certainly does assign a null character, when you use the %s format specifier. That is, providing scanf doesn't encounter an error or EOF. On that note, you should probably check for errors from scanf:
if (scanf("%s", userinput) != 1) {
/* Insert error handling here */
}
... as you should with all standard library functions in C.
k is pointless. Your loop already increments i at the same frequency as k.
strlen returns a size_t. Make sure you store return values in the right types. If a function returns size_t, then you store the return value in size_t. If a function returns int, then you store the return value in an int. Got it? Whatever the return type is, is whatever type you use to store the return type. Use the manual to find that out.
printf("%s", userinput[i]);
There's that type confusion again. userinput[i] is a char. %s tells printf to expect a char *. When the argument is invalid, the behaviour is undefined. That may cause your program to malfunction. Consider printf("%c", userinput[i]); or printf("%s", &userinput[i]);.

Resources