How to print different strings depending on the input? - c

I want one message to appear if the name Emily or Jack is entered and a different message for another input.
My code:
#include <stdio.h>
#include <string.h>
int main()
{
char name;
printf("What is your name?");
gets(name);
if ((strcmp(name,"Emily") == 0) || (strcmp(name,"Jack") == 0))
{
printf("Hello %s\n", name);
} else
{
printf("Welcome Stranger!\n");
}
return 0;
}
This code will compile but won't output anything.

The first problem is that name can store exactly one char, to store a string of characters you'll need a char array.
The second problem, not causing the faulty behavior but equaly important, is the use of gets. This function was deprecated in C99 and removed from the international standard with C11, and for good reason, it's very dangerous as it can easily overflow the destination buffer, it has no control over the length of the input stream. fgets is regularly used instead.
char name[256]; //array store the name
//...
fgets(name, sizeof name, stdin); //safe, can't overflow the buffer, input size is limited
name[strcspn(name, "\n")] = '\0'; //fgets parses the newline character, it must be removed
//...

Related

Why does gets() read in more characters to the pointer than the limit I set it when initializing it with calloc()? [duplicate]

This question already has answers here:
Why is the gets function so dangerous that it should not be used?
(13 answers)
Closed 4 years ago.
I'm trying to get a hold of dynamic memory allocation and I just want my program to get a string and the max number of characters that should be printed from the string from the user, then just output the string up to the number of characters I allocated with calloc. When I run the program, it completely disregards the limit I set for it using calloc() and just prints out the whole string.
I tried using malloc but had the same results. Also, I dereferenced text when I first tried printing out the inputted text but it caused the program to stop after you entered the string you wanted printed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int max;
char *text = NULL;
printf("\n\n");
printf("Please enter the limit for the string as a positive integer: \n");
scanf("%d", &max);
text = (char *)calloc(max, sizeof(char));
if (text != NULL)
{
printf("Please enter the string you want printed: \n");
scanf(" "); //read in next character so it pauses
gets(text);
printf("Inputted text is : %s\n", text);
}
free(text);
text = NULL;
return 0;
}
Yes, I know, I get the warning that gets is unsafe but I was watching from a tutorial and the instructor's version built and ran fine. Even if I use scanf to read in a string into text, the result it the same.
Revised code using fgets():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int max;
char *text = NULL;
printf("\n\n");
printf("Please enter the limit for the string as a positive integer: \n");
scanf("%d", &max);
text = (char *)calloc(max, sizeof(char));
if (fgets(text, max, stdin))
{
printf("Please enter the string you want printed: \n");
fgets(text, max, stdin);
text[strcspn(text, "\n")] = '\0';
printf("Inputted text is : %s\n", text);
}
free(text);
text = NULL;
return 0;
}
I changed my code to use fgets instead and made some corrections. It returns 1 less character than the "max" the user inputs. Also, does using fgets mean I don't need to bother with calloc?
When you allocate memory and assign it to a pointer, there is no way to deduce the size of the memory from the pointer in hand. So gets has no chance (and will therefore not check) if it will exceed the amount of memory you reserved. BTW: gets is not part of C standard any more (since C11). Use fgets instead and pass your max as argument:
if (fgets(text, max, stdin)) {
// something successfully read in
text[strcspn(text, "\n")] = '\0';
}
Note that fgets, in contrast to gets, preserves any entered new line and keeps it at the end of text. To get rid of this, you can use text[strcspn(text, "\n")] = '\0', which will let the string end at the new line character (if any).
I think the exact reason your code is disregarding the max variable is that the gets() function is writing over all the null bytes in your text character array when the string provided on standard input is longer than max. This is one of the many reasons why we always say “never use gets()”!
More specifically, gets() will continue to write into your array from stdin until it reaches a newline or EOF character, with no regard to the bound of it. The fact that you’re seeing the entire string printed if just undefined behavior.

Add two strings in C

