if i am writing into file with fwrite as follows
char buffer[3]={255,255,255,'\0'};
char buffer2[3]={0,0,0,'\0'};
fwrite(buffer, sizeof(char), sizeof(buffer), outputFile);
fwrite(buffer2, sizeof(char), sizeof(buffer2), outputFile);
what i am trying to understand is the third argument, sizeof(buffer)
my issue is that if the array has an appended '\0' nul character, does fwrite copy the nul character also into the file
also if i used a while loop to write into a file such as
int i=0;
while(i++<100){
fwrite(buffer, sizeof(char), sizeof(buffer), outputFile);
fwrite(buffer2, sizeof(char), sizeof(buffer2), outputFile);
}
what are the potential problems here directly to do with the nul character
also one more question , as i am having a problem with my program
int main (int argc, char *argv[]) {
// check that the types have the size i'm relying on here
assert (sizeof(bits8) == 1);
assert (sizeof(bits16) == 2);
assert (sizeof(bits32) == 4);
FILE *outputFile;
int squareSize;
outputFile = fopen(BMP_FILE, "wb");
assert ((outputFile!=NULL) && "Cannot open file");
writeHeader(outputFile);
printf ("Enter square size (must be a factor of %d): \n", SIZE);
scanf ("%d", &squareSize);
assert (SIZE % squareSize == 0);
char buffer[squareSize*BYTES_PER_PIXEL]; //white
char buffer2[squareSize*BYTES_PER_PIXEL]; //black
initialize(buffer, buffer2, squareSize);
int line=0;
int m=1;
while(line<SIZE){
if(line%squareSize==0&&m==1)
m=0;
else if(line%squareSize==1&&m==0)
m=1;
writeToFile(buffer,buffer2,m,outputFile,squareSize);
line+=squareSize;
printf("\nline is %d inside while loop ",line);
}
fclose(outputFile);
return EXIT_SUCCESS;
}
void writeHeader (FILE *file) {
assert(sizeof (bits8) == 1);
assert(sizeof (bits16) == 2);
assert(sizeof (bits32) == 4);
bits16 magicNumber = MAGIC_NUMBER;
fwrite (&magicNumber, sizeof magicNumber, 1, file);
bits32 fileSize = OFFSET + (SIZE * SIZE * BYTES_PER_PIXEL);
fwrite (&fileSize, sizeof fileSize, 1, file);
bits32 reserved = 0;
fwrite (&reserved, sizeof reserved, 1, file);
bits32 offset = OFFSET;
fwrite (&offset, sizeof offset, 1, file);
bits32 dibHeaderSize = DIB_HEADER_SIZE;
fwrite (&dibHeaderSize, sizeof dibHeaderSize, 1, file);
bits32 width = SIZE;
fwrite (&width, sizeof width, 1, file);
bits32 height = SIZE;
fwrite (&height, sizeof height, 1, file);
bits16 planes = NUMBER_PLANES;
fwrite (&planes, sizeof planes, 1, file);
bits16 bitsPerPixel = BITS_PER_PIXEL;
fwrite (&bitsPerPixel, sizeof bitsPerPixel, 1, file);
bits32 compression = NO_COMPRESSION;
fwrite (&compression, sizeof compression, 1, file);
bits32 imageSize = (SIZE * SIZE * BYTES_PER_PIXEL);
fwrite (&imageSize, sizeof imageSize, 1, file);
bits32 hResolution = PIX_PER_METRE;
fwrite (&hResolution, sizeof hResolution, 1, file);
bits32 vResolution = PIX_PER_METRE;
fwrite (&vResolution, sizeof vResolution, 1, file);
bits32 numColors = NUM_COLORS;
fwrite (&numColors, sizeof numColors, 1, file);
bits32 importantColors = NUM_COLORS;
fwrite (&importantColors, sizeof importantColors, 1, file);
}
void initialize(char *buffer, char*buffer2, int size){
//white for buffer 255,255,255 1 pixel
//black for buffer2 00,00,00 1 pixel
int buf = 255;
int buf2 = 0;
int i = 0;
while(i<size*3){
buffer[i]=buf;
buffer2[i]=buf2;
printf("\nbuffer 1 [i] is %c and i is %d\n",buffer[i],i);
printf("buffer 2 [i] is %c and i is %d\n",buffer2[i],i);
i++;
// printf("\nline ran %d times inside initialize loop ",i);
}
buffer[i]='\0';
buffer2[i]='\0';
printf("%s\n",buffer);
printf("%s",buffer2);
}
void writeToFile(char *buffer,char *buffer2, int m, FILE *file,
int squareSize){
int k = 0;
// printf("\nline ran %d times",line);
if(m==0){
while(k<(SIZE/squareSize)){
fwrite(buffer2, sizeof(char), sizeof(buffer2), file);
k+=1;
fwrite(buffer, sizeof(char), sizeof(buffer), file);
k+=1;
// printf("\nline ran %d times inside first if ",line);
}
}
else if(m==1){
while(k<(SIZE/squareSize)){
fwrite(buffer, sizeof(char), sizeof(buffer), file);
k+=1;
fwrite(buffer2, sizeof(char), sizeof(buffer2), file);
k+=1;
// printf("\nline ran %d times inside second else if",line);
}
}
}
the program is supposed to write to a file that is supposed to be a bmp file
the header write output function works fine
however i am having problem with the function initialize and the function writeToFile which i think has to do witht he nul pointer because i think fwrite is taking the nul pointer over as well and causing the bmp file to have the wrong information throw into it , also if i do remove teh nul character does fwrite produce problems by not stopping at the specified spot or does it stil copy correctly
i dont know what the problem is but the program is not writing in the order that i imagined
i have been at it ALL NIGHT and it still does not function correctly i am not sure where the problem is
the program is supposed to write into a 512 by 512 output file which is supposed to print out checkered black and white squares based on the input by user of a square which is a factor of 512
so that if the person chooses the input to be 256 , the program is supposed to divide the 512 by 512 space into 4 square with the first square being black then white, then white then black and etc
if the person choose 16 as the size of square in pixels, then i am supposed to divide the space into squares of 16 pixels sides ion the order of starting with black then white(across) next line above white then black all the way to the end
i think the problem is with my write to File function but i am not sure what the problem is, really confusing
hope you can help to give me some suggestions on how to deal with this problem
any help would be highly appreciated so that i can get this over and done with
The second argument of fwrite() is the size of each object, and the third argument is the number of objects. In your case, you tell it to write 4 objects of size 1, but here you could just write one object of size 4 just as easily.
"Nul characters" are irrelevant here, since they terminate strings, and fwrite() explicitly deals with binary objects, not strings. It'll write exactly what you give it to the file.
As an aside, a regular unqualified char can be (and often is) signed, rather than unsigned, so trying to stuff all those 255s into them may not be wise. unsigned char may be better for this.
In the writeToFile() function in your third block of code, this:
fwrite(buffer, sizeof(char), sizeof(buffer), file);
is a simple misunderstanding of how the sizeof operator works. In this context, buffer is not an array, it's a pointer to char that you have passed to the function. sizeof will therefore give you the size of a character pointer, usually 4 or 8 bytes, and that size will obviously be totally unrelated to the size of the buffer it points to. If char pointers are 8 bytes on your system, then sizeof(buffer) in this context will always evaluate to 8, regardless of whether you initially set up a 3 byte array, or a 4 byte array, or a 672 byte array.
To make what you want to do work in a function like this, you'll have to explicitly pass to the writeToFile() function the size of the buffer you created, and use that instead of sizeof.
fwrite and fread don't care at all about zero bytes. They simply write or read the number of bytes you ask for.
And note that buffer2 does not just have a '\0' appended but is in fact all '\0's since 0 and '\0' are identical in that context.
You don't need to zero-terminate your buffers since they aren't strings, they're just data and can contain zero-bytes within them.
Question: does fwrite copy the nul character also into the file?
Answer: The way you are calling it, the answer is "Yes". The third argument to the buffer is the number of objects that you wish to write to the stream.
Solution to your problem
You can change your variables
char buffer[3]={255,255,255,'\0'}; // This should be a compiler error/warning.
char buffer2[3]={0,0,0,'\0'}; // You have 4 items in {} for an array of size 3.
to
char buffer[3]={255,255,255};
char buffer2[3]={0,0,0};
You need a '\0' at the end of an array of char only if you want to treat the array as a null-terminated string. Since you are using the array to store only pixel values, you don't need to have the terminating null character in your array.
Potential pitfalls of not having the null character is that most functions that work with strings expect a terminating null character. They won't work with buffer or buffer2. Don't use:
Any of the standard string manipulation functions, such as strlen, strcpy.
printf("%s", buffer);.
and many other functions.
Considering your usage of those variable, I don't think you need to use them.
Related
So, I have this piece of code in c that is supposed to read from an ascii file and then return a string that is parsed and compiled into bytecode. When I try to get the size of a file using ftell, it returns 33 rather than 29 (the amount of bytes that the file has including new lines).
the file:
push #25
nop
push #44
add
hlt
the code:
uint8_t* read_ascii_file(uint8_t* path) {
FILE* file = fopen(path, "r");
if (file == NULL)
return NULL;
fseek(file, 0, SEEK_END);
uint32_t size = ftell(file);
fseek(file, 0, SEEK_SET);
uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t) * size);
if (buffer == NULL)
return NULL;
fread(buffer, sizeof(uint8_t), size, file);
buffer[size] = '\0';
fclose(file);
return buffer;
}
Four more bytes are added for seemingly no reason. My parser complains that "hlt====" is not a valid instruction ("====" are the 4 extra bytes).
Ftell or fseek is messing up in this situation and I don't know if it is a bug or not
I'm on Windows and I'm also using visual studio
You're not allocating enough space.
You allocate sizeof(uint8_t) * size bytes for the file contents, however this isn't enough to hold the null byte that you later add to terminate the string. So you write past the bounds of allocated memory, triggering undefined behavior.
Add 1 to leave space for the null terminator.
uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t) * size + 1);
Also, these lines are problematic:
fread(buffer, sizeof(uint8_t), size, file);
buffer[size] = '\0';
Because of the translation of newlines on windows, you'll end up reading in less bytes then the file actually contains. This means the teminating null byte is in the wrong place.
Save the return value of fread which will tell you how many bytes you actually read, then use that value to write the null byte.
size_t rval = fread(buffer, sizeof(uint8_t), size, file);
if (rval > 0) {
buffer[rval] = '\0';
}
I can't understand why function fread() behaves differently in these 2 examples:
1)
I have a structure with a short and a char (size is 4 bytes including padding) and an array of three such structures.If I write each short and char of each structure separately with fwrite() and then read that file with fread() to a variable whose type is that structure, I will read 4 bytes at a time (there will be 9 bytes in the file) so you can see that one byte will be left in 3rd iteration (and one byte will be lost in each iteration).What happens is that there is no 3rd read because I'm left with one byte and fread has to read 4 bytes.
2)
A simpler example, if I write a 1 byte char to a file with fwrite() and then put the content of that file into a 4 byte int with fread(), the integer will get that data.
Why does this happen?Why does the data get read in one case but not in the other if EOF is reached?
Here is the first example:
int main()
{
struct X { short int s; char c; } y, x[]=
{{0x3132,'3'},{0x3435,'6'},{0x3738,'9'}};
FILE *fp=fopen("FILE.DAT","wb+");
if (fp)
{
for(int i=0;i<sizeof(x)/sizeof(x[i]);)
{
fwrite(&x[i].s,sizeof(x[i].s),1,fp);
fwrite(&x[i].c,sizeof(x[i].c),1,fp);
i++;
}
rewind(fp);
for(int i=0;fread(&y,sizeof(y),1,fp);)
printf("%d:%x %c\n",++i, y.s, y.c);
fclose(fp);
}
return 0;
}
Second example:
int main()
{
FILE *fp=fopen("FILE.DAT","wb+");
char c = 'a';
fwrite(&c, sizeof(c), 1, fp);
rewind(fp);
int num;
fread(&num, sizeof(num), 1, fp);
fclose(fp);
return 0;
}
Why does the data get read in one case but not in the other if EOF is reached?
"What happens is that there is no 3rd read because I'm left with one byte and fread has to read 4 bytes." is a questionable premise.
1st Code did read 3 times. There are with no bytes left to read.
In both codes, the last read was a partial read with a fread() return value of 0.#Useless
(The first code did not print the result of the 3rd read.)
With fread(), a return value of 0 does not mean "end-of-file" was immediately encountered - nothing read. Instead, 0 means an complete read did not occur due to :
* "end-of-file" or partial read.
* rare I/O error.
Why does this happen?
In the 2nd code, results may differ due to Indeterminate behavior
fread() ... If a partial element is read, its value is indeterminate1 C11dr §7.21.8.1 2
fread(&num, sizeof(num), 1, fp) result may or may not be as expected.
A more informative example
int main(void) {
FILE *fp = fopen("FILE.DAT", "wb+");
char c = 'a';
printf(" %8X\n", c);
fwrite(&c, sizeof(c), 1, fp);
rewind(fp);
unsigned num = rand();
printf(" %8X\n", num);
size_t len = fread(&num, sizeof(num), 1, fp);
printf("%zu %8X\n", len, num);
len = fread(&num, sizeof(num), 1, fp);
printf("%zu\n", len);
fclose(fp);
return 0;
}
Output
61 as expected
5851F42D as expected - some random value
0 5851F461 Indeterminate! (in this case, looks like the LSByte was replaced.)
0 as expected
Moral of the story: assess the return value of fread() before relying on what was read into the buffer.
1 indeterminate value
either an unspecified value or a trap representation
... when EOF is reached ...
EOF isn't "reached". Many <stdio.h> functions return EOF as a signal that something went wrong, giving no indication what that something is. If you want to know what went wrong after receiving the signal, test with feof() and/or ferror().
I am attempting to read a file into a character array, but when I try to pass in a value for MAXBYTES of 100 (the arguments are FUNCTION FILENAME MAXBYTES), the length of the string array is 7.
FILE * fin = fopen(argv[1], "r");
if (fin == NULL) {
printf("Error opening file \"%s\"\n", argv[1]);
return EXIT_SUCCESS;
}
int readSize;
//get file size
fseek(fin, 0L, SEEK_END);
int fileSize = ftell(fin);
fseek(fin, 0L, SEEK_SET);
if (argc < 3) {
readSize = fileSize;
} else {
readSize = atof(argv[2]);
}
char *p = malloc(fileSize);
fread(p, 1, readSize, fin);
int length = strlen(p);
filedump(p, length);
As you can see, the memory allocation for p is always equal to filesize. When I use fread, I am trying to read in the 100 bytes (readSize is set to 100 as it should be) and store them in p. However, strlen(p) results in 7 during if I pass in that argument. Am I using fread wrong, or is there something else going on?
Thanks
That is the limitation with attempting to read text with fread. There is nothing wrong with doing so, but you must know whether the file contains something other than ASCII characters (such as the nul-character) and you certainly cannot treat any part of the buffer as a string until you manually nul-terminate it at some point.
fread does not guarantee the buffer will contain a nul-terminating character at all -- and it doesn't guarantee that the first character read will not be the nul-character.
Again, there is nothing wrong with reading an entire file into an allocated buffer. That's quite common, you just cannot treat what you have read as a string. That is a further reason why there are character oriented, formatted, and line oriented input functions. (getchar, fgetc, fscanf, fgets and POSIX getline, to list a few). The formatted and line oriented functions guarantee a nul-terminated buffer, otherwise, you are on your own to account for what you have read, and insure you nul-terminate your buffer -- before treating it as a string.
I'm having a bit of trouble getting my code to work, which is to open a file, count the number of characters in it, and then allocating that using malloc(). And then I am supposed to read the characters in from one file (mine contained "Hello World!") using fread(), and write them to a blank .txt file using fwrite.
My code so far is printing corrupted characters. I couldn't find any questions that were specific enough to my problem. If anyone could tell me what I'm doing wrong I'd appreciate it. I think it is specific to my fread and fwrite calls, but nothing I've tried works.
The code in question (not commented yet, sorry!):
#include <stdio.h>
#include <stdlib.h>
//initialized using ./a.out in.txt out.txt
int main(int argc, char *argv[])
{
FILE *fp;
int count, end;
char *memory;
char c[64];
fp = fopen(argv[1], "r");
if((fp) == NULL)
{
printf("Error: cannot open file.\n");
}
else
{
while((fgetc(fp))!= EOF)
{
count++;
}
memory = (char*)malloc(count);
c[64] = fread(memory, sizeof(char), 1, fp);
fclose(fp);
fp = fopen(argv[2], "w");
fwrite(c, sizeof(char), sizeof(c), fp);
fclose(fp);
free(memory);
}
return 0;
}
code have logical mistakes, as follow
Initialise variables int count= 0 , char c[64]= {0};
Type cast not required memory = malloc(count);
First you have counted number of char in file so Before reading again file rewind it by fseek(fp,0,SEEK_SET);
c[64] = fread(memory, sizeof(char), 1, fp); In this if you are reading single char, you should read complete file , To read complete file do fread(memory, 1, count, fp); and c[64] is out of bound and fread return the number of char successfully read .
fwrite(c, sizeof(char), sizeof(c), fp); In this you are writing complete char array to file but you have read only single variable in array which number of char read . So you are writing uninitialised char array to file. so you are getting corrupted character in file.
To write in file do fwrite(memory, 1, count, fp);
To solve problem ,avoid above error and read complete file in char array and then write.
Alright, there are a number of problems here, I'll start with the least bad:
memory = (char*)malloc(count);
Casting the return of malloc() is unnecessary and can potentially mask errors, for more info see here.
int count;
You never initialise count to anything. This is undefined behaviour and there is no guarantee it'll start at 0. It can start at random garbage left in memory. Same for end
c[64] = fread(memory, sizeof(char), 1, fp);
2 Problems here. c[64] is out of bounds for the array c since indexes start at 0, so the last element in the array is c[63]. sizeof(char) is defined to be 1, so use 1 instead. Further, fread() returns the amount of characters read, so not sure what you are trying to do with that value even.
fwrite(c, sizeof(char), sizeof(c), fp);
You're writing a complete uninitialised array to the file (=garbage)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fp;
char ch;
char buffer[80] ;
fp = fopen("c:\\Rasmi Personal\\hello.txt", "w");
if(fp == NULL)
{
printf("File not found");
exit(1);
}
else
{
while(1)
{
gets(buffer);
fwrite(buffer, strlen(buffer), 2, fp); /* I made, size_t nitems = 2 (third element/argument)*/
fwrite("\n", 1, 1, fp);
}
}
fclose(fp);
return 0;
}
Input:
Rasmi Ranjan Nayak
Output:
Rasmi Ranjan Nayak 0# ÿ" 8ÿ"
Why this garbage is coming.
According to fwrite() function. if the size_t nitems is more than 1 then the entered text will be written more than once.
But here why I am getting garbage?
You're telling fwrite() to write two times strlen(buffer) bytes from the buffer (by setting nmemb = 2 you're making it write two "objects", each of which is strlen(buffer) bytes long), so it reads twice the number of bytes that are actually present.
The "garbage" is simply whatever happens to appear in memory after the string ends in buffer.
This is broken code, nmemb should be 1.
The signature of fwrite function is
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
ptr
Pointer to the array of elements to be written.
size
Size in bytes of each element to be written.
count
Number of elements, each one with a size of size bytes.
stream
Pointer to a FILE object that specifies an output stream.
In this case, if you try to write count * size who is bigger (in bytes) than the original string you have this garbage. If you clean the buffer
memset(buffer,0,80*sizeof(char));
gets(buffer);
probably will see a different result
$ ./a.out
asdadsadasdsad
$ cat -v hello.txt
asdadsadasdsad^#^#^#^#^#^#^#^#^#^#^#^#^#^#
but the text is always writen once. the difference is how many bytes will be writen