What could cause fwrite() function so slow - c

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]);
}
}

Related

fgets not reading whole line

I have a simple function, which is supposed to read line from standard input and put it into an char array, and I call this function in a loop till EOF is inputed. The problem is, that for extremely long lines (more than 10k characters) the fgets reads only a number of characters and stops, although it has not encountered any \n and the buffer has sufficient space, therefore next invoking of this function reads the rest of the line. Is there a reason for this behaviour (wrongly written code, some buffers I am unavare of)? Is it possible to fix it? If I have something wrong in the code I will be gratefull if you point it out.
static int getLine(char** line){
if(feof(stdin)) return 0;
int len=0;
char* pointer=NULL;
int max = 1;
while(1){
max+=400;
*line=(char*)realloc( *line,max);
if(pointer==NULL)
pointer=*line;
if(fgets(pointer, 401, stdin)==NULL)break;
int len1=strlen(pointer);
len+=len1;
if(len1!=400 || pointer[len1]=='\n')break;
pointer+=len1;
}
if(len==0)return 0;
if((*line)[len-1]=='\n'){
*line=(char*)realloc(*line, len);
(*line)[len-1]='\0';
return len-1;}//without \n
return len;
}
I think it likely that your problem is the way you use pointer:
char* pointer=NULL;
int max = 1;
while(1){
max+=400;
*line=(char*)realloc( *line,max);
if(pointer==NULL)
pointer=*line;
if(fgets(pointer, 401, stdin)==NULL)
break;
int len1=strlen(pointer);
len+=len1;
if(len1!=400 || pointer[len1]=='\n')
break;
pointer+=len1;
}
The trouble is that realloc() can change where the data is stored, but you fix it to the location you are first given. It is more likely that you'll have data move on reallocation if you handle large quantities of data. You can diagnose this by tracking the value of *line (print it after the realloc() on each iteration).
The fix is fairly simple: use an offset instead of a pointer as the authoritative length, and set pointer on each iteration:
enum { EXTRA_LEN = 400 };
size_t offset = 0;
int max = 1;
while (1)
{
max += EXTRA_LEN;
char *space = (char*)realloc(*line, max); // Leak prevention
if (space == 0)
return len;
*line = space;
char *pointer = *line + offset;
if (fgets(pointer, EXTRA_LEN + 1, stdin) == NULL)
break;
int len1 = strlen(pointer);
len += len1;
if (len1 != EXTRA_LEN || pointer[len1] == '\n')
break;
offset += len1;
}
I have reservations about the use of 401 rather than 400 in the call to fgets(), but I haven't the energy to expend establishing whether it is correct or not. I've done about the minimum changes to your code that I can; I would probably make more extensive changes if it were code I was polishing. (In particular, max would start at 0, not 1, and I would not use the +1 in the call to fgets().

Using read() system call

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.

Using write() system call to output dec/hex value of char array bufffer

int fd = open(argv[argc-1], O_RDONLY, 0);
if (fd >=0) {
char buff[4096]; //should be better sized based on stat
ssize_t readBytes;
int j;
readBytes = read(fd, buff, 4096);
char out[4096];
for (j=0; buff[j] != '\0'; j++) {
out[j] = buff[j];
//printf("%d ", out[j]);
}
write(STDOUT_FILENO, out, j+1);
close(fd);
}
else {
perror("File not opened.\n");
exit(errno);
}
This is code for a file dump program. The goal is to have a file and dump its contents to the command line both as ASCII chars and as hex/dec values. The current code is able to dump the ascii values, but not the hex/dec. We are allowed to use printf (as seen in the commented out section) but we can get extra credit if we don't use any high level (higher than system) functions. I have tried multiple ways to manipulate the char array in the loop, but it seems no matter how I try to add or cast the chars they come out as chars.
This isn't surprising since I know chars are, at least in C, technically integers. I am at a loss for how to print the hex/dec value of a char using write() and as have yet not seen any answers on stack that don't default to printf() or putchar()
You could make a larger buffer, make the conversion from ASCII to hex/dec (as needed) in that and print the new one. I hope this example illustrates the idea:
#include <stdlib.h>
#include <io.h>
int main (int argc, char** argv)
{
const char* pHexLookup = "0123456789abcdef";
char pBuffer[] = {'a', 'b', 'c'}; // Assume buffer is the contents of the file you have already read in
size_t nInputSize = sizeof(pBuffer); // You will set this according to how much your input read in
char* pOutputBuffer = (char*)malloc(nInputSize * 3); // This should be sufficient for hex, since it takes max 2 symbols, for decimal you should multiply by 4
for (size_t nByte = 0; nByte < nInputSize; ++nByte)
{
pOutputBuffer[3 * nByte] = pBuffer[nByte];
pOutputBuffer[3 * nByte + 1] = pHexLookup[pBuffer[nByte] / 16];
pOutputBuffer[3 * nByte + 2] = pHexLookup[pBuffer[nByte] % 16];
}
write(1 /*STDOUT_FILENO*/, pOutputBuffer, nInputSize * 3);
free(pOutputBuffer);
return EXIT_SUCCESS;
}
This will print a61b62c63, the ASCII and hex values side by side.
This was done on Windows so don't try to copy it directly, I tried to stick to POSIX system calls. Bascially for hex you allocate a memory chunk 3 times larger than the original (or more if you need to pad the output with spaces) and put an ASCII symbol that corresponds to the hex value of the byte next to it. For decimal you will need more space since it the value can span to 3 characters. And then just write the new buffer. Hope this is clear enough.
How about:
unsigned char val;
val = *out / 100 + 48;
write(STDOUT_FILENO, &val, 1);
val = (*out - *out / 100 * 100 ) / 10 + 48;
write(STDOUT_FILENO, &val, 1);
val = (*out - *out / 10 * 10) + 48;

Get number of not null bytes fread()

I am developing simple server-client app and now I have problem with reading file on server side. Here is code:
int size;
for (i = 0; i < parts; i++) {
size = fread(buffer, 1, 256, file);
printf("size: %i \n", size);
send(sockfd, buffer, size, 0);
/* ... */
}
I supposed that if fread() can read only (for example) 50 bytes, then size will be 50, but it's not true. It's still 256.
Is there any simple way how to get number of not null bytes?
If you want to have the length of the buffer after fread(), why don't use strlen()?
Also, its probably not a good idea to depend on the return value of fread() for number of bytes read. In case, if the size (second argement) is not 1, it may cause you trouble with actual bytes count.
size_t fread(void * ptr, size_t size, size_t nmemb, FILE * stream) returns the number of elements successfully read. In OP's case, a return value of 256 means 256 char are read.
A simple way to get number of "not null bytes" would entail a simple loop.
size_t size = fread(buffer, 1, 256, file);
size_t count = 0;
for (size_t i = 0; i< size; i++) {
if (buffer[i] == '\0') count++;
}
number_of_not_null_bytes = count;
As #Ron Burk says, the \0 may be interspersed in buffer and need select handling before passing on to send().

Why does this code not output the expected output?

This can be a good question for finding bugs.
No? Okay for beginners at least.
#define SIZE 4
int main(void){
int chars_read = 1;
char buffer[SIZE + 1] = {0};
setvbuf(stdin, (char *)NULL, _IOFBF, sizeof(buffer)-1);
while(chars_read){
chars_read = fread(buffer, sizeof('1'), SIZE, stdin);
printf("%d, %s\n", chars_read, buffer);
}
return 0;
}
Using the above code, I am trying to read from a file using redirection ./a.out < data. Contents of input file:
1line
2line
3line
4line
But I am not getting the expected output, rather some graphical characters are mixed in.
What is wrong?
Hint: (Courtesy Alok)
sizeof('1') == sizeof(int)
sizeof("1") == sizeof(char)*2
So, use 1 instead :-)
Take a look at this post for buffered IO example using fread.
The type of '1' is int in C, not char, so you are reading SIZE*sizeof(int) bytes in each fread. If sizeof(int) is greater than 1 (on most modern computers it is), then you are reading past the storage for buffer. This is one of the places where C and C++ are different: in C, character literals are of type int, in C++, they are of type char.
So, you need chars_read = fread(buffer, 1, SIZE, stdin); because sizeof(char) is 1 by definition.
In fact, I would write your loop as:
while ((chars_read = fread(buffer, 1, sizeof buffer - 1)) > 0) {
buffer[chars_read] = 0; /* In case chars_read != sizeof buffer - 1.
You may want to do other things in this case,
such as check for errors using ferror. */
printf("%d, %s\n", chars_read, buffer);
}
To answer your another question, '\0' is the int 0, so {'\0'} and {0} are equivalent.
For setvbuf, my documentation says:
The size argument may be given as zero to obtain deferred optimal-size buffer allocation as usual.
Why are you commenting with \\ instead of // or /* */? :-)
Edit: Based upon your edit of the question, sizeof("1") is wrong, sizeof(char) is correct.
sizeof("1") is 2, because "1" is a char array containing two elements: '1' and 0.
Here's a byte-by-byte way to fread the lines from a file using redirection ./a.out < data.
Produces the expected output at least ... :-)
/*
Why does this code not output the expected output ?,
http://stackoverflow.com/questions/2378264/why-does-this-code-not-output-the-expected-output
compile with:
gcc -Wall -O3 fread-test.c
create data:
echo $'1line\n2line\n3line\n4line' > data
./a.out < data
*/
#include <stdio.h>
#define SIZE 5
int main(void)
{
int i=0, countNL=0;
char singlechar = 0;
char linebuf[SIZE + 1] = {0};
setvbuf(stdin, (char *)NULL, _IOFBF, sizeof(linebuf)-1);
while(fread(&singlechar, 1, 1, stdin)) // fread stdin byte-by-byte
{
if ( (singlechar == '\n') )
{
countNL++;
linebuf[i] = '\0';
printf("%d: %s\n", countNL, linebuf);
i = 0;
} else {
linebuf[i] = singlechar;
i++;
}
}
if ( i > 0 ) // if the last line was not terminated by '\n' ...
{
countNL++;
linebuf[i] = '\0';
printf("%d: %s\n", countNL, linebuf);
}
return 0;
}
char buffer[SIZE + 1] = {0};
This isn't doing what you expect, it is making buffer point to a one byte region in the programs constant data segment. I.e this will corrupt SIZE amount of bytes and possibly cause a memory protection fault. Always initialize C strings with strcpy() or equivalent.

Resources