How would I add a string to a string that I get from scanf?
Do this:
char animal[size];
scanf("%s", animal);
Then add "Is it a animal?" to whatever is input, then return the whole thing as animal again.
For example if I input 'duck' for animal, it will make animal return "Is it a duck?"
Also, should I add the ? to animal first then add "Is it a "?
Here is a quick and dirty working example of how this could be done.
However, it is not very safe/foolproof. E.g., you can easily overrun the animal buffer with scanf(). Also, if you change the format of the string in sprintf(), you'll need to make sure str has enough room.
#include <stdio.h>
int main()
{
char animal[20];
char str[29];
animal[19] = 0; /* make sure animal is 0-terminated. Well, scanf() will 0-term it in this case anyway, but this technique is useful in many other cases. */
printf("Name the beast (up to 19 characters): ");
scanf("%s", animal);
sprintf( str, "Is it a %s?", animal );
puts(str);
return 0;
}
And here is a somewhat improved version. We make sure that we don't read more characters than the animal buffer can hold, define a pre-processor macro for the maximum animal name length for easier maintenance, trap the case when the user entered more characters than asked, get rid of the newline that terminates user input.
#include <stdio.h>
#include <string.h>
#define MAX_ANIMAL_NAME_LEN 9
int main()
{
/* 1 char for 0-terminator + 1 to catch when a user enters too
many characters. */
char animal[MAX_ANIMAL_NAME_LEN + 2];
char str[MAX_ANIMAL_NAME_LEN + 11];
printf("Name the beast (up to %d characters): ", MAX_ANIMAL_NAME_LEN);
fgets( animal, MAX_ANIMAL_NAME_LEN + 2, stdin );
{
/* fgets() may include a newline char, so we get rid of it. */
char * nl_ptr = strchr( animal, '\n' );
if (nl_ptr) *nl_ptr = 0;
}
if (strlen(animal) > MAX_ANIMAL_NAME_LEN)
{
fprintf( stderr, "The name you entered is too long, "
"chopping to %d characters.\n", MAX_ANIMAL_NAME_LEN );
animal[MAX_ANIMAL_NAME_LEN] = 0;
}
sprintf( str, "Is it a %s?", animal );
puts(str);
return 0;
}
As other users have pointed out, strings in C, as the C language itself, can get fairly tricky pretty fast. Further improvements will be your homework. Search engines are your friends. Happy learning!
One treacherous pitfall you may want to beware is that there is still input to be read from STDIN if the user has typed more than fgets() wanted to accept. If you call fgets() or some other input function later on, you will read those extra characters, which is probably not what you wanted! Please see the following posts:
How to clear input buffer in C?
C: Clearing STDIN
Thanks to chux for pointing this out.
If you just want to display the message of "Is it a ___?" you can just output it like
char animal[size];
scanf("%s", animal);
printf("Is it a %s?", animal);
How would I add a string to a string that I get from a scanf?
Adding two different strings,.
#include <stdio.h>
#include <string.h>
int main(void)
{
char animal[20], text1[20] = "Is it a ";
scanf("%11s", animal);
strcat(text1, animal);
printf("%s\n", text1);
return 0;
}

too few arguments to function 'fgets' in C

Whenever I compile this I get that error, and I am not sure why. I am copying this straight out of a book. Can anyone help?
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[256];
printf("Enter your name and press enter:\n");
fgets(buffer);
printf("Your name has %d characters and spaces!", strlen(buffer));
return 0;
}
Use fgets() because the gets() function is a common source of buffer overflow vulnerabilities and should never be used.
char *fgets(char *str, int n, FILE *stream)
str -- This is the pointer to an array of chars where the string read
is stored.
n -- This is the maximum number of characters to be read (including
the final null-character). Usually, the length of the array passed as
str is used.
stream -- This is the pointer to a FILE object that identifies the
stream where characters are read from.
fgets takes three parameters. Did they mean gets perhaps?
The book's code fgets(buffer); does not match any C compiler using standard libraries. Code corrected below.
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[256];
printf("Enter your name and press enter:\n");
// fgets(buffer);
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
// Remove potential \n
buffer[strcspn(buffer, "\n")] = 0;
// printf("Your name has %d ...
printf("Your name has %zu characters and spaces!\n", strlen(buffer));
}
return 0;
}
fgets() takes 3 parameters: buffer, size, stream.
char *fgets(char * restrict s, int n, FILE * restrict stream);
Always check return value with I/O functions.
Remove potential '\n' as printf(..."characters and spaces" ...) reports as if \n was not there.
strlen() return type size_t. To print, use specifier "%zu".

Reading string from input with space character? [duplicate]

