Using fwrite with char* - c

How would one use fwrite to a file with a char*? If I want to append a char* to the end of a file with a newline after, would something like this be right? If you had a variable like:
char* c = "some string";
Would it be:
FILE *fp = fopen("file.txt", "ab");
fwrite(c, sizeof(char*), sizeof(c), fp);
fwrite("\n", sizeof(char), 1, fp);
close(fp);
I'm a bit confused about the 2nd fwrite statement. Is it sizeof(char*) or sizeof(char)? Should I also have sizeof(c) or is that incorrect? Any advice would be appreciated, thanks.

It is the first call of fwrite that is incorrect.
fwrite(c, sizeof(char*), sizeof(c), fp);
It should be written like for example
fwrite(c, sizeof( char ), strlen( c ), fp);
That is the string literal "some string" excluding its terminating zero character is written in the file.
As for this call
fwrite("\n", sizeof(char), 1, fp);
then one character '\n' is written in the file fp.
Note: the string literal "\n" is internally represented as a character array of two elements { '\n', '\0' }.
The function is declared like
size_t fwrite(const void * restrict ptr,
size_t size,
size_t nmemb,
FILE * restrict stream);
and according to the C Standard (7.21.8.2 The fwrite function)
2 The fwrite function writes, from the array pointed to by ptr, up to
nmemb elements whose size is specified by size, to the stream pointed
to by stream. For each object, size calls are made to the fputc
function, taking the values (in order) from an array of unsigned char
exactly overlaying the object. The file position indicator for the
stream (if defined) is advanced by the number of characters
successfully written. If an error occurs, the resulting value of the
file position indicator for the stream is indeterminate.

Other answers and comments here tell you what's wrong with the code you posted, but a better solution is to use fputs, which is specifically designed to write out nul-terminated strings:
const char* c = "some string";
FILE *fp = fopen("file.txt", "ab");
fputs (c, fp);
fputs ("\n", fp);
fclose(fp);

Related

How to read binary data from file as string in C

I have a .dat file I am trying to read from that has binary data. I have tried using
FILE *fp=fopen("whatever.dat","rb");
unsigned char buf[BUFFER_SIZE];
while(fread(buf,sizeof(buf),1,fp)){
printf("%s",buf);
}
to print the contents of the file, but it will only read the file signature. After that, it stops reading. How do I get it to read the whole file?
As #Barmar said, strings are null terminated. I prefer to use fwrite and get the file size, and output it to stdout. Since "get the file size" is dangerous, I suggest using sizeof(buf) instead.
FILE *fp = fopen("whatever.dat", "rb");
unsigned char buf[BUFFER_SIZE];
while(fread(buf, sizeof(buf), 1, fp)){
fwrite(buf, sizeof(char), sizeof(buf), stdout);
// Note, you can change "sizeof char" into 1.
}
Read data into a buffer, noting the length of it that was used.
Then print that buffer with fwrite(), possible a portion of it.
Note many characters do not print text as they are control characters.
if (fp) {
unsigned char buf[BUFFER_SIZE];
size_t len;
while((len = fread(buf,sizeof buf, 1, fp)) > 0) {
fwrite(buf,len, 1, stdout);
}

Length of character array after fread is smaller than expected

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.

Allocating memory from a file, then using fread and fwrite C

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)

create a binary file in C

I'm currently working on a binary file creation. Here is what I have tried.
Example 1:
#include<stdio.h>
int main() {
/* Create the file */
int a = 5;
FILE *fp = fopen ("file.bin", "wb");
if (fp == NULL)
return -1;
fwrite (&a, sizeof (a), 1, fp);
fclose (fp);
}
return 0;
}
Example 2:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char str[256] = {'\0'};
strcpy(str, "3aae71a74243fb7a2bb9b594c9ea3ab4");
fp = fopen("file.bin", "wb");
if(fp == NULL)
return -1;
fwrite(str, sizeof str, 1, fp);
return 0;
}
Example 1 gives the right output in binary form. But Example 2 where I'm passing string doesn't give me right output. It writes the input string which I have given into the file and appends some data(binary form).
I don't understand and I'm unable to figure it out what mistake I'm doing.
The problem is that sizeof str is 256, that is, the entire size of the locally declared character array. However, the data you are storing in it does not require all 256 characters. The result is that the write operation writes all the characters of the string plus whatever garbage happened to be in the character array already. Try the following line as a fix:
fwrite(str, strlen(str), 1, fp);
C strings are null terminated, meaning that anything after the '\0' character must be ignored. If you read the file written by Example 2 into a str[256] and print it out using printf("%s", str), you would get the original string back with no extra characters, because null terminator would be read into the buffer as well, providing proper termination for the string.
The reason you get the extra "garbage" in the output is that fwrite does not interpret str[] array as a C string. It interprets it as a buffer of size 256. Text editors do not interpret null character as a terminator, so random characters from str get written to the file.
If you want the string written to the file to end at the last valid character, use strlen(str) for the size in the call of fwrite.

fwrite and printing into an output file program

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.

Resources