I'm trying to make a loop that does not stop until the user inputs a string. For ex. if the user inputs a number or a letter it will say Invalid input until the user enters a string.
But for some strange reason, when I run my code and I input a string, the program continues to loop the block of code. Here's the output
#include <stdio.h>
int main() {
char name[100];
char letter[100];
lt:
printf("\033[0;33m");
printf("\nEnter your Name:\ni.e. Miguel\n");
printf("\033[0m");
scanf("%s", name);
if (name != letter) {
printf("\033[0;31m");
printf("Invalid input");
printf("\033[0m");
goto lt;
}
return0;
}
I've tried the goto function to loop the code but seems like that isn't working.
Uninitialized variables:
char letter[100];
letter is used uninitialized in your code. It's contents are indeterminate. Variables declared with automatic storage aren't implicitly initialised to 0.
Comparing strings:
if (name != letter)
This only compares the pointer addresses (and I believe it invokes undefined behavior), not the contents of the what those pointers point to.
The C standard library provides a function strcmp that compares two strings.
Note: It's declared in string.h.
Buffer overflow vulnerability:
scanf("%s", name);
is similar to using gets (in terms of limiting input). scanf will happily continue to read from stdin until it sees a whitespace, ignore everything to the right hand side of the whitespace, (which leads to more problems down the road) and potentially overflow the buffer.
You could use a field width to limit input:
scanf("%99s", name);
Or even better, use fgets.
fgets(name, sizeof(name), stdin);
It will read at most n - 1 characters and null-terminate the string.
Side-note: fgets will store the \n character in the buffer, which might not be what you want. Here's one way to remove it¹:
name[strcspn(name, "\n\r")] = '\0';
scanf returns the number of successful conversions:
Ignoring the return value of scanf gainsays the 6th commandment of Henry Spencer's "The Ten Commandments for C Programmers":
If a function be advertised to return an error code in the event of
difficulties, thou shalt check for that code, yea, even though the
checks triple the size of thy code and produce aches in thy typing
fingers, for if thou thinkest ``it cannot happen to me'', the gods
shall surely punish thee for thy arrogance.
if (scanf("%99s", name) != 1) {
handle the error here..
}
Using goto:
While that is a legal use, it's discouraged. goto should not be used for such purposes.
Instead, as #SimonGoater suggested, use a while loop.
if the user inputs a number or a letter it will say Invalid input
until the user enters a string.
So the requirements are:
Names should be greater than 1 character.
Names shouldn't have any numbers in them. (But my friends have names with numbers, and even special characters. :-( )
Note:
You can't have a string with one char, unless that char is a null-byte.
Possible Solutions:
As strlen doesn't include the null-terminator, we can use it to calculate the length of the string, and if it equals 1, handle the error accordingly.
Iterate through the buffer character by character, and if you find a number or a special character, handle the error accordingly.
[1] You might want to give this a read for more:
https://codereview.stackexchange.com/q/67608
#include <stdio.h>
#include<conio.h>
#include<string.h>
int main(){
char name[100];
char letter[100]="amir";
lt:
printf("\033[0;33m");
printf("\nEnter your Name:\ni.e. Miguel\n");
printf("\033[0m \n");
scanf("%s",name);
if(strcmp(name, letter) != 0){
printf("\033[0;31m");
printf("Invalid input");
printf("\033[0m");
goto lt;
}
return 0;
}
Related
I'm attempting to learn C and decided to use Visual Studio as a base for where I can practice my code. I have everything set up already and have started writing up code as well but I seem to be running into a problem where I cannot see the user input.
Here is my program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char string[] = "";
char reversed[] = "Placeholder";
printf("Please enter an input string.\n");
scanf("%s", &string);
printf("Your original string is %s\n", string);
printf("The string reversed is %s", reversed);
return 0;
}
When I run this program, the first printf statement is never printed nor is the user input ever shown
anywhere (not in the terminal either). All it says is that the program is running. When I force stop it,
it will say 'Done!' and that's all that ever happens (I have to force stop because I never see the place to input the string therefore the program just keeps running waiting for an input). I just set up Visual Studio so it is possible I missed something and this is an easy fix but not quite sure what it is.
The string you're inputting is empty. First avoid naming variables "string" as in standard libraries there might already be defined one. And try to allocate more space for your string to be able to input data.
`
char str[128];
char reversed[] = "Placeholder";
printf("Please enter an input string.\n");
scanf("%s", &str);
printf("Your original string is %s\n", str);
printf("The string reversed is %s", reversed);
return 0;
`
Also, be sure to read more about arrays, strings and functions in c. The code you've written is probably not gonna work as you've intended.
There are a couple of problems.
You're not allocating any memory for string, so when the user inputs something, its written into memory it doesn't own, resulting in undefined behavior.
Your scanf is wrong,, kind of. You must provide it a pointer to the memory where the input should go, you're providing the address of the pointer. In this case, they're one in the same, but if that was a pointer to heap memory, for instance, &string would not point to the memory you've reserved.
Instead, try something like this:
int main()
{
char string[64] = ""; // string can now hold 63 user-input characters plus
// one for the NUL terminator, which scanf will add
// automatically.
char reversed[] = "Placeholder"; // This reserves at least 12 bytes, 11 for the text plus the NUL terminator.
printf("Please enter an input string.\n");
scanf("%s", string); // string decays to a pointer to where its memory is allocated.
printf("Your original string is %s\n", string);
return 0;
}
Note, you can still overflow your string buffer if you enter (in this case) more >= 64 characters, and you'll be back where you started. I believe there is a way for scanf to limit the amount of input accepted, but will need to look up how. Another option is to use fgets to accept limited input.
I am writing a code to see whether or not the user's input is equivalent to an already stated string. The program loops until the input is the same as the string, using the strcmp function, but for some reason the program does not compare the strings and therefore the loop malfunctions. The code is below:
int main()
{
char passcode[3]="ZZZ";
char input[3];
int check;
while(check!=0)
{
printf("What is the password?\n");
gets(input);
check=strcmp(passcode, input);
}
printf("You crack the pass code!");
return 0;
}
The main problem is here:
char passcode[3]="ZZZ";
char input[3];
A string in C consists of a sequence of characters followed by a null byte. passcode is not large enough to hold the null byte for the string it's initialized with. So when you try to use it as a string by passing it to strcmp it reads past the end of the array. Doing so invokes undefined behavior.
Similarly, input isn't big enough to hold a string big enough to compare against.
You're also not initializing check, so the first time you enter the loop it's value is unknown.
Another problem is the use of gets. This function is dangerous because it does not check if the string the user entered can fit into the given buffer. If is is too big, this again invokes undefined behavior.
Make your arrays larger to hold the user's input as well as the target string, and use fgets instead of gets. You should also change the while loop to do..while since you need to enter the loop at least once.
#include <stdio.h>
int main()
{
char passcode[]="ZZZ"; // array is automatically sized
char input[50];
int check;
do {
printf("What is the password?\n");
fgets(input, sizeof(input), stdin);
check=strcmp(passcode, input);
} while (check!=0);
printf("You crack the pass code!");
return 0;
}
The suggested code above does not recognize the input. It likely wont work and will stuck within the while loop. I would suggest to make it much easier using scanf for the input and then compare the string as you did with strcmp. If input is correct then let in and break out of the while loop. Try this:
#include <stdio.h>
int main()
{
char input[3];
printf ("\nHit the pass code!\npass code: ");
while (input != "ZZZ") {
scanf ("%s",&input);
if (strcmp(input, "ZZZ") == 0){
printf ("\nYou crack the pass code!!\n\n");
break;
} else {
printf ("Wroooong!\n pass code: ");
}
}
return 0;
}
I see what is going on. Your input string is only three three bytes and you are reading using the unsafe gets. The gets is putting the input of ZZZ into the input variable as expected but it is putting the terminating null in the first byte of passcode.
Change the size of your input buffer to 999 and things will work a lot better.
I have to make a code that checks to see whether the Student 1's first name was blank and if it was then ask the user to input a name. However, when I use this code it doesn't display that message. When I press enter the cursor just goes to the next line until I actually type something in. I've tried this with strcmp too and nothing works.
#include <stdio.h>
#include <string.h>
{
char charStudent1FirstName[50] = "";
printf("Please enter Student 1's First name: ");
scanf("%s", &charStudent1FirstName);
if (charStudent1FirstName[0] == '\0')
{
printf("Please input Student 1's first name again: ");
scanf("%s", &charStudent1FirstName);
}
}
Here's what I changed:
Use fgets instead of scanf. This means you will actually see the blank line if that's all that's entered.
Trim the newline from the fgets result.
Use charStudent1FirstName instead of &charStudent1FirstName. You want to pass a char*, not a char**. If your compiler doesn't warn you about this, consider using a different compiler or changing your compilation settings.
Use a loop so the user is prompted to enter a name as many times as necessary until one is entered.
Complete working code:
#include <stdio.h>
#include <string.h>
int main() {
char charStudent1FirstName[50] = "";
while (charStudent1FirstName[0] == 0) {
printf("Please input Student 1's first name: ");
fgets(charStudent1FirstName, 50, stdin);
charStudent1FirstName[strcspn(charStudent1FirstName, "\n")] = 0;
}
printf("First name: %s\n", charStudent1FirstName);
}
There's nothing wrong with the way that you're checking for the empty string. Your issue is that you're using scanf, which is notoriously hard to use. scanf handles whitespace probably not in the way you expect: you want line-based input, but scanf reads a stream of tokens. scanf does not care about newlines, so in your case, it won't read anything until you type in non-whitespace and therefore will not retrieve an empty string.
Instead, you should read an entire line using fgets (or POSIX getline if available) and then parse that line (if necessary) with sscanf. (Note that fgets can leave a newline at the end of the string, so you must strip that off.)
Perhaps beating a dead horse, your usage of scanf is also unsafe because you do not limit the amount of data that it can write to charStudent1FirstName, and consequently a user could easily overflow the destination buffer. While it's possible to jump through some hoops to use scanf safely when reading strings, using fgets/getline would avoid these problems. (Additionally, using fgets/getline would make it more obvious that you should be passing charStudent1FirstName as an argument, not &charStudent1FirstName.)
int main()
{
//Define Variables
char studentName;
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
scanf("%s", &studentName);
printf("\n\n%s", &studentName);
return 0;
}
Seeing the above code, I am only printing to screen out the first word when I type in a sentence.
I know it is a basic thing, but I am just starting with plain C.
Read scanf(3) documentation. For %s is says
s Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character array that is long
enough to hold the input sequence and the terminating null
byte ('\0'), which is added automatically. The input string
stops at white space or at the maximum field width, whichever
occurs first.
So your code is wrong, because it should have an array for studentName i.e.
char studentName[32];
scanf("%s", studentName);
which is still dangerous because of possible buffer overflow (e.g. if you type a name of 32 or more letters). Using %32s instead of %s might be safer.
Take also the habit of compiling with all warnings enabled and with debugging information (i.e. if using GCC with gcc -Wall -g). Some compilers might have warned you. Learn to use your debugger (such as gdb).
Also, take the habit of ending -not starting- your printf format string with \n (or else call fflush, see fflush(3)).
Learn about undefined behavior. Your program had some! And it misses a #include <stdio.h> directive (as the first non-comment significant line).
BTW, reading existing free software code in C will also teach you many things.
There are three problems with your code:
You are writing a string into a block of memory allocated for a single character; this is undefined behavior
You are printing a string from a block of memory allocated for a single character - also an undefined behavior
You are using scanf to read a string with spaces; %s stops at the first space or end-of-line character.
One way to fix this would be using fgets, like this:
char studentName[100];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
fgets(studentName, 100, stdin);
printf("\n\n%s", &studentName);
return 0;
Try scanf("%[^\n]", &studentName); instead of scanf("%s", &studentName);
This is happening because %s stops reading the input as soon as a white space is encountered.
To avoid this what you can do is declare an array of the length required for your string.
Then use this command to input the string:-
scanf("%[^\n]s",arr);
This way scanf will continue to read characters unless a '\n' is encountered, in other words you press the enter key on your keyboard. This gives a new line signal and the input stops.
int main()
{
//Define Variables
char studentName[50];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
scanf("%[^\n]s", &studentName);
printf("\n\n%s", &studentName);
return 0;
}
Alternatively you can also use the gets() and puts() method. This will really ease your work if you are writing a code for a very basic problem.
[EDIT] : As dasblinkenlight has pointed out...I will also not recommend you to use the gets function since it has been deprecated.
int main()
{
//Define Variables
char studentName[50];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
gets(studentName); printf("\n\n");
puts(studentName);
return 0;
}
make the changes below and try it. I added [80] after the studentName definition, to tell the compiler that studentName is an array of 80 characters (otherwise the compiler would treat it as only one char). Also, the & symbol before studentName is not necessary, because the name of the array implicitly implies a pointer.
int main()
{
//Define Variables
char studentName[80];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
scanf("%s", studentName);
printf("\n\n%s", studentName);
return 0;
}
Your problem is here
char studentName;
It is a char, not a string.
Try:
Define it as an array of chars like char studenName[SIZE];.
allocating memory dynamically using malloc:
.
char buffer[MAX_SIZE];
scanf("%s", &buffer);
char * studentName = malloc (sizeof(buffer) + 1);
strcpy (studentName , buffer);
I am writing a super simple command line based program in C. It's just a small test and the code is very simple. So what it is meant to do is to ask the user for their name, maths grade, english grade, computing grade. Then it figures out their average grade and also tells them the name they entered. Yes I know this is an extremely simple program, but I'm still doing something wrong.
The problem is, one part of my code will run first telling the user to enter their name and then once they do this and press enter the rest of my code will run all at once and then stop working. It's weird I just don't understand what is wrong.
#include <stdio.h>
int main(int argc, const char * argv[])
{
char chr;
char firstname;
int mathsmark, englishmark, computingmark, averagemark;
printf("What is your name?\n");
scanf("%c", &firstname);
printf("\n");
printf("What is your maths mark?\n");
scanf("%d", &mathsmark);
printf("\n");
printf("What is your english mark?\n");
scanf("%d", &englishmark);
printf("\n");
printf("What is your computing mark?\n");
scanf("%d", &computingmark);
printf("\n");
printf("Your name is: %c", firstname);
printf("\n");
averagemark = (mathsmark + englishmark + computingmark) / 3;
printf("%d", averagemark);
printf("\n");
chr = '\0';
while (chr != '\n') {
chr = getchar ();
}
return 0;
}
One major problem is that you've declared firstname to be a single character long, and when you try to read the name from the console, you're using the %c conversion specifier, which reads the next single character from the input stream and stores it to firstname. The remainder of the name is left in the input stream to foul up the remaining scanf calls.
For example, if you type "Jacob" as a first name, then the first scanf call assigns J to firstname, leaving "acob\n" in the input stream.
The next scanf call attempts to convert "acob\n" to an integer value and save it to mathsmark, which fails ("acob\n" is not a valid integer string). Same thing happens for the next two scanf calls.
The last loop
while (chr != '\n')
{
chr = getchar();
}
finally consumes the rest of "acob\n", which contains the newline character (because you hit Enter after typing the name), causing the loop and program to exit.
How do you fix this?
First, you need to declare firstname as an array of char:
char firstname[SOME_SIZE] = {0};
where SOME_SIZE is large enough to handle all your cases. The you need to change scanf call to
scanf("%s", firstname);
This tells scanf to read characters from the input stream up to the next whitespace character and store the results to the firstname array. Note that you don't need to use the & operator here; under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array.
Note that scanf is not very safe, and it's not very robust. If you enter more characters than your buffer is sized to hold, scanf will happily store those extra characters to memory following the array, potentially clobbering something important. You can guard against this by using an explicit field width in the conversion specifier, like
scanf(*%29s", firstname);
but in general it's a pain.
scanf is also not very good at detecting bad input. If you enter "12er" as one of your marks, scanf will convert and assign the "12", leaving the "er" in the stream to foul up the next read.
scanf returns the number of successful assignments, so one way to guard against bad input is to check the return value, like so:
if (scanf("%d", &mathmarks) != 1)
{
printf("Bad input detected for math marks\n");
}
Unfortunately, scanf won't remove bad characters from the stream; you'll have to do that yourself using getchar or similar.
This is a common mistake amongst newer C/C++ developers. The scanf function detects you hitting the ENTER/RETURN key to signal the end of input, but it also catches the \n character as well at the end of the input string, so you essentially get two RETURNS being detected.
Please read up on an example of using fgets and sscanf here:
http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html
It will resolve this issue very quickly for you. In the meantime, I strongly urge you to check out this book:
http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965
It is the most commonly used C programming book in high school and colleges in North America, and has TONS of examples for you to work through, including this specific program you demonstrated above. The print version has more examples than the e-book, so I would just cough up the $30.00 for the printed version.
Good luck!
You might want to look at a few tutorials. Maybe one on Format specifiers and one on strings in C
scanf() reads data from stdin and stores them as specified by the format specifiers. In this case:
char firstname;
scanf("%c", &firstname);
Read 1 character from stdin and store it to firstname:
>> What is your first name?
Mike
Now firstname == 'M' because scanf() read 1 character as we requested.
What you wanted to do was read a string (a bunch of characters):
char firstname[5]; // an array of characters
scanf("%s", firstname); // store as a string
firstname[4] = '\0'; // Truncate the result with a NULL to insure no overflow
>> What is your first name?
Mike
Now firstname is [M][i][k][e][\0] because scanf() read 1 string, as we requested.
Note the same holds true for printf(), a printf with a %c will give you one character where as a printf() with a %s will give you all the characters until the NULL terminator.
You have (at least) two choices.
char firstname[number_big_enough_to_hold_long_name];
/*or */
char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);
Further it would be best to limit width of read. scanf() does not know the size (available space) of firstname.
scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */
char firstname[32];
if(scanf("%31s", firstname) == EOF) {
perror("bad");
return 1;
}
Further you should check if there is anything left before trying next read. I.e. If someone enters "My Name" then only "My" will end up in firstname and "Name" will be left in input stream.
And getchar() returns an int not a char.
getchar
scanf
And search "ansi c char arrays tutorial" or similar.