This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 4 years ago.
I'm using Ubuntu and I'm also using Geany and CodeBlock as my IDE.
What I'm trying to do is reading a string (like "Barack Obama") and put it in a variable:
#include <stdio.h>
int main(void)
{
char name[100];
printf("Enter your name: ");
scanf("%s", name);
printf("Your Name is: %s", name);
return 0;
}
Output:
Enter your name: Barack Obama
Your Name is: Barack
How can I make the program read the whole name?
Use:
fgets (name, 100, stdin);
100 is the max length of the buffer. You should adjust it as per your need.
Use:
scanf ("%[^\n]%*c", name);
The [] is the scanset character. [^\n] tells that while the input is not a newline ('\n') take input. Then with the %*c it reads the newline character from the input buffer (which is not read), and the * indicates that this read in input is discarded (assignment suppression), as you do not need it, and this newline in the buffer does not create any problem for next inputs that you might take.
Read here about the scanset and the assignment suppression operators.
Note you can also use gets but ....
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
Try this:
scanf("%[^\n]s",name);
\n just sets the delimiter for the scanned string.
Here is an example of how you can get input containing spaces by using the fgets function.
#include <stdio.h>
int main()
{
char name[100];
printf("Enter your name: ");
fgets(name, 100, stdin);
printf("Your Name is: %s", name);
return 0;
}
scanf(" %[^\t\n]s",&str);
str is the variable in which you are getting the string from.
The correct answer is this:
#include <stdio.h>
int main(void)
{
char name[100];
printf("Enter your name: ");
// pay attention to the space in front of the %
//that do all the trick
scanf(" %[^\n]s", name);
printf("Your Name is: %s", name);
return 0;
}
That space in front of % is very important, because if you have in your program another few scanf let's say you have 1 scanf of an integer value and another scanf with a double value... when you reach the scanf for your char (string name) that command will be skipped and you can't enter value for it... but if you put that space in front of % will be ok everything and not skip nothing.
NOTE: When using fgets(), the last character in the array will be '\n' at times when you use fgets() for small inputs in CLI (command line interpreter) , as you end the string with 'Enter'. So when you print the string the compiler will always go to the next line when printing the string. If you want the input string to have null terminated string like behavior, use this simple hack.
#include<stdio.h>
int main()
{
int i,size;
char a[100];
fgets(a,100,stdin);;
size = strlen(a);
a[size-1]='\0';
return 0;
}
Update: Updated with help from other users.
#include <stdio.h>
// read a line into str, return length
int read_line(char str[]) {
int c, i=0;
c = getchar();
while (c != '\n' && c != EOF) {
str[i] = c;
c = getchar();
i++;
}
str[i] = '\0';
return i;
}
Using this code you can take input till pressing enter of your keyboard.
char ch[100];
int i;
for (i = 0; ch[i] != '\n'; i++)
{
scanf("%c ", &ch[i]);
}
While the above mentioned methods do work, but each one has it's own kind of problems.
You can use getline() or getdelim(), if you are using posix supported platform.
If you are using windows and minigw as your compiler, then it should be available.
getline() is defined as :
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
In order to take input, first you need to create a pointer to char type.
#include <stdio.h>
#include<stdlib.h>
// s is a pointer to char type.
char *s;
// size is of size_t type, this number varies based on your guess of
// how long the input is, even if the number is small, it isn't going
// to be a problem
size_t size = 10;
int main(){
// allocate s with the necessary memory needed, +1 is added
// as its input also contains, /n character at the end.
s = (char *)malloc(size+1);
getline(&s,&size,stdin);
printf("%s",s);
return 0;
}
Sample Input:Hello world to the world!
Output:Hello world to the world!\n
One thing to notice here is, even though allocated memory for s is 11 bytes,
where as input size is 26 bytes, getline reallocates s using realloc().
So it doesn't matter how long your input is.
size is updated with no.of bytes read, as per above sample input size will be 27.
getline() also considers \n as input.So your 's' will hold '\n' at the end.
There is also more generic version of getline(), which is getdelim(), which takes one more extra argument, that is delimiter.
getdelim() is defined as:
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
Linux man page
If you need to read more than one line, need to clear buffer. Example:
int n;
scanf("%d", &n);
char str[1001];
char temp;
scanf("%c",&temp); // temp statement to clear buffer
scanf("%[^\n]",str);
"%s" will read the input until whitespace is reached.
gets might be a good place to start if you want to read a line (i.e. all characters including whitespace until a newline character is reached).
"Barack Obama" has a space between 'Barack' and 'Obama'. To accommodate that, use this code;
#include <stdio.h>
int main()
{
printf("Enter your name\n");
char a[80];
gets(a);
printf("Your name is %s\n", a);
return 0;
}
scanf("%s",name);
use & with scanf input

