I have a college exercise to do, that consists in writing a bank in C and I do know that scanf is a really buggy function and fgets reads the '\n', that I don't really want to be read. So I have written new functions trying to solve this problem:
char *readstr(char *buff, size_t bytes) {
char *ptr;
for (ptr = buff;
(*ptr = getchar()) != '\n' && *ptr != EOF && ptr - buff < bytes - 1;
ptr++)
;
int c = *ptr;
*ptr = '\0';
if (c != EOF && c != '\n') {
while ((c = getchar()) != '\n' && c != EOF)
;
}
return buff;
}
int readint() {
char buffer[256] = "";
readstr(buffer, 256);
return atoi(strpbrk(buffer, "0123456789"));
}
double readfloat() {
char buffer[256] = "";
readstr(buffer, 256);
return atof(strpbrk(buffer, "0123456789"));
}
char readchar() {
char buffer[2] = "";
readstr(buffer, 2);
return *buffer;
}
until now, I wrote these ones. Any advice or suggestion? a more elegant one or simpler solution? apparently they work, but I don't know if this is the best approach.
scanf is not buggy, it's simply hard to use correctly.
Anyway, you can use fgets and remove manually the newline character. A way to do this is by using the strcspn function like follows:
fgets(str, size, stdin);
str[strcspn(str, "\n")] = 0;
Your goal seems to read a line of input into a buffer with a given size, not storing the trailing newline and discarding any excess characters present on the line. You do need to read the newline so it does not linger in the input stream, but you do not want to store it into the destination array as fgets() does.
Note that this can be achieved with scanf() this way:'
char buf[100] = "";
if (scanf("%99[^\n]", buf) == EOF) {
// handle end of file
} else {
// line was read into buf or empty line was detected and buf was not modified
scanf("%*[^\n]"); // consume extra bytes on the line if any
scanf("%*1[\n]"); // consume the newline if present
}
This is very cumbersome, and it gets even worse if the buffer size is a variable value. As many savvy C programmers noted, scanf is not buggy, it is just difficult to use correctly. I would even say its semantics are confusing and error prone, yet it can be used safely, unlike gets(), which was removed from recent versions of the C Standard because any arbitrary long input can cause undefined behavior with it.
Reading a line and discarding the trailing newline can be done with fgets(), but combining the reading the line, discarding extra bytes and consuming the newline may be useful as a separate function.
There are problems in your code:
you store the return value of getchar() directly into the char array, removing the distinction between EOF and the char value '\377' on architectures with signed chars, while *ptr != EOF would never match on architectures where char is unsigned by default. You must store it into an int variable.
there is no way to tell if the end of file was reached: the function returns an empty string at end of file, just like it does for blank lines int the stream
the buffer size cannot be zero.
truncation cannot be detected: instead of returning the destination array, you could return the number of characters needed for the full line and -1 at end of file.
calling atoi(strpbrk(buffer, "0123456789")) poses multiple problems: strpbrk can return a null pointer, causing undefined behavior, it will skip a leading sign, and atoi is not fully defined for contents representing values out of range for type int.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int readstr(char *buff, size_t bytes) {
size_t pos = 0;
int c;
while ((c = getchar()) != EOF && c != '\n') {
if (pos + 1 < bytes)
buff[pos] = (char)c;
pos++;
}
if (size > 0) {
if (pos < size)
buff[pos] = '\0';
else
buff[size - 1] = '\0';
}
if (c == EOF && pos == 0)
return -1;
return (int)pos;
}
int readint(void) {
char buffer[256];
long n;
if (readstr(buffer, sizeof buffer) < 0)
return -1;
n = strtol(buffer, NULL, 0);
#if LONG_MIN < INT_MIN
if (n < INT_MIN) {
errno = ERANGE;
return INT_MIN;
}
#endif
#if LONG_MAX > INT_MAX
if (n > INT_MAX) {
errno = ERANGE;
return INT_MAX;
}
#endif
return (int)n;
}
double readdouble(void) {
char buffer[256];
if (readstr(buffer, sizeof buffer) < 0)
return NAN;
else
return strtod(buffer, NULL);
}
int readchar(void) {
char buffer[2] = "";
if (readstr(buffer, sizeof buffer) < 0)
return EOF;
else
return (unsigned char)*buffer;
}
I am trying to get some data from the user and send it to another function in gcc. The code is something like this.
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
However, I find that it has a newline \n character in the end. So if I enter John it ends up sending John\n. How do I remove that \n and send a proper string.
Perhaps the simplest solution uses one of my favorite little-known functions, strcspn():
buffer[strcspn(buffer, "\n")] = 0;
If you want it to also handle '\r' (say, if the stream is binary):
buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...
The function counts the number of characters until it hits a '\r' or a '\n' (in other words, it finds the first '\r' or '\n'). If it doesn't hit anything, it stops at the '\0' (returning the length of the string).
Note that this works fine even if there is no newline, because strcspn stops at a '\0'. In that case, the entire line is simply replacing '\0' with '\0'.
The elegant way:
Name[strcspn(Name, "\n")] = 0;
The slightly ugly way:
char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
*pos = '\0';
else
/* input too long for buffer, flag error */
The slightly strange way:
strtok(Name, "\n");
Note that the strtok function doesn't work as expected if the user enters an empty string (i.e. presses only Enter). It leaves the \n character intact.
There are others as well, of course.
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n')
name[ln] = '\0';
Below is a fast approach to remove a potential '\n' from a string saved by fgets().
It uses strlen(), with 2 tests.
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') {
buffer[--len] = '\0';
}
Now use buffer and len as needed.
This method has the side benefit of a len value for subsequent code. It can be easily faster than strchr(Name, '\n'). Ref YMMV, but both methods work.
buffer, from the original fgets() will not contain in "\n" under some circumstances:
A) The line was too long for buffer so only char preceding the '\n' is saved in buffer. The unread characters remain in the stream.
B) The last line in the file did not end with a '\n'.
If input has embedded null characters '\0' in it somewhere, the length reported by strlen() will not include the '\n' location.
Some other answers' issues:
strtok(buffer, "\n"); fails to remove the '\n' when buffer is "\n". From this answer - amended after this answer to warn of this limitation.
The following fails on rare occasions when the first char read by fgets() is '\0'. This happens when input begins with an embedded '\0'. Then buffer[len -1] becomes buffer[SIZE_MAX] accessing memory certainly outside the legitimate range of buffer. Something a hacker may try or found in foolishly reading UTF16 text files. This was the state of an answer when this answer was written. Later a non-OP edited it to include code like this answer's check for "".
size_t len = strlen(buffer);
if (buffer[len - 1] == '\n') { // FAILS when len == 0
buffer[len -1] = '\0';
}
sprintf(buffer,"%s",buffer); is undefined behavior: Ref. Further, it does not save any leading, separating or trailing whitespace. Now deleted.
[Edit due to good later answer] There are no problems with the 1 liner buffer[strcspn(buffer, "\n")] = 0; other than performance as compared to the strlen() approach. Performance in trimming is usually not an issue given code is doing I/O - a black hole of CPU time. Should following code need the string's length or is highly performance conscious, use this strlen() approach. Else the strcspn() is a fine alternative.
Direct to remove the '\n' from the fgets output if every line has '\n'
line[strlen(line) - 1] = '\0';
Otherwise:
void remove_newline_ch(char *line)
{
int new_line = strlen(line) -1;
if (line[new_line] == '\n')
line[new_line] = '\0';
}
For single '\n' trimming,
void remove_new_line(char* string)
{
size_t length = strlen(string);
if((length > 0) && (string[length-1] == '\n'))
{
string[length-1] ='\0';
}
}
for multiple '\n' trimming,
void remove_multi_new_line(char* string)
{
size_t length = strlen(string);
while((length>0) && (string[length-1] == '\n'))
{
--length;
string[length] ='\0';
}
}
My Newbie way ;-) Please let me know if that's correct. It seems to be working for all my cases:
#define IPT_SIZE 5
int findNULL(char* arr)
{
for (int i = 0; i < strlen(arr); i++)
{
if (*(arr+i) == '\n')
{
return i;
}
}
return 0;
}
int main()
{
char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
int counter = 0;
//prompt user for the input:
printf("input string no longer than %i characters: ", IPT_SIZE);
do
{
fgets(input, 1000, stdin);
*(input + findNULL(input)) = '\0';
if (strlen(input) > IPT_SIZE)
{
printf("error! the given string is too large. try again...\n");
counter++;
}
//if the counter exceeds 3, exit the program (custom function):
errorMsgExit(counter, 3);
}
while (strlen(input) > IPT_SIZE);
//rest of the program follows
free(input)
return 0;
}
The steps to remove the newline character in the perhaps most obvious way:
Determine the length of the string inside NAME by using strlen(), header string.h. Note that strlen() does not count the terminating \0.
size_t sl = strlen(NAME);
Look if the string begins with or only includes one \0 character (empty string). In this case sl would be 0 since strlen() as I said above doesn´t count the \0 and stops at the first occurrence of it:
if(sl == 0)
{
// Skip the newline replacement process.
}
Check if the last character of the proper string is a newline character '\n'. If this is the case, replace \n with a \0. Note that index counts start at 0 so we will need to do NAME[sl - 1]:
if(NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
Note if you only pressed Enter at the fgets() string request (the string content was only consisted of a newline character) the string in NAME will be an empty string thereafter.
We can combine step 2. and 3. together in just one if-statement by using the logic operator &&:
if(sl > 0 && NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
The finished code:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
If you rather like a function for use this technique by handling fgets output strings in general without retyping each and every time, here is fgets_newline_kill:
void fgets_newline_kill(char a[])
{
size_t sl = strlen(a);
if(sl > 0 && a[sl - 1] == '\n')
{
a[sl - 1] = '\0';
}
}
In your provided example, it would be:
printf("Enter your Name: ");
if (fgets(Name, sizeof Name, stdin) == NULL) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
else {
fgets_newline_kill(NAME);
}
Note that this method does not work if the input string has embedded \0s in it. If that would be the case strlen() would only return the amount of characters until the first \0. But this isn´t quite a common approach, since the most string-reading functions usually stop at the first \0 and take the string until that null character.
Aside from the question on its own. Try to avoid double negations that make your code unclearer: if (!(fgets(Name, sizeof Name, stdin) != NULL) {}. You can simply do if (fgets(Name, sizeof Name, stdin) == NULL) {}.
If using getline is an option - Not neglecting its security issues and if you wish to brace pointers - you can avoid string functions as the getline returns the number of characters. Something like below
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *fname, *lname;
size_t size = 32, nchar; // Max size of strings and number of characters read
fname = malloc(size * sizeof *fname);
lname = malloc(size * sizeof *lname);
if (NULL == fname || NULL == lname)
{
printf("Error in memory allocation.");
exit(1);
}
printf("Enter first name ");
nchar = getline(&fname, &size, stdin);
if (nchar == -1) // getline return -1 on failure to read a line.
{
printf("Line couldn't be read..");
// This if block could be repeated for next getline too
exit(1);
}
printf("Number of characters read :%zu\n", nchar);
fname[nchar - 1] = '\0';
printf("Enter last name ");
nchar = getline(&lname, &size, stdin);
printf("Number of characters read :%zu\n", nchar);
lname[nchar - 1] = '\0';
printf("Name entered %s %s\n", fname, lname);
return 0;
}
Note: The [ security issues ] with getline shouldn't be neglected though.
In general, rather than trimming data that you don't want, avoid writing it in the first place. If you don't want the newline in the buffer, don't use fgets. Instead, use getc or fgetc or scanf. Perhaps something like:
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
char Name[256];
char fmt[32];
if( snprintf(fmt, sizeof fmt, "%%%zd[^\n]", sizeof Name - 1) >= (int)sizeof fmt ){
fprintf(stderr, "Unable to write format\n");
return EXIT_FAILURE;
}
if( scanf(fmt, Name) == 1 ) {
printf("Name = %s\n", Name);
}
return 0;
}
Note that this particular approach will leave the newline unread, so you may want to use a format string like "%255[^\n]%*c" to discard it (eg, sprintf(fmt, "%%%zd[^\n]%%*c", sizeof Name - 1);), or perhaps follow the scanf with a getchar().
Tim Čas one liner is amazing for strings obtained by a call to fgets, because you know they contain a single newline at the end.
If you are in a different context and want to handle strings that may contain more than one newline, you might be looking for strrspn. It is not POSIX, meaning you will not find it on all Unices. I wrote one for my own needs.
/* Returns the length of the segment leading to the last
characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
const char *ch;
size_t len = strlen(s);
more:
if (len > 0) {
for (ch = accept ; *ch != 0 ; ch++) {
if (s[len - 1] == *ch) {
len--;
goto more;
}
}
}
return len;
}
For those looking for a Perl chomp equivalent in C, I think this is it (chomp only removes the trailing newline).
line[strrspn(string, "\r\n")] = 0;
The strrcspn function:
/* Returns the length of the segment leading to the last
character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
const char *ch;
size_t len = strlen(s);
size_t origlen = len;
while (len > 0) {
for (ch = reject ; *ch != 0 ; ch++) {
if (s[len - 1] == *ch) {
return len;
}
}
len--;
}
return origlen;
}
The function below is a part of string processing library I am maintaining on Github. It removes and unwanted characters from a string, exactly what you want
int zstring_search_chr(const char *token,char s){
if (!token || s=='\0')
return 0;
for (;*token; token++)
if (*token == s)
return 1;
return 0;
}
char *zstring_remove_chr(char *str,const char *bad) {
char *src = str , *dst = str;
while(*src)
if(zstring_search_chr(bad,*src))
src++;
else
*dst++ = *src++; /* assign first, then incement */
*dst='\0';
return str;
}
An example usage could be
Example Usage
char s[]="this is a trial string to test the function.";
char const *d=" .";
printf("%s\n",zstring_remove_chr(s,d));
Example Output
thisisatrialstringtotestthefunction
You may want to check other available functions, or even contribute to the project :)
https://github.com/fnoyanisi/zString
for(int i = 0; i < strlen(Name); i++ )
{
if(Name[i] == '\n') Name[i] = '\0';
}
You should give it a try. This code basically loop through the string until it finds the '\n'. When it's found the '\n' will be replaced by the null character terminator '\0'
Note that you are comparing characters and not strings in this line, then there's no need to use strcmp():
if(Name[i] == '\n') Name[i] = '\0';
since you will be using single quotes and not double quotes. Here's a link about single vs double quotes if you want to know more
This is my solution. Very simple.
// Delete new line
// char preDelete[256] include "\n" as newline after fgets
char deletedWords[256];
int iLeng = strlen(preDelete);
int iFinal = 0;
for (int i = 0; i < iLeng; i++) {
if (preDelete[i] == '\n') {
}
else {
deletedWords[iFinal] = preDelete[i];
iFinal++;
}
if (i == iLeng -1 ) {
deletedWords[iFinal] = '\0';
}
}
Is there a library function to read a line of input from stdin with the following requirements?
I have a limited static buffer of specific size (size may be a known constant).
No dynamic allocation allowed. So the library functions like getline() cannot be used.
For lines whose length is beyond the buffer size, the unread tail part of the line is to be ignored.
My solution to read a line is using fgets and a loop to read and ignore the tail part. The code is as below
char buffer[80], tail_buffer[80];
char * line, * tail;
line = tail = fgets(buffer, 80, stdin);
/* Read the tail part to ignore it */
while (tail != NULL && tail[strlen(tail)-1] != '\n')
{
tail = fgets(tail_buffer, 80, stdin);
}
/* Use 'line' as needed */
An alternative solution using scanf to read until the newline is found, and the getchar to read the newline.
char buffer[80];
if ( fgets( buffer, sizeof buffer, stdin ) != NULL )
{
if ( strchr( buffer, '\n' ) == NULL ) // if the buffer does not contain the newline
{
scanf( "%*[^\n]" ); // read up to the newline
getchar(); // read the newline
}
}
After looking into the documentation of scanf, I found a solution myself.
char buffer[80];
scanf(" %79[^\n]%*[^\n]", buffer);
EDIT: With the comments from #chux that this has some limitations in parsing the blank lines and initial spaces, and with the solution from #user3386109, I enhance this as below to scan all the lines till EOF.
char buffer[80] = "";
while (scanf("%79[^\n]%*[^\n]", buffer) != EOF)
{
/* Process the line in buffer */
if (feof(stdin)) break;
getchar(); /* Remove end of line */
buffer[0] = 0;
}
fgets() has corner cases that preclude using it at a complete solution to OP's goal.
Simply loop using fgetc().
// Return count of `char` read - not including potential \n.
int read_line(char *dest, int size) {
int i = 0;
if (size > 0) {
size--;
int ch;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
if (i < size) {
dest[i++] = ch;
}
}
dest[i] = '\0';
if (ch == EOF && i == 0) return EOF;
}
return i;
}
A forced use of fgets() looks like
bool was_there_extra(char *buf, size_t size) {
char *lf = strchr(buf, '\n');
if (lf) {
*lf = '\0'; // optional: lop off potential trailing \n
return false;
}
int ch;
bool extra = false;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
extra = true;
}
return extra;
}
while (fgets(buf, sizeof buf, stdin)) {
if (was_there_extra(buf, sizeof buf)) ...
else ...
}
This approach does get fooled if code reads a '\0'.
I am trying to use a function that returns char * buffer to trap random user input from standard input and return a char* (that is, a string) with the input until '\n' or '\0' is detected as input.
However, the function user_input() crashed at the second occurence of c = getchar(); near the end of the function (at the //Error Here comment).
What am I doing wrong?
char* user_input(){
char *buffer=NULL;
size_t num_read = 0;
size_t buffer_size = 100;
char c = '\0';
char *new_buffer=NULL;
buffer = malloc(buffer_size);
fflush(stdin);
c = getchar();
while ( c != '\n' || c !='\0' ) {
if (num_read >= buffer_size) {
new_buffer=NULL;
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
return NULL;
/* Abort - out of memory */
}
buffer = new_buffer;
}
buffer[num_read] = c;
num_read++;
c = getchar(); //Error Here
}//while
buffer[num_read] = '\0';
return buffer;
}
while ( c != '\n' || c !='\0' ) {
should use && instead of || or the loop will never exit
while ( c != '\n' && c !='\0' ) {
I built it and it worked although there are other bugs in the code such as the "buffer[num_read] = '\0';" at the end could overflow the buffer if there are exactly buffer_size items in the array.
Here are the issues that I found:
You cannot call fflush() on stdin. It leads to undefined behavior. fflush() is only for output streams.
The type for c should be an int. The getchar() will return EOF when there is no more input, and EOF is a value not equal to any valid value for unsigned char. That is why getchar() returns an int, so your variable receiving the return value of getchar() should match that type.
The sense of the while check is incorrect. You will only leave the loop if c equals both \n and \0 at the same time, which is not possible. Thus the loop will never exit. If you actually ended the input given to your program, you probably entered an infinite loop, continually allocating until your system ran out of memory. So, you want to leave the loop if c equals \n or \0.
You should add a check to leave the loop if c is EOF.
You should make sure num_read is less than buffer_size before you assign the \0 character. This can be done by moving your realloc() code to be at the bottom of the while loop instead of at the top.
With these changes, the code looks like:
char *user_input() {
char *buffer = NULL;
size_t num_read = 0;
size_t buffer_size = 100;
int c = '\0';
char *new_buffer = NULL;
buffer = malloc(buffer_size);
c = getchar();
while (!(c == EOF || c == '\n' || c == '\0')) {
assert(num_read < buffer_size);
buffer[num_read++] = c;
if (num_read >= buffer_size) {
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
return NULL;
}
buffer = new_buffer;
}
c = getchar();
} //while
assert(num_read < buffer_size);
buffer[num_read] = '\0';
return buffer;
}
I have modified your code below. Try to run it as is, using the 'q' character at first, then you can experiment with other exit criteria later. By the way, your code worked without modification and did not crash for me (unless buffer overrun occured, but it would never leave the while loop otherwise (as Brian Walker pointed out). In any case, Try this in any ANSI C compiler: (just don't enter more than 1000 entries :)
#include <ansi_c.h>
char* user_input(void);
int main(void)
{
char *buf;
buf = malloc(1000);
//SearchDirectory("C:\\dev");
sprintf(buf, "%s", user_input());
printf("%s", buf);
free(buf);
return 0;
}
char* user_input(void){
char *buffer=NULL;
size_t num_read = 0;
size_t buffer_size = 100;
char c = '\0';
char *new_buffer=NULL;
buffer = malloc(buffer_size);
fflush(stdin);
c = getchar();
while ( c != 'q' ) {
if (num_read >= buffer_size) {
new_buffer=NULL;
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
return NULL;
/* Abort - out of memory */
}
buffer = new_buffer;
}
buffer[num_read] = c;
num_read++;
c = getchar();
}//while
buffer[num_read] = '\0';
return buffer;
}
I want to read a string through keyboard to avoid buffer overflow. When i used
fgets(text,30,stdin), it reads but it also reads '\n' character. But i don't want to read '\n' character.
char s[30];
scanf("%30[^\n]", s);
a little explain:
%30[^\n]
30 which means read at most 30 chars, [^\n] which means read any char except '\n'.
So remove the line feed once you have the string:
int get_line(char *buffer, size_t max)
{
if(fgets(buffer, max, stdin) == buffer)
{
size_t len = strlen(buffer);
if(len > 0 && buffer[len - 1] == '\0')
buffer[--len] = '\0';
return len;
}
return 0;
}
UPDATE: Changed to return the length, which might save the caller some trouble. This means that for an empty string input, it will return 0.
Read with the '\n' character but remove it afterwards
if (fgets(text, 30, stdin)) {
size_t tlen = strlen(text);
if (len > 0) {
if (text[tlen - 1] == '\n') {
text[--tlen] = 0;
} else {
/* fgets read all it could
** but there wasn't a '\n'
** for the number of bytes available */
}
} else {
/* empty string read: not even a '\n' */
}
} else {
/* fgets failed */
}