#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);
}
Related
I'm using a Ubuntu Machine compiling with Clang.
I'm reading a simple file, storing it into a buffer then getting the length. I'm anticipating receiving a 5 but got a 6.
strlen() isn't suppose to include the null terminator. Is this perhaps because I performed a cast on the buffer?
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
unsigned char buffer[30];
memset(buffer, '\0', 30);
int fd_read = open("test.txt", O_RDONLY);
read(fd_read, buffer, 29);
ssize_t length = strlen((const char *)buffer);
printf("%zu\n", length);
}
Contents of test.txt:
Hello
Output:
6
strlen() isn't suppose to include the null terminator.
That is true.
Is this perhaps because I performed a cast on the buffer?
The cast is unnecessary but it is not what is causing the problem.
I'm reading a simple file, storing it into a buffer then getting the length. I'm anticipating receiving a 5 but got a 6.
The likely scenario is that you have newline character at the end of the read string, as pointed out by Chris Dodd, which strlen will count. To remove it:
buffer[strcspn(buffer, "\n")] = '\0';
Other considerations about your code:
You should verify the return value of open to confirm that the file was successfuly accessed.
memset(buffer, '\0', 30); is unnecessary, you can null terminate buffer:
ssize_t nbytes = read(fd_read, buffer, sizeof buffer - 1);
if(nbytes >= 0)
buffer[nbytes] = '\0';
Or you can initialize the array with 0s:
unsigned char buffer[30] = {'\0'}; // or 0
Your program is somewhat convoluted, using modified types for no reason. Yet the problem does not come from these typing issues nor the use of casts, it is much more likely the file contains 6 bytes instead 5, namely the letters Hello and a newline(*).
Here is a modified version:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
char buffer[30] = { 0 };
int fd_read = open("test.txt", O_RDONLY);
if (fd_read >= 0) {
int count = read(fd_read, buffer, sizeof(buffer) - 1);
size_t length = strlen(buffer);
printf("count=%d, length=%zu\n", count, length);
printf("contents: {");
for (size_t i = 0; i < count; i++) {
printf("%3.2X", (unsigned char)buffer[i]);
}
printf(" }\n");
close(fd_read);
}
return 0;
}
(*)or possibly on legacy platforms, Hello and an end of line sequence CR/LF (7 bytes) that is translated to a single '\n' byte by the read library function that is a wrapper on system calls that performs complex postprocessing
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
}
I have been trying to get strcmp to return true in the following program for many days now, I have read the man pages for strcmp, read, write... I have other's posts who have had the exact same problem. The following source code is just a test program that is frustrating the heck out of me, there are some commented out lines that are other attempts I've made at getting strcmp to work as expected. I have compiled with 'gdb -g' and stepped through one instruction at a time. The printf statements pretty much tell the whole story. I cannot get the value of buf, or bufptr to equal 't' ever. I have simplified the program, and had it just print one character at a time one after the other to the screen and they print as expected from whatever file is read-in, however, as soon as I start playing with strcmp, things get crazy. I cannot for the life of me figure out a way to get the value in buf to be the single char that I am expecting it to be.
When simplified to just the write(1,...) call, it writes the expected single char to stdout, but strcmp to a single 't' never returns 0. !!!!! Thank you in advance. I originally didnt have bufptr in there and was doing a strcmp to buf itself and also tried using bufptr[0] = buf[0] and the still were not the same.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define BUF_SIZE 1
void main(int argc, char *argv[])
{
char buf[BUF_SIZE];
int inputFd = open(argv[1], O_RDONLY);
char tee[] = "t";
int fff = 999;
char bufptr[BUF_SIZE];
// char *bufptr[BUF_SIZE];
while (read(inputFd, buf, BUF_SIZE) > 0) {
bufptr[0] = buf[0];
// bufptr = buf;
printf("********STRCMP RETURNED->%d\n", fff); // for debugging purposes
printf("--------tee is -> %s\n", tee); // for debugging purposes
printf("++++++++buf is -> %s\n", buf); // " " "
printf("########bufptr is -> %s", bufptr); // " " "
write (1, buf, BUF_SIZE);
if ((fff = strcmp(tee, bufptr)) == 0)
printf("THIS CHARACTER IS A T");
}
close(inputFd);
}
The str-family of functions expects strings as inputs, which are arrays storing null-terminated character sequences. However, you do not provide space in the buffer for the null character. To make the buffers strings, you need to add space for the null-character and zero-out the value so that they end with the null character.
void main(int argc, char *argv[])
{
char buf[ BUF_SIZE + 1 ] = {0};
int inputFd = open(argv[1], O_RDONLY);
char tee[] = "t";
while (read(inputFd, buf, BUF_SIZE) > 0) {
if ( strcmp( tee, buf ) == 0 )
printf("THIS CHARACTER IS A T");
}
close(inputFd);
}
// Some code for initialization
int fd[2];
pipe(fd);
int k = fork();
if (k == 0) { // Child
dup2(fd[1], fileno(stdout));
execl("someExecutable", NULL); // The executable just printfs one line
}
else if (k > 0) { // Parent
wait(&status);
while (read(fd[0], buffer, 1) > 0) {
printf("%s", buffer);
}
}
I omitted error checking.
First, if my executable has printf("some line\n");, my output on screen looks like s?9o?9m?9e?9 ?9l?9i?9n?9e?9. Why are there these random characters in between?
Second, my reading never ends. The read end of the pipe should've closed when the executable ended right?
Thank you.
You're printing binary data. The following
while (read(fd[0], buffer, 1) > 0) {
printf("%s", buffer);
}
Will print until it gets a NULL ie '\0'. Try this instead
while (read(fd[0], buffer, 1) > 0) {
printf("%.*s", 1, buffer);
}
This code might help illustrate the point about printf and null terminated strings...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(void) {
srand(time(NULL));
size_t n = 0;
//First we create some random data.
//Lets assume this is our binary stream
char *str_cpy = malloc(1024);
n = 0;
while(n++ < 1024) {
str_cpy[n] = rand() % 255;
}
//We have a known string we want to print
const char *str = "foobar";
printf("%s\n", str);
memcpy(str_cpy, str, 6);//Ooops: forgot to copy the null terminator
size_t str_len = strlen(str_cpy);
// This is unlikely to print 6
printf("%zu\n", str_len);
//This is undefined behavior
printf("%s\n", str_cpy);
free(str_cpy);
return 0;
}
You have to pass a (pointer to) null-terminated string to %s format specifier in printf().
To print one character, using %c is good.
while (read(fd[0], buffer, 1) > 0) {
printf("%c", *buffer);
}
If your buffer is declared as char buffer, then pass a pointer to it in read(), if it is declare as buffer[], then you may want to pass the size as the parameter instead of 1, as you are already checking for the status for read() which should return the number of bytes read, if successful. Now change printf("%c"...) or printf("%s"...), accordingly.
I cannot for the life of me remember how to do this. This program opens a file then reads the file. All I would like it to do is print out the contents it has just read.
int main(int argc, char *argv[])
{
char memory[1000]; //declare memory buffer size
int fd = 0;
int count = 1000;
if ((fd = open(argv[1], O_RDONLY)) == -1)
{
fprintf(stderr, "Cannot open.\n");
exit(1);
}
read(fd, memory, count);
//printf the buffered memory contents
return 0;
}
printf accepts %s format to print a C-string. However, by default it requires that string to have a null-terminator (0x0 ASCII code). If you are sure it was read by the call to read then you can do this:
printf("%s\n", memory);
However, you cannot be sure. Because you don't even check how many bytes were read... or for error code.
So you have to fix your code first.
Once you are done checking for errors and know how many bytes were read, you can do this:
printf("%.*s\n", (int)bytes_that_were_read, memory);
Good luck!
for (unsigned int i = 0; i < count; i++) {
printf("%c", memory[i]);
}
Do you have to stick to printf() for some reason? What if the file is binary with '\0' somewhere inside? This will break even printf("%.*s", ...). If you read with read() you should be able to write with write():
while (bytes_written < bytes_read)
{
ssize_t x = write(STDOUT_FILENO,
memory + bytes_written,
bytes_read - bytes_written);
if (-1 == x)
{
exit(1);
}
bytes_written += x;
}
Set the last char to \0 in memory
use printf()
Or read one character less because last one you will need to set as \0
You can use a for loop and printf("%c", buffer[i]) to print one char at a time or you can use printf("%s", buffer) if the buffer is a null-terminated string.