Using read() system call - c

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.

Related

Read N bytes from a file and print it using read() and write()

I'm trying to read a program that reads N bytes from a file using read() and prints them in STDOUT using write(). The thing is, the user can also especify the blocksize, by default it's 1024 and can only get up to 1048576. I have to store what I read in a buffer, but that buffer can't be the same size as the bytes that I have to read because, otherwise, I could potentially create a buffer too large for the stack size. Therefore, I create a buffer as large as the blocksize so I just read until it's full, write and then read again to the beginning of the buffer.
The problem with all this is that it definetely doesn't work as intended and I'm pretty sure there's gotta be an easier way to do this.
Relevant code:
void run_hd_b (int b, int fd, int BSIZE){
int res_read; //result from write
int res_write; //result from read
int read_bytes = 0;
char buffer[BSIZE];
int i = 0;
int count = 0;
if (b < BSIZE) count = b;
else count = BSIZE;
while (read_bytes < b && (res_read = read(fd, &buffer[i], count)) != 0){
if (res_read == BSIZE){
i = 0;
}
else i = res_read;
read_bytes += res_read;
while((res_write = write(1, buffer, res_read)) < res_read);
}
}
Below is a revised version of your loop that compiles (and probably works) followed by some notes.
#include <assert.h>
#include <unistd.h>
void run_hd_n (int n, int fd, int BSIZE) {
int res_read;
char buffer[BSIZE];
// can only get up to 1048576
assert(BSIZE <= 1048576);
for( int read_bytes=0; read_bytes < n; read_bytes += res_read ) {
if( (res_read = read(fd, buffer, BSIZE)) < BSIZE ) {
if( res_read == 0 ) return; // EOF or error
}
if( write(STDOUT_FILENO, buffer, res_read) < res_read ) return;
}
}
I changed b to n out of convention.
Stick close to the standard. read(2) and write(2) take size_t, not int. How will your program react if called with n == -1?
If you have a known imposed constraint, include it somewhere. You asserted a maximum size for BSIZE; I used assert to enforce it.
I couldn't tell if your question was about allocating the space or copying the data. I chose to address the latter.
It's not an error to read less than the full size of the buffer. No need to putz with count. Just read and see if you got anything.
You've written an I/O function with a void return type. How will the caller learn what happened? I would return res_read and let the caller test if he read as many as requested, else consult errno.

Why fread() is not getting the expected bytes?

I'm trying to read file in binary mode using C, but it only stores in the buffer the first 43 characters.
I want to read the file in groups of 245 bytes. It contains multi-character bytes and also null chars.
This is the content of the file in hex:
323031353037303735393036333130343739332032373231333732534e30323033323545533036303130340000000008557c0000000000693c0000000000000c0000000008557c0000000000693c0000000000000c0000000008557c0000000000693c0000000000000c00001c00001c00001c00000c00000c00000c00001c4d4e202020204942202020204f393920202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202039444b524d4144
And this is the code that I have:
char* to_hex(const char* strin) {
char * strout = malloc(2 * strlen(strin) + 1);
int x;
for (x = 0; x < strlen(strin);x++){
sprintf(&strout[x+x],"%02x", (int)(*(unsigned char*)(&strin[x])) );
}
strout[2 * strlen(strin)]='\0'
return strout;
}
int main(int argc, char *argv[]) {
FILE * pfinput = fopen("stack.bin", "rb");
int lrec = 245;
char* sbuff = (char *)malloc((lrec + 1) * sizeof(char));
if (pfinput != NULL) {
while (fread (sbuff, 1, lrec, pfinput) > 0){
sbuff[lrec] = '\0';
printf("len=%d hex=%s\n\n", strlen(sbuff), to_hex(sbuff) );
}
}
return 0;
}
It returns the following:
len=43 hex=323031353037303735393036333130343739332032373231333732534e3032303332354553303630313034
Why it only reads 43 characters instead of 245?
Do you have any alternative to do it?
When your string has embedded null characters, you cannot use strlen to reliably compute the number of characters. You need to capture the number of characters read by fread and use it.
int nread = 0;
while (( nread = fread (sbuff, 1, lrec, pfinput)) > 0)
Instead of
printf("len=%d hex=%s\n\n", strlen(sbuff), to_hex(sbuff) );
You need to use:
printf("len=%d hex=%s\n\n", nread, to_hex(sbuff) );
You'll also need to pass nread to to_hex so that you are able to treat the embedded null characters appropriately in that function.
char* to_hex(const char* strin, int nread) {
char * strout = malloc(2 * nread + 1);
int x;
for (x = 0; x < nread; x++){
sprintf(&strout[x+x],"%02x", (int)(*(unsigned char*)(&strin[x])) );
}
strout[2 * nread]='\0';
return strout;
}
After that, the printf line needs to be:
printf("len=%d hex=%s\n\n", nread, to_hex(sbuff, nread) );
PS Note that you are leaking memory here. Memory allocated by to_hex is used in the call to printf but after that it is not deallocated. You might want to capture that memory in a variable and deallocate it.
char* hexstring = to_hex(sbuff, nread);
printf("len=%d hex=%s\n\n", nread, hexstring);
free(hexstring);
Also, deallocate sbuff before returning from main.
free(sbuff);
PS 2 I would simplify the line
sprintf(&strout[x+x],"%02x", (int)(*(unsigned char*)(&strin[x])) );
to
int c = strin[x];
sprintf(&strout[x+x],"%02x", c );
'Upon successful completion, fread() shall return the number of elements successfully read',
The vaue returned by fread() is the ONLY way to determine how many bytes have been read into your buffer. At the end of the file, it is possible that less than 'lrec' chars may be read.

Can't read more than one word from named pipe, using poll

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?

How do I use scanf when I dont know how many values it will assign in C?

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.

What could cause fwrite() function so slow

I'm writing chucks of chat *ptr into file, but it takes me so long to finish.
I don't know why.
for(int i = 1; i < 64048; i++){
if(ptr[i] != NULL){
fwrite(ptr[i], 1, strlen(ptr[i])-6, file);
free(ptr[i]);
}
}
there is array of char pointers storing 8186 bytes, and I want to write into file, but the time is so long.
I have 64048 chunks of string need to write into file.
What could cause the slowing fwrite() ??
thank you
OP is using wrong method to size fwrite(), amongst other small errors.
If "array of char pointers storing 8186 bytes" means
1 each char array has 8186 significant bytes of data, use size 8186.
2 each char array is a NUL terminated string, then a test needs to occur to insure each is at least length 6. Not sure what this 6 is all about.
Note: size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream )
I suspect that the OP's - 6 is causing a problem when strlen(ptr[i]) is less than 6. This would make the negative difference a very large size_t, which is usually unsigned for count in fwrite().
for(int i = 0; i < 64048; i++){ // start at 0
if(ptr[i] != NULL){
int result;
result = fwrite(ptr[i], 1, 8186, file);
if (result != 8186) ; handle error;
// or
size_t len = strlen(ptr[i]) + 1; /// Add 1 for the NUL byte
if (len < 6) ; handle error of whatever the OP's 6 is about.
result = fwrite(ptr[i], 1, len, file);
if (result != len) ; handle error;
free(ptr[i]);
}
}

Resources