Code snippet for gets()
int main(int argc, char *argv[])
{
char str[MAX_SIZE]
gets(str);
printf("\n");
Code snippet for puts()
printf("The most probable key is: %d\n", max2);
puts(output);
return 0;
I did not paste my whole code since it seems pretty irrelevant for my question. I just want to know a way I could fix this because when I run my code through GCC, it gives me errors and is not allowing me to use gets(). How would I fix this?
Use fgets and fputs instead. There is - beside removing all the flaws of gets- also a main difference in the usage between gets and fgets: fgets stores a new line character in the buffer (and gets does not).
So an equivalent - i.e. eliminating any new line if not desired - could look as follows. Function call strcspn(buffer,"\n") gives the longest sequence of characters until a new line is encountered (or strlen(buffer), if the string does not contain a new line). By writing a 0 to the index at this position a new line - if any - is eliminated.
char buffer[MAX_SIZE] = "";
if (fgets(buffer, MAX_SIZE ,stdin)) {
buffer[strcspn(buffer,"\n")] = '\0';
}
You should absolutely, positively avoid using gets(), its dangerous and removed from the recent C standard. That's why you see the warning
C11, Foreword, Paragraph 6 mentions
Major changes from the previous edition include:
[....]
removed the gets function (<stdio.h>)
Instead, use fgets().
To add, puts() is just fine, I see no reason for replacing that one.
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
char * fgets ( char * str, int num, FILE * stream );
The following example shows the usage of fgets() function.
#include <stdio.h>
int main () {
FILE *fp;
char str[60];
/* opening file for reading */
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
if( fgets (str, 60, fp)!=NULL ) {
/* writing content to stdout */
puts(str);
}
fclose(fp);
return(0);
}
alternative can I use instead of gets()
char str[MAX_SIZE]; gets() has problems when reading a line of N characters. (N also counts the '\n').
When N > MAX_SIZE, the result is undefined behavior (UB). Too much input and no place to go. Often this UB writes into places used by other objects. Bad - very bad.
C11 eliminated gets() and is not a standard function since then.
The usual fgets() solution is well suggested by #Stephan Lechner. fgets() has some short comings listed below.
str[MAX_SIZE] now needs to be str[MAX_SIZE + 1] as fgets() also saves the '\n', unlike gets(). Sometimes adding + 1 is not practical.
fgets() retains the potential '\n'. See Removing trailing newline character from fgets()
When input is excessive, fgets() simply does not read it, unlike gets(). This is well behaved (not UB) yet we are still stuck with that problem: how to detect excessive input and what to do about it?
If code can live with these, use fgets(). Otherwise, read on.
mygets() alternative
This function does not need a +1 to the size of the s buffer.
Excessively long input returns NULL. All the line is read. The s buffer is filled with the initial characters.
char *mygets(char *s, size_t n) {
char *dest = s;
// Pathological case of n==0
char dummy[1];
if (n == 0) {
n = sizeof dummy;
dest = dummy;
}
size_t i = 0;
int ch;
n--;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
if (i < n) {
dest[i++] = (char) ch;
} else {
s = NULL; // Not enough room
}
}
if (ch == EOF) {
if (feof(stdin)) { // end-of-file
if (i == 0) {
s = NULL;
}
} else { // input error
i = 0;
s = NULL;
}
}
dest[i] = '\0';
return s;
}
Subtle bonuses:
s buffer is well defined on rare input error. With gets/fgets buffer contents are then undefined.
Pathological size of 0 is well defined. fgets() is a bit iffy on that.
Buffer size is the idiomatic size_t rather than int as with fgets().
Usage
str[MAX_SIZE];
if (mygets(str, sizeof str)) {
printf("Success <%s>\n", str);
} else {
if (feof(str)) printf("End of file detected. <%s>\n", str);
else if (ferror(str)) printf("End of file detected. <%s>\n", str);
else printf("Input too long <%s>.", str);
}
Related
What is the most accurate way to read strings from the keyboard in C, when the string contains spaces in between words? When I use scanf for that purpose then it doesn't read a string with spaces.The second option is to use gets but it is supposed to be harmful(I also want to know why?).Another thing is that I don't want to use any file handling concept like fgets.
These are 2 ways to read strings containing spaces that don't use gets or fgets
You can use getline (POSIX 2008 may not exist in your system) that conveniently manages allocation of the buffer with adequate size to capture the whole line.
char *line = NULL;
size_t bufsize = 0;
size_t n_read; // number of characters read including delimiter
while ((n_read = getline(&line, &bufsize, stdin)) > 1 && line != NULL) {
// do something with line
}
If you absolutely want scanf, in this example it reads to the end of line unless the line has more than the specified number of chars minus 1 for the delimiter. In the later case the line is truncated and you'll get the remaining chars in the next scanf invocation.
char line[1024];
while (scanf("%1023[^\n]\n", line) == 1) {
// do something with line
}
I should also point out that when you read strings from the keyboard with scanf for example, you are actually reading from a file with file pointer stdin. So you can't really avoid "any file handling concept"
#user3623265,
Please find a sample program which Uses fgets to read string from standard input.
Please refer some sample C documents as to how fgets can be used to get strings from a keyboard and what is the purpose of stdin.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[80];
int i;
printf("Enter a string: ");
fgets(str, sizeof(str), stdin);
i = strlen(str) - 1;
if (str[i] == '\n')
str[i] = '\0';
printf("This is your string: %s", str);
return 0;
}
There is a third option, you can read the raw data from stdin with the read() call:
#include <unistd.h>
int main(void) {
char buf[1024];
ssize_t n_bytes_read;
n_bytes_read = read(STDIN_FILENO, buf, sizeof(buf) - 1);
if (n_bytes_read < 0) {
// error occured
}
buf[n_bytes_read] = '\0'; // terminte string
printf("\'%s\'", buf);
return 0;
}
Please not that every input is copied raw to buf including the trailing return. That is, if you enter Hello World you will get
'Hello World
'
as output. Try online.
If you insist on not having a FILE * in scope, use getchar().
char buff[1024];
int ch;
int i = 0;
while( (ch = getchar()) != '\n' )
if(i < 1023)
buff[i++] = ch;
buff[i] = 0;
/* now move string into a smaller buffer */
Generally however it's accepted that stdout and stdin and FILE * are available. Your requirement is a bit odd and, since you are obviously not an advanced C programmer who has an unusual need to suppress the FILE * symbol, I suspect your understanding of C IO is shaky.
I am having the absolute craziest time getting full line input to work. I will explain my problem. I need to get a full line of input, including a space, from the user entered at the keyboard. Simple right? Wrong!
MY GOAL
Store multiple strings, with spaces, into variables. If it makes a difference, I want to make the variables equal to a char pointer. So once I get the input from tempString, I want to set it to a char pointer. Like so:
char *variable1, *variable2;
//get user input
variable1 = tempString;
//get more user input
variable 2 = tempString;
//etc etc etc
Here's what I've tried.
First try
char tempString[100];
scanf("%s", &tempString);
printf("%s", tempString);
Invalid: scanf will stop reading at a white space, so "Example String" would just end up being "Example".
Second try
So I do more research. I thought I found the magic fix.
char tempSTring[100];
fgets(tempString, 100, stdin);
printf("%s", tempString);
Originally this works. However there is a massive problem. I need to get the user to enter about 8 inputs. Meaning I have to use a command like this 8 times. The problem is the program often skips over the fgets command. If I use a scanf previously, somehow the \n character is stuck in the input stream, and automatically feeds into fgets, satisfying its stdin input, and then does not prompt the user for input.
Third try
After thinking fgets was maybe my solution with a work around, I tried some tricks.
char tempSTring[100];
getc(stdin);
fgets(tempString, 100, stdin);
printf("%s", tempString);
I tried adding this getc(stdin) line. It worked for much of my program. It absorbs the \n character left behind in the stream. When it does so, great, it works. But sometimes, for some reason, the \n is NOT left in the stream, and when debugging, it looks like getc(stdin) is requesting input from the user, so it pauses my program to ask for input.
Question
These don't work for me.
How should I be doing this easy task?
To read (up to) 8 lines from a file, you can use either of these solutions. I decline to use variables char *variable1, *variable2, …; — that is an array seeking to escape.
POSIX getline()
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
enum { MAX_LINES = 8 };
char *lines[MAX_LINES];
int index = 0;
char *buffer = 0;
size_t buflen = 0;
while (index < MAX_LINES && getline(&buffer, &buflen, stdin) != -1)
{
lines[index++] = buffer;
buffer = 0;
buflen = 0;
}
free(buffer); // Space may be allocated before EOF is detected
for (int i = 0; i < index; i++)
printf("%d: %s", i, lines[i]);
return 0;
}
If getline() fails to allocate memory, it will report an error, so there is no need to do an explicit error check.
Standard C fgets()
Code using strdup(), another POSIX function. It isn't a part of standard C (though it is widely available). It is trivial to implement.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
enum { MAX_LINES = 8 };
char *lines[MAX_LINES];
int index = 0;
char buffer[4096];
while (index < MAX_LINES && fgets(buffer, sizeof(buffer), stdin) != 0)
{
if ((lines[index] = strdup(buffer)) == 0)
break;
index++;
}
for (int i = 0; i < index; i++)
printf("%d: %s", i, lines[i]);
return 0;
}
The test in the loop allows for the possibility of strdup() failing to allocate memory.
Notes
Both the solutions above keep the newline at the end of the input string. If you don't want that, you can zap it with:
lines[i][strcspn(lines[i], "\r\n")] = '\0';
This overwrites a carriage return or newline with a null byte, transforming DOS or Unix line endings. You then need to adjust the printing which assumes the string includes a newline. Note that the expression shown works correctly even if there is no carriage return or newline in the string.
The fgets() solution will break lines at 4095 characters, leaving the rest to be read as 'the next line'. If that's not acceptable, you have a variety of strategies open to you.
You can detect whether there is a newline and arrange to allocate more memory and read the next section of the line into the extra memory, repeating until you come across a newline or EOF.
You can read the remaining characters up to the newline or EOF:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
Implementing strdup()
If for some reason your system doesn't have an implementation of strdup(), you can create a surrogate with:
#include <assert.h>
#include <stdlib.h>
#include <string.h>
char *strdup(const char *old_str)
{
assert(old_str != 0);
size_t old_len = strlen(old_str) + 1;
char *new_str = malloc(old_len);
if (new_str != 0)
memmove(new_str, old_str, old_len);
return new_str;
}
Here's how we old fart C programmers would do it:
#include <stdio.h>
#define MAX_LEN 100
int main( )
{
int c;
char input[MAX_LEN+1];
int i = 0;
while ( (c=getchar()) != '\n' && c != EOF && i < MAX_LEN)
input[i++] = c;
if (c == EOF || c =='\n') {
/* received input that terminated within buffer limit */
input[i] = '\0';
printf("read in your input string of: %s\n", input);
}
else {
printf("don't buffer overflow me dude!\n");
return -1;
}
return 0;
}
But nowadays people will tell you to use one of the library functions. I'm still an old fart though.
EDIT: Fixed my embarrassing mistakes pointed out by the helpful comments below.
You can take care of '\n' left by previous scanf by writing it like this -
scanf("%d%*c", &x); //<-- example to take int input
%*c will read from stdin and then discard it, thus '\n' would be removed from stdin.
You can achieve with scanf like this (a way for your previous attempt)-
char tempString[100];
/* As suggested by chqrile it is essential to check return of scanf */
if(scanf("%99[^\n]", tempString)!=1){
// ^^ & not required
tempString[0]='\0';
}
%99[^\n] this will read 99 characters and will stop only after encountering '\n' , thus would read input with spaces.
I was trying to take a full line input in C. Initially I did,
char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);
Ignoring security flaws and buffer overflows, I knew this could never take more than a word input. I modified it again,
scanf("[^\n]", line);
This, of course, couldn't take more than a line of input. The following code, however was running into infinite loop,
while(fscanf(stdin, "%[^\n]", line) != EOF)
{
printf("%s\n", line);
}
This was because, the \n was never consumed, and would repeatedly stop at the same point and had the same value in line. So I rewrote the code as,
while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
printf("%s\n", line);
}
This code worked impeccably(or so I thought), for input from a file. But for input from stdin, this produced cryptic, weird, inarticulate behavior. Only after second line was input, the first line would print. I'm unable to understand what is really happening.
All I am doing is this. Note down the string until you encounter a \n, store it in line and then consume the \n from the input buffer. Now print this line and get ready for next line from the input. Or am I being misled?
At the time of posting this question however, I found a better alternative,
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
{
printf("%s\n", line);
}
This works flawlessly for all cases. But my question still remains. How come this code,
while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
printf("%s\n", line);
}
worked for inputs from file, but is causing issues for input from standard input?
Use fgets(). #FredK
char buf[N];
while (fgets(buf, sizeof buf, stdin)) {
// crop potential \n if desired.
buf[strcspn(buf, "\n")] = '\0';
...
}
There are to many issues trying to use scanf() for user input that render it prone to mis-use or code attacks.
// Leaves trailing \n in stdin
scanf("%[^\n]", line)
// Does nothing if line begins with \n. \n remains in stdin
// As return value not checked, use of line may be UB.
// If some text read, consumes \n and then all following whitespace: ' ' \n \t etc.
// Then does not return until a non-white-space is entered.
// As stdin is usually buffered, this implies 2 lines of user input.
// Fails to limit input.
scanf("%[^\n]\n", line)
// Does nothing if line begins with \n. \n remains in stdin
// Consumes 1 char after `line`, even if next character is not a \n
scanf("%99[^\n]%*c", line)
Check against EOF is usual the wrong check. #Weather Vane The following, when \n is first entered, returns 0 as line is not populated. As 0 != EOF, code goes on to use an uninitialized line leading to UB.
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
Consider entering "1234\n" to the following. Likely infinite loop as first fscanf() read "123", tosses the "4" and the next fscanf() call gets stuck on \n.
while(fscanf(stdin, "%3[^\n]%*c", line) != EOF)
When checking the results of *scanf(), check against what you want, not against one of the values you do not want. (But even the following has other troubles)
while(fscanf(stdin, "%[^\n]%*c", line) == 1)
About the closest scanf() to read a line:
char buf[100];
buf[0] = 0;
int cnt = scanf("%99[^\n]", buf);
if (cnt == EOF) Handle_EndOfFile();
// Consume \n if next stdin char is a \n
scanf("%*1[\n]");
// Use buf;
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
worked for inputs from file, but is causing issues for input from standard input?
Posting sample code and input/data file would be useful. With modest amount of code posted, some potential reasons.
line overrun is UB
Input begins with \n leading to UB
File or stdin not both opened in same mode. \r not translated in one.
Note: The following fails when a line is 100 characters. So meeting the assumption cal still lead to UB.
char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);
Personally, I think fgets() is badly designed. When I read a line, I want to read it in whole regardless of its length (except filling up all RAM). fgets() can't do that in one go. If there is a long line, you have to manually run it multiple times until it reaches the newline. The glibc-specific getline() is more convenient in this regard. Here is a function that mimics GNU's getline():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long my_getline(char **buf, long *m_buf, FILE *fp)
{
long tot = 0, max = 0;
char *p;
if (*m_buf == 0) { // empty buffer; allocate
*m_buf = 16; // initial size; could be larger
*buf = (char*)malloc(*m_buf); // FIXME: check NULL
}
for (p = *buf, max = *m_buf;;) {
long l, old_m;
if (fgets(p, max, fp) == NULL)
return tot? tot : EOF; // reach end-of-file
for (l = 0; l < max; ++l)
if (p[l] == '\n') break;
if (l < max) { // a complete line
tot += l, p[l] = 0;
break;
}
old_m = *m_buf;
*m_buf <<= 1; // incomplete line; double the buffer
*buf = (char*)realloc(*buf, *m_buf); // check NULL
max = (*m_buf) - old_m;
p = (*buf) + old_m - 1; // point to the end of partial line
}
return tot;
}
int main(int argc, char *argv[])
{
long l, m_buf = 0;
char *buf = 0;
while ((l = my_getline(&buf, &m_buf, stdin)) != EOF)
puts(buf);
free(buf);
return 0;
}
I usually use my own readline() function. I wrote this my_getline() a moment ago. It has not been thoroughly tested. Please use with caution.
here is my current code:
int num = 0;
char c = '#';
scanf("%d",&num);
do{
for (int i=0;i<num;i++){
printf("%c",c);
}
printf("\n");
}
while (scanf("%d", &num) == 1);
How would I have it so that if the user doesn't enter anything, that the program won't spit out a newline?
Any help is appreciated, thank you!
This code should work for what you want to do :
#include <stdio.h>
int main()
{
int num = 0;
char c = '#';
char readLine[50];
while ((fgets(readLine, sizeof readLine, stdin) != NULL) && sscanf(readLine, "%d", &num) == 1)
{
for (int i=0;i<num;i++){
printf("%c",c);
}
printf("\n");
fflush(stdout);
}
return 0;
}
The behaviour of this code is the following : fgets will read anything you enter in the standard stream (stdin), and put it in the readLine array. The program will then try to read the number which is in your readLine variable and put it in your num variable with the sscanf function. If a number is read, the program will execute the behaviour you did present in your question (writing a # character "num" times), and go back to the beginning of the loop. If anything else than a number has been read, the loop is stopped.
In general, avoid scanf. It's very easy to leave yourself with unprocessed cruft on the input stream. Instead, read the whole line and then use sscanf (or something else) to process it. This guarantees that you won't get stuck with a partially read line, those are hard to debug.
I prefer getline to fgets to read lines. fgets requires you to guess how long the input might be, and input might get truncated. getline will allocate the memory to read the line for you avoiding buffer overflow or truncation problems.
NOTE: getline is it's not a C standard function, but a POSIX one and fairly recent (2008), though it was a GNU extension well before that. Some older compilers may not have it.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char c = '#';
char *line = NULL;
size_t linelen = 0;
/* First read the whole line */
while( getline(&line, &linelen, stdin) > 0 ) {
/* Then figure out what's in it */
long num = 0;
if( sscanf(line, "%ld", &num) > 0 ) {
for( int i = 0; i < num; i++ ) {
printf("%c", c);
}
printf("\n");
}
}
free(line);
return 0;
}
if( sscanf(line, "%ld", &num) > 0 ) { will ignore any line that does not match any part of the pattern, such as a blank line or a line full of words, by checking how many things matched. Yet it will still handle 0 as a valid input.
$ ./test
foo
bar
foo123
12
############
1
#
0
2
##
I also moved num inside the loop to guarantee it's reinitialized each iteration, and on the general principle of putting your variables in minimum scopes to avoid interference. And I upgraded it to a long int better able to handle the unpredictably large numbers users might type in.
Here is how I have done input parsing over the years using the fgets() and sscanf() functions. I don't write c++ much, and if I can I keep code within old style ansi C then I do.
The fgets and sscanf functions from the stdio.h library are universal and are always available on any platform.
For a character array used to read in anything, I generally set LINE_SIZE to 256 or 512 even if I know typically the line to be read is 80 characters or less. With any computer today having over 1GB of RAM, not worth worrying about allocating an extra 500 or so bytes. Obviously, if you have no idea how long the input line is then you either have to:
guess at what LINE_SIZE should be set to and not worry about it
or verify a newline character is present in line[] prior to a null character after calling fgets().
# include <stdio.h>
# define LINE_SIZE 256
int main ( int argc, char *argv[] )
{
FILE *fp;
char line[LINE_SIZE];
int nn;
int value;
fp = fopen( "somefile", "r" );
fgets( line, LINE_SIZE, fp );
/*
this way to read from standard input (i.e. the keyboard)
using fgets with stdin prevents compiler warning when using
deprecated gets function
fgets( line, LINE_SIZE, stdin );
*/
if ( line[0] != '\n' )
{
/* definitely not a blank line */
nn = sscanf( line, "%d", &num );
if ( nn == 1 )
{
/* some number placed into num variable that met the
%d conversion for the sscanf function
*/
}
}
return 0;
I have been thinking of ways to flush bad entries in scanf functions to allow for loop prompts to do their job.
I have a function call here that flushes the input. This works but it's still buggy if I enter something like 2q when I ask for an int.
void flushKeyBoard()
{
int ch; //variable to read data into
while((ch = getc(stdin)) != EOF && ch != '\n');
}
And then I'll have something like this in another function:
printf("Enter a value: ");
check = scanf("%f", &b);
while(check == 0)
{
printf("Invalid number entered. Please re-enter: ");
check = scanf("%f, &b");
flushKeyBoard();
}
Any better ideas? Someone suggested fflush(); but it's not really standard to use that here..
Using getchar (common, easily comprehensible)
int c;
while ((c = getchar()) != EOF && c != '\n'); /* <note the semicolon! */
if (c == EOF) {
if (feof(stdin)) {
/* Handle stdin EOF. */
}
else {
/* Handle stdin error. */
}
}
Using fgets (less common, less comprehensible)
char buf[8];
while (fgets(buf, sizeof buf, stdin) != NULL) {
size_t len = strlen(buf);
/*
* Exit the loop if either EOF was encountered before '\n', or
* if '\n' is detected.
*/
if (len + 1 != sizeof(buf) || memchr(buf, '\n', len))
break;
}
if (feof(stdin)) {
/* Handle stdin EOF. */
}
else {
/* Handle stdin error. */
}
Using a scanset with scanf (likely uncommon, easily comprehensible)
/*
* Combining the scanset with assignment suppression (the '*' before the
* scanset) will return EOF on EOF/error and 0 if '\n' was read.
*/
if (scanf("%*[^\n]") == EOF) {
if (feof(stdin)) {
// Handle stdin EOF.
}
else {
// Handle stdin error.
}
}
getchar(); // Flush the '\n'.
Using getline (likely uncommon, difficult)
char *buf = NULL;
size_t bufsize = 0;
ssize_t len;
/* getline() will stop reading on '\n' or EOF. */
len = getline(&buf, &bufsize, stdin);
/* No bytes read and EOF encountered, or there was an error. */
if (len == -1) {
if (feof(stdin)) {
/* Handle stdin EOF. */
}
else if (ferror(stdin)) {
/* Handle stdin error. */
}
else {
/* Handle errno error, if desired. */
}
/*
* The value of "buf" is indeterminate here, so you likely
* just want to return from the function/program at this point
* rather than continuing and potentially freeing an invalid
* buffer.
*/
}
free(buf);
Of course, all of these methods assume you want to handle things that happen on EOF/error differently than with \n, perhaps even all three being separate cases. For example, by placing one of the above snippets into a self-contained function, you might return 0 if \n was read or EOF on EOF/error, or even 0 on \n, EOF on EOF, and 1 on error.
Things worth noting:
The getchar and fgets methods are 100% cross-platform. I prefer the getchar method for its simplicity.
The scanset method is less cross-platform only because not all compilers implement scansets (and are therefore not C99-compliant).
The getline method is also not quite cross-platform: it's primarily implemented on GNU/Linux and on some other POSIX operating systems; this does not include Windows at this time. It isn't terribly difficult to write one yourself once you have some experience managing memory and working with pointers, but you'd be better off using one of the first two methods since writing an implementation of getline would likely end up using fgetc or fgets anyway (fgetc(stdin) and getchar() should behave identically).
You can use:
fscanf(stdin, "%*[^\n]%*c");
There's a few ways of doing this. Effectively, what you're trying to do is consume a line of text up to a \n character (or an EOF.) To do this properly, you should use sscanf (or fscanf.)
sscanf("%*[^\n]\n");
This uses the regular expression [^\n]*\n (Any number of characters that are NOT \n, followed by a \n) and consumes everything matching that.
Edit: Because I'm dumb and forgot that scanf regex's use a slightly different syntax.