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.
Related
#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);
}
// 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 am simulating having two writers and one reader, based on this answer.
So, I create two pipes and I write one actual string to every pipe and one string which notifies the reader that he is done with this writer.
However, it will only read the first string and sometimes the ending string of the 2nd pipe.
What am I missing?
reader.c
int main() {
int w_no = 2;
int fd[w_no];
char * myfifo[w_no];
fill_names(myfifo, w_no);
print_names(myfifo, w_no);
struct pollfd fdtab[w_no];
int done[w_no];
/* create the FIFO (named pipe) */
int i;
for (i = 0; i < w_no; ++i) {
//fd[i] = open(myfifo[i], O_RDONLY);
while( (fd[i] = open(myfifo[i], O_RDONLY)) == -1);
fdtab[i].fd = fd[i];
fdtab[i].events = POLLIN;
fdtab[i].revents = 0;
done[i] = 0;
}
char buffer[1024];
ssize_t bytes;
printf("Edw prin\n");
while(not_all_done(done, w_no)) {
int retpoll = poll(fdtab, w_no, 300);
if(retpoll != 0) {
if (retpoll == -1) {
perror("poll");
break;
}
for(i = 0; i < w_no; ++i) {
if(fdtab[i].revents & POLLIN) {
printf("Edw %d %d %d %d\n", i, retpoll, fdtab[i].revents, POLLIN);
//read the written pipe
while((bytes = read(fdtab[i].fd, buffer, sizeof(buffer))) > 0)
printf("Read |%s| %d %d %d\n", buffer, retpoll, fdtab[i].revents, POLLIN);
if(!strcmp(buffer, "++"))
done[i] = 1;
}
}
} else if (retpoll == 0) {
/* the poll has timed out, nothing can be read or written */
printf("timeout from writer\n");
break;
}
}
for (i = 0; i < w_no; ++i) {
close(fd[i]);
}
free_names(myfifo, w_no);
return 0;
}
writer.c
int main() {
int w_no = 2;
int fd[w_no];
char * myfifo[w_no];
fill_names(myfifo, w_no);
print_names(myfifo, w_no);
/* create the FIFO (named pipe) */
int i;
int bytes;
for (i = 0; i < w_no; ++i) {
mkfifo(myfifo[i], 0666);
fd[i] = open(myfifo[i], O_WRONLY);
while( (bytes = write(fd[i], "Hi+", sizeof("Hi+"))) == 3);
printf("wrote %d bytes, %d\n", bytes, sizeof("Hi+"));
while( (bytes = write(fd[i], "++", sizeof("++"))) == 2);
printf("wrote %d bytes, %d\n", bytes, sizeof("++"));
}
for (i = 0; i < w_no; ++i) {
close(fd[i]);
unlink(myfifo[i]);
}
free_names(myfifo, w_no);
return 0;
}
Sample output:
/tmp/myfifo_0
/tmp/myfifo_0
/tmp/myfifo_1
/tmp/myfifo_1
wrote 4 bytes, 4
wrote 3 bytes, 3
wrote 4 bytes, 4
Edw prin
wrote 3 bytes, 3
Edw 0 2 17 1
Read |Hi+| 2 17 1
Edw 1 2 1 1
Read |Hi+| 2 1 1
^C
EDIT
When the Hi+ strings are arriving the value of bytes is 7.
The ending string I am trying to send is ++, but it doesn't get read.
EDIT_2
char* concat(char *s1, char *s2) {
char *result = malloc(strlen(s1) + strlen(s2) + 1); //+1 for the null-terminator
//in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
void fill_names(char* f[], int n) {
int i = 0;
char * buf = "/tmp/myfifo_";
char str[15];
for (; i < n; ++i) {
sprintf(str, "%d", i);
f[i] = concat(buf, str);
}
}
Idea
Maybe the writer closes and unlinks the pipes before the data is read from them? If so, what should I do to prevent that?
If put a sleep(10) before that, it wont' change behaviour, it will just read the two first strings, but it will take more time and then it will hang up (because it waits the ending strings).
EDIT_3
I also have a main.c which execs reader and writer.
There is a problem in your string writing:
while( (bytes = write(fd[i], "Hi+", sizeof("Hi+"))) == 3);
printf("wrote %d bytes, %d\n", bytes, sizeof("Hi+"));
while( (bytes = write(fd[i], "++", sizeof("++"))) == 2);
printf("wrote %d bytes, %d\n", bytes, sizeof("++"));
Here you send 7 bytes: H i + \0 + + \0 , because the sizeof() of a string litteral includes the null terminator.
By the way, while((bytes=write(...))==3) will loop as long as 3 bytes could be written. This doesn't happen here because of the null terminator your writing as well. But better remove the enclosing while.
As the pipe is a stream, nothing garantees you will receive the bytes in two distinct reads. In fact, all your explanations and logs show that your receive all the 7 bytes at once.
However, you print the content using printf("Read |%s| %d %d %d\n"...): the result of prining a string that includes a '\0" is undefined. In your case, the printed string is truncated. So only "Hi+" is printed but "\0++" remains hidden in the buffer.
By the way, while((bytes = read(...)) > 0) could loop and print several times. This is not per se a problem. It's just that if the writer sends the data in time, the continuous reading could temporary lock out the reading of the other pipes. Generally in a poling programme, one prefer to read a little bit from every ready pipe.
Your check for the ending string
if(!strcmp(buffer, "++"))
done[i] = 1;
might in most cases not succeed. You are not sure that one write on one side will result in on read in the other side. So your "++" string will not necessarily be at the begin of the buffer. It could be anywhere in the buffer, so you have to search for it. It could even be split between two successive reads.
By the way, it might be that read() only finds back partial data (ex: "i+") without the terminating null. If you'd then try to print your buffer assuming that there is a valid string in it, you'd risk a buffer overflow.
Recommendation:
If your named pipes are meant for processing text data, I would suggest to add a '\n' at the end of each group of data you want to send, and write the strings to the pipe without the terminating null:
bytes = write(fd[i], "Hi+\n", sizeof("Hi+\n")-1);
Then, when you read, you could manage the buffer like a string: always add the trailing 0:
bytes = read(fdtab[i].fd, buffer, sizeof(buffer)-1); // leave a byte for terminator
if (bytes>0) {
buffer[bytes]=0; // end of string.
// process the string in the buffer
}
else if (bytes==0) {
done[i]=1;
}
Finally for identifying your end command, assuming that you've send it as "++\n" there are three possibilities:
if (strncmp(buffer,"++\n",3)==0 /* it's at the beginning of the buffer */
|| strstr(buffer, "\n++\n") ) /* it's in the middle but not a subpart and preceded by a packet separator */
done[i]=1;
But you also have to check for splits between two reads. This is more delicate, but I'm sure you find a way ;-)
Try to also print the number of bytes that you read in your reader program. My guess is that you have read some more bytes than you think, but when printing the string you only get the bytes before the first terminating zero.
Was it your intention to send terminating zeros on the named pipe? Maybe it would have been better to send something else like a newline?
For an assignment in class we were tasked with using the read() function to read a file containing numbers. While I was able to read the numbers into a buffer I have been unable to move them from the buffer into a char *array so that they can be easily accessed and sorted. Any advice is appreciated.
int readNumbers(int hexI, int MAX_FILENAME_LEN, int **array, char* fname) {
int numberRead = 0, cap = 2;
*array = (int *)malloc(cap*sizeof(int));
int n;
int filedesc = open(fname, O_RDONLY, 0);
if(filedesc < 0){
printf("%s: %s\n", "COULD NOT OPEN", fname);
return -1;
}
char * buff = malloc(512);
buff[511] = '\0';
while(n = read(filedesc, buff+totaln, 512 - totaln) > 0) //Appears to loop only once
totaln += n;
int len = strlen(buff);
for (int a = 0; a < len; a++) { //Dynamically allocates array according to input size
if ((&buff[a] != " ") && (&buff[a] != '\n'))
numberRead++;
if (numberRead >= cap){
cap = cap*2;
*array = (int*)realloc(*array, cap*sizeof(int));
}
}
int k = 0;
while((int *)&buff[k]){ //attempts to assign contents of buff to array
array[k] = (int *)&buff[k];
k++;
}
}
Your use of read() is wrong. There are at least two serious errors:
You ignore the return value, except to test for end-of-file.
You seem to assume that read() will append a nul byte after the data it reads. Perhaps even that it will pad out the buffer with nul bytes.
If you want to read more data into the same buffer after read() returns, without overwriting what you already read, then you must pass a pointer to the first available position in the buffer. If you want to know how many bytes were read in total, then you need to add the return values. The usual paradigm is something like this:
/*
* Read as many bytes as possible, up to buf_size bytes, from file descriptor fd
* into buffer buf. Return the number of bytes read, or an error code on
* failure.
*/
int read_full(int fd, char buf[], int buf_size) {
int total_read = 0;
int n_read;
while ((n_read = read(fd, buf + total_read, buf_size - total_read)) > 0) {
total_read += n_read;
}
return ((n_read < 0) ? n_read : total_read);
}
Having done something along those lines and not received an error, you can be assured that read() has not modified any element of the buffer beyond buf[total_read - 1]. It certainly has not filled the rest of the buffer with zeroes.
Note that it is not always necessary or desirable to read until the buffer is full; the example function does that for demonstration purposes, since it appears to be what you wanted.
Having done that, be aware that you are trying to extract numbers as if they were recorded in binary form in the file. That may indeed be the case, but if you're reading a text file containing formatted numbers then you need to extract the numbers differently. If that's what you're after then add a string terminator after the last byte read and use sscanf() to extract the numbers.
These are the instructions:
"Read characters from standard input until EOF (the end-of-file mark) is read. Do not prompt the user to enter text - just read data as soon as the program starts."
So the user will be entering characters, but I dont know how many. I will later need to use them to build a table that displays the ASCII code of each value entered.
How should I go about this?
This is my idea
int main(void){
int inputlist[], i = -1;
do {++i;scanf("%f",&inputlist[i]);}
while(inputlist[i] != EOF)
You said character.So this might be used
char arr[10000];
ch=getchar();
while(ch!=EOF)
{
arr[i++]=ch;
ch=getchar();
}
//arr[i]=0; TO make it a string,if necessary.
And to convert to ASCII
for(j=0;j<i;j++)
printf("%d\n",arr[j]);
If you are particular in using integer array,Use
int arr[1000];
while(scanf("%d",&arr[i++])!=EOF);
PPS:This works only if your input is one character per line.
scanf returns EOF on EOF
You have a reasonable attempt at a start to the solution, with a few errors. You can't define an array without specifying a size, so int inputlist[] shouldn't even compile. Your scanf() specifier is %f for float, which is wrong twice (once because you declared inputlist with an integer type, and twice because you said your input is characters, so you should be telling scanf() to use %c or %s), and really if you're reading input unconditionally until EOF, you should use an unconditional input function, such as fgets() or fread(). (or read(), if you prefer).
You'll need two things: A place to store the current chunk of input, and a place to store the input that you've already read in. Since the input functions I mentioned above expect you to specify the input buffer, you can allocate that with a simple declaration.
char input[1024];
However, for the place to store all input, you'll want something dynamically allocated. The simplest solution is to simply malloc() a chunk of storage, keep track of how large it is, and realloc() it if and when necessary.
char *all_input;
int poolsize=16384;
all_input = malloc(pool_size);
Then, just loop on your input function until the return value indicates that you've hit EOF, and on each iteration of the loop, append the input data to the end of your storage area, increment a counter by the size of the input data, and check whether you're getting too close to the size of your input storage area. (And if you are, then use realloc() to grow your storage.)
You could read the input by getchar until reach EOF. And you don't know the size of input, you should use dynamic size buffer in heap.
char *buf = NULL;
long size = 1024;
long count = 0;
char r;
buf = (char *)malloc(size);
if (buf == NULL) {
fprintf(stderr, "malloc failed\n");
exit(1);
}
while( (r = getchar()) != EOF) {
buf[count++] = r;
// leave one space for '\0' to terminate the string
if (count == size - 1) {
buf = realloc(buf,size*2);
if (buf == NULL) {
fprintf(stderr, "realloc failed\n");
exit(1);
}
size = size * 2;
}
}
buf[count] = '\0';
printf("%s \n", buf);
return 0;
Here is full solution for your needs with comments.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
// Number of elements
#define CHARNUM 3
int main(int argc, char **argv) {
// Allocate memory for storing input data
// We calculate requested amount of bytes by the formula:
// NumElement * SizeOfOneElement
size_t size = CHARNUM * sizeof(int);
// Call function to allocate memory
int *buffer = (int *) calloc(1, size);
// Check that calloc() returned valid pointer
// It can: 1. Return pointer in success or NULL in faulire
// 2. Return pointer or NULL if size is 0
// (implementation dependened).
// We can't use this pointer later.
if (!buffer || !size)
{
exit(EXIT_FAILURE);
}
int curr_char;
int count = 0;
while ((curr_char = getchar()) != EOF)
{
if (count >= size/sizeof(int))
{
// If we put more characters than now our buffer
// can hold, we allocate more memory
fprintf(stderr, "Reallocate memory buffer\n");
size_t tmp_size = size + (CHARNUM * sizeof(int));
int *tmp_buffer = (int *) realloc(buffer, tmp_size);
if (!tmp_buffer)
{
fprintf(stderr, "Can't allocate enough memory\n");
exit(EXIT_FAILURE);
}
size = tmp_size;
buffer = tmp_buffer;
}
buffer[count] = curr_char;
++count;
}
// Here you get buffer with the characters from
// the standard input
fprintf(stderr, "\nNow buffer contains characters:\n");
for (int k = 0; k < count; ++k)
{
fprintf(stderr, "%c", buffer[k]);
}
fprintf(stderr, "\n");
// Todo something with the data
// Free all resources before exist
free(buffer);
exit(EXIT_SUCCESS); }
Compile with -std=c99 option if you use gcc.
Also you can use getline() function which will read from standard input line by line. It will allocate enough memory to store line. Just call it until End-Of-File.
errno = 0;
int read = 0;
char *buffer = NULL;
size_t len = 0;
while ((read = getline(&buffer, &len, stdin)) != -1)
{ // Process line }
if (errno) { // Get error }
// Process later
Note that if you are using getline() you should anyway use dynamic allocated memory. But not for storing characters, rather to store pointers to the strings.