C Programming Input Error

int main(void) {
char *input;
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
prompt>input
RUN FAILED (exit value 138, total time: 3s)
What's wrong with the code? Has to be either the scanf() or the second printf(). The input is of unknown length. A lot people have said to simply create a char array of length 'X' to hold the input. Just wanted to know then why this code works.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
Your specific problem is that you have no storage behind input. It's an uninitialised pointer, pointing to a random spot in memory, which is unlikely to be anywhere useful.
You can use something like:
char *input = malloc (100);
// check that input != NULL
// use it
free (input);
or:
char input[100];
but you have a serious problem with your use of scanf (see below).
You should never use an unbounded %s in scanf (or any of its variants unless you totally control the input). It's a dangerous practice prone to buffer overflows and the sooner you get out of the habit, the better. It's akin to gets() in that way.
From an earlier answer of mine, this piece of code below (along with your main code incorporated into it) provides a safe way of getting user input. You pass in an optional prompt, the buffer to load the input into, and the size of the buffer.
It will return the input up to the size of the buffer (stripped of the newline if there) then clear out the rest of the line if necessary so that it doesn't affect the next input operation. It will return either OK or an error indication on end-of-file or if the input was too long (you still get the first part of the input in case you want to do something with it).
Once you have the line, you can sscanf it, safely, to your heart's content. However, that's not required in your case since you're only trying to get a string. Just use the buffer that's returned directly.
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
int main(void) {
char input[10];
int rc = getLine ("prompt> ", input, sizeof (input));
switch (rc) {
case NO_INPUT: printf ("\nNo input recieved\n"); break;
case TOO_LONG: printf ("Too long, truncated input below:\n");
default: printf("Your input was [%s]\n", input);
}
return 0;
}
Give that a shot, it's far more robust than using scanf("%s") on its own.
As for your update asking why this works:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
It's undefined code. Period. You only allocate space for a character but you scan in a string. Since a string is a character array of all the characters followed by a zero character, the only string you could input safely there would be an empty one.
Anything else will write to both the character and whatever happens to be adjacent to the character on the stack.
This is no different to allocating char input[100] then entering 200 characters, it's still buffer overflow and should be avoided.
Discussion below is based on a particular implementation of C, not necessarily all implementations.
Chances are, you got lucky here. Compilers may generate code that keeps the stack pointer aligned so that, even though you asked for one byte, you may get space allocated for four (or even more, depending on the architecture - I'll assume most types are four bytes here for simplicity).
In addition, you may find that you can also safely overwrite the eight bytes of argc integer and argv pointer (they're probably still there even though you don't use them, no point having two different sets of start-up code just to save a few bytes on the stack).
If you write further than that, you'll eventually overwrite the return address from main to your start-up code. Then you'll know about it since your code will go off into la-la land when main exits.
With undefined behaviour, anything can happen. Sometimes that anything includes the possibility that it will work perfectly (similar to "throw a deck of cards in the air often enough and they'll eventually fall in a nice neat sorted heap" but a little less random).
That does not make undefined behaviour any less of a bad thing.
char *input;
Is only a pointer - there is no data space allocated store the data that scanf collects.
try this instead
char input[100];
You may want to try scanf("%c", input) inside of a while loop that has your delimiting character. You should also make input an array char input[X] where X is a number of sufficient value to hold the most likely values for your input. I would try making input an array first though.
You forgot to allocate the memory before using your pointer.
Try it:
int main(void) {
char input[256];
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
or even:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
char *input = (char *) malloc(sizeof(char) * 256));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
What compiler do you use? In Turbo C 3.0 it works.
Try this variant:
#include <stdio.h>
#include <alloc.h>
int main(void)
{
char *input = (char*)calloc(100, sizeof(char));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
free(input);
return 0;
}
Try:-
int main(void) {
char input[100];
printf("prompt>");
scanf("%99s", input);
printf("%s", input);
return 0;
}
This will limit the string to 99 bytes. Note "%s" == string of characters delimited by white space or newline ie. you only get the first word!
I think what you really want is:
#include <stdio.h>
int main(void) {
char input[99];
printf("prompt>");
fgets(input,99,stdin);
printf("->%s<-", input);
return 0;
}
You probably need to add some code to get rid of unwanted new line characters!

Resources