How to change the gets() code to fgets()? [duplicate] - c

This question already has answers here:
fgets() function in C
(4 answers)
Closed 2 years ago.
Replace gets function with fgets in this code. Compile the program. Does the program comprise errors? If it does, explain the error and fix the code. Can anyone help me with it? Thank you.
#include <stdio.h>
int main(int argc, char **argv){
char buf[7]; // buffer for seven characters
gets(buf); // read from stdio (sensitive function!)
printf("%s\n", buf); // print out data stored in buf
return 0; // 0 as return value
}

Looking up some documentation for fgets,
Declaration
char *fgets(char *str, int n, FILE *stream)
Parameters
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.
So the difference is that we need to supply the stream (in this case, stdin aka input) and the length of the string to be read from stdin.
The following should work:
#include <stdio.h>
#define BUFLEN 7
int main(int argc, char **argv) {
char buf[BUFLEN]; // buffer for seven characters
fgets(buf, BUFLEN, stdin); // read from stdio
printf("%s\n", buf); // print out data stored in buf
return 0; // 0 as return value
}

The difference is that:
you pass the length of the buffer which avoids writing past end of buffer (what you want)
fgets leaves the '\n' in the buffer, so you have to manually remove it. More exactly the '\n' at the end of buffer says that the line could fit in the buffer - this is how to handle lines longer than the buffer.
Here is a possible code (no special processing for long lines):
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char buf[7]; // buffer for seven characters
if (NULL == fgets(buf, sizeof(buf), stdin)) { // read from stdio (sensitive function!)
buf[0] = '\0'; // test end of file of read error and says empty data
}
else {
size_t ix = strcspn(buf, "\n"); // remove an optional '\n'
buf[ix] = '\0';
}
printf("%s\n", buf); // print out data stored in buf
return 0; // 0 as return value
}

Related

C reading lines from stdin

My goal is to read every line from a piped .txt file with the getline() function, but I somehow get a error every time I use this function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int Chars;
int size = 10;
char *string;
printf("Please enter a string: ");
string = (char*) malloc(size);
Chars = getline(&string, &size, stdin);
if (Chars == -1)
{
puts("ERROR!");
}
else
{
puts("You entered the following string: ");
puts(string);
printf("\nCurrent size for string block: %d", Chars);
}
return 0;
}
I always get the errorcode: [Error] Id retruned 1 exit status
I've reproduced the linking error on DevC++, in which getline() seems to be missing even after forcing recent C revisions with gcc compiler options such as -std=c11.
So I've rewritten your code using fgets():
char *fgets(char *s, int size, FILE *stream);
It is for sure more portable than getline but has a few differences:
It reads up to size-1 characters if the newline is not encountered before this limit (it automatically appends the string terminator). So it doesn't manage buffer reallocation
The resulting string contains the '\n' character, if found
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STR_SIZE 32
int main( void )
{
int len = 0;
char *str;
printf("Please enter a string: ");
str = malloc(MAX_STR_SIZE); /* (1) */
while( 1 )
{
size_t newline_pos;
fgets( str, MAX_STR_SIZE, stdin );
/* (2) */
if( len == 0) /* (3) */
{
puts("You entered the following string: ");
}
newline_pos = strcspn(str, "\n" );
str[newline_pos] = '\0';
len += strlen(str); /* (4) */
fputs(str, stdout);
if(newline_pos < MAX_STR_SIZE-1) /* (5) */
break;
}
printf("\n\nCurrent size for string block: %d", len);
free( str ); /* (6) */
return 0;
}
So, basically, I just use fgets to read from stdin, iterating until the '\n' character is found. In order to understand is this condition is met, I use strcspn() function, and I use the same function to remove the newline from the resulting string.
A few notes/assumptions (check the corresponding number in code section):
Casting the result of malloc is required only if you are compiling with a C++ compiler. It can be omitted in C
Removed fgets error check: it returns NULL in case of error (no chars read before EOF is found. It won't happen reading from stdin)
Checking for len==0 we make sure that the "You entered the following string: " is printed only once
The length of the string is calculated by summing the length of the strings read in every iteration
The break condition is met when the string contains '\n'. Otherwise strcspn's return value will be MAX_STR_SIZE
Even if the OS will release all the dynamic memory used by the program, on return, it is a good habit always freeing it anyway

read() end line not being found causing code to output weird symbol

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof buf);
printf("%s\n", buf);
}
return(0);
}
Basically, this is what happens:
$ gcc -Wall above.c
$ ./a.out
h
h
#
a
a
&
^C
$
How do I make it so that this special character is not printed? I'm unsure how to fix this. I tried making buf[10] = '\0' but I still get the same error.
You have several errors, why don't use the return value of read?
Simply you can use it in a "%.*s" format specifier, like in
printf("%.*s\n", ret, buf);
but....
you have to check that ret < 0 for errors.
you have to check that ret == 0 for End of file condition.
read(2) never terminates the sequence of characters read with a \0 char, so you cannot use any str* function on it (I used the trick of printing only the first ret chars because the ret variable tells me there are not more, so I don't get behind the last character read) but this approach will eat all the characters read after an actual \0 in the input file (or in the buffer), up to the ret-esim char. That is because the %*s format stops before the specified ret value if it finds the string terminator null char.
It is better to use write(2) or fwrite(2) with read(2), as in:
write(1, buffer, ret);
As read(2), write(2) doesn't treat \0 as a string terminator, and case you have some \0 chars in the buffer, it will print them, as if they were normal characters. This is important if you do want verbatim output from input (as in cat(1) command)
read() does not zero terminate anything. It is a function that is used to read any bytes from a file descriptor, including zero bytes. As such, zero terminating the result would be kind of pointless. Instead, read() returns the amount of bytes that were successfully read. You must interpret that return value if you want to do correct reading.
You have to initialize the 'buf' with null. As 'buf' is declares local array and you didn't initialize it with null, 'read' call is reading up to sizeof(buf) which is 10 bytes. If you giving input string less than sizeof(buf) size, then it will read the remaining junk characters from the 'buf'. So initialize the 'buf' with null.
int main(int argc, char **argv) {
char buf[10] = {'\0'};
int ret;
while(1) {
ret = read(0, buf, sizeof buf);
printf("\n%s\n", buf);
}
return(0);
}
buf[10] = ... is undefined behavior. The buffer goes from 0..9, so the naive approach should be buf[9] = 0;.
This still doesn't work because it is not linked to how much you actually read. You do know this because of the ret variable - so add buf[ret] = 0; before trying to output buf.
edit: as pointed out in the comments, if the full amount of chars has been read (in this case 10) then buf[ret] is the same as buf[10] and so it is still undefined behavior. Easiest solution is to ensure the buffer is bigger than the max size you are trying to read.
you should set buf[ret] to '\0' not buf[10].
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof(buf));
buf[ret] = '\0';
printf("%s\n", buf);
}
return(0);
}
well, as commented there are some mistakes in my answer. I just want to point out the single point, so I haven't consider too much.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof(buf) - 1); // keep last byte for termination charactor
if (ret == -1) {
printf("error:%s\n", strerror(errno));
break;
} else if (ret == 0) {
// end of file. such as ctrl + D
break;
} else {
// ret certainly less than sizeof(buf)
buf[ret] = '\0';
printf("%s\n", buf);
}
}
return(0);
}

scan a sequence of lines of strings with white spaces

My code is for reading an input of strings and newline is used as delimiter. But my code doesn't read the inputs correctly and the output is different from the input. In my code i used %*[\n]c to read the newline character for if any present and skip it so that it is not included while reading the next string.
#include<stdio.h>
main()
{
char s[100],s1[100],s2[100];
scanf("%[^\n]s%*[\n]c%[^\n]s%*[\n]c%[^\n]s%*[\n]c",s,s1,s2);
printf("%s%s%s",s,s1,s2);
return 0;
}
My inputs for this program are below:
this is 1st line
this is 2nd line
this is 3rd line
My output is
this is 1st line.N=ΓΆ
Can someone correct my code.Thank you.
In the posted code, there is a risk of buffer overflow since no maximum width is specified for the input buffers. Such widths should always be specified for safe code; remember to leave space for the null character that terminates the string.
scanf(" %99[^\n] %99[^\n] %99[^\n]", s, s1, s2);
The fgets() function is better suited to read lines of input. Note that fgets() keeps the newline when it reads a line of input, so you may want to remove this in some cases. Also, if the user inputs more characters than will fit in the specified buffer, the newline and some characters will remain in the input stream. But this is no different than using scanf(), in that one must always be careful about what may be left behind in the input stream after an IO operation. In any event, using fgets() is generally less error-prone than using scanf(), and there is benefit in having user input stored in a string. The sscanf() function can always be used on the string obtained with fgets(), but in this case you still have the input string to work with after calling sscanf().
Also, note that the function signature in the OP code needs to be one of:
int main(void)
int main(int argc, char **argv)
int main(int argc, char *argv[])
Here is an example using fgets() to read and then display lines of input:
#include <stdio.h>
#include <stdlib.h>
#define MAXLINES 25
#define BUF_LEN 1000
int main(void)
{
char lines[MAXLINES][BUF_LEN];
size_t num_lines = 0;
puts("Enter some lines of text (empty line to quit):");
for(num_lines = 0; num_lines < MAXLINES; num_lines++) {
if (fgets(lines[num_lines], BUF_LEN, stdin) == NULL) {
fprintf(stderr, "Error in fgets\n");
exit(EXIT_FAILURE);
}
if (lines[num_lines][0] == '\n') {
break;
}
}
for (size_t i = 0; i < num_lines; i++) {
printf("%s",lines[i]);
}
return 0;
}
#include<stdio.h>
main()
{
char s[100], s1[100], s2[100];
scanf("%[^\n] %[^\n] %[^\n]", s, s1, s2);
printf("%s\n%s\n%s\n", s, s1, s2);
}

How To Read String that contains Spaces, in C language

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.

Why are extra garbage characters printed?

I try to use read() to get some characters from file just for learning this API. I have create a file called "file" in the same directory and it is content:
1:2:ab:cd:ef
Here is the code:
#include <stdio.h>
#include <error.h>
int read_indent(int sockfd){
int sport, cport;
char user[3], rtype[3], addinfo[3];
char buffer[4+4+3+3+3+1];
if(read(sockfd, buffer, sizeof(buffer)) <= 0) {
perror("read: %m");
return -1;
}
buffer[sizeof(buffer)-1] = '\0';
sscanf(buffer, "%d:%d:%s:%s:%s", &sport, &cport, rtype, user, addinfo);
printf("%d:%d:%s:%s:%s", sport, cport, rtype, user, addinfo);
return 0;
}
int main(){
FILE *file_pt = fopen("file", "r");
if(file_pt == NULL) { printf("fopen error\n"); return -1;}
char buf[128];
int a = read_indent(fileno(file_pt));
fclose(file_pt);
return 0;
}
My printf returns me
1:2:ab:cd:ef::xPvx
where x is some garbage character I cannot recognize. What is the reason for this? int is 4 bytes in my system.
One issue is that you didn't specify a width for the %s parameters. This means that it matches up until the first whitespace character. There are no whitespace characters in your string, so the first %s matches until the end, leaving only garbage data after your string to fill the other variables.
Try this:
sscanf(buffer, "%d:%d:%2s:%2s:%2s", &sport, &cport, rtype, user, addinfo);
The other issue is that you don't null-terminate your buffer properly, read returns the number of characters read - add a null after that.
char buffer[4+4+3+3+3+1];
The buffer is bigger than what you plan to read and that's ok, but:
buffer[sizeof(buffer)-1] = '\0';
This is wrong, add the \0 at size+1 , where size is what you get back with read(), the actual number of bytes read.
See here:
The value returned may be less than nbyte if the number of bytes left in the file is less than nbyte, if the read() request was interrupted by a signal, or if the file is a pipe or FIFO or special file and has fewer than nbyte bytes immediately available for reading.
char buffer[4+4+3+3+3+1];
if(read(sockfd, buffer, sizeof(buffer)) <= 0) {
//....
}
buffer[sizeof(buffer)-1] = '\0';
The read function does not add \0 to the buffer after reading. But you read just 12 bytes, and your buffer size is 18. So you still have 5 bytes of garbage in your buffer. This gets added to the last string you read.

Resources