I need to write function which will write elements of array into binary file, and after that find the mean value of elements of binary file.
#include <stdio.h>
double enterArray(){
int i=0,n;
double a[101];
FILE* fp=fopen("niz.bin", "w");
while(1){
scanf("%lf", &a[i]);
if(a[i]==-1)break;
i++;
if(i==100)break;
}
n=i;
for (i=0; i<n; i++)
fwrite(a,4, n, fp);
fclose(fp);
return 0;
}
double meanValue(){
return 1;
}
int main() {
enterArray();
printf("%g\n", meanValue());
return 0;
}
I get some random characters in niz.bin file. Could you help me fix my code?
There are a few problems with the code.
You take an arbitrary number of doubles, and then write the first n * 4 bytes in the array "repeatedly" to the file.
You don't know for sure that sizeof (double) is equal to 4 bytes.
On every iteration, you write (n * 4) bytes from the array a to the file.
What you want is, starting from i * sizeof (double), write sizeof (double) bytes to the file (if you want to use a loop. You could simply just write (n * sizeof (double) bytes to the file at once)
You use the "w" mode in fopen, which is not the "write binary" mode. Use "wb" instead.
Then, in meanValue(), you don't do anything. Writing/reading a 10-element double array to/from a binary file can be done in the following way:
/* write to the file */
double write_arr[10] = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
FILE *fp = fopen("niz.bin", "wb");
fwrite(&write_arr, sizeof(double), 10, fp);
fclose(fp);
/* read from the file */
fp = fopen("niz.bin", "rb");
double read_arr[10];
fread(&read_arr, sizeof (double), 10, fp);
Also, note that you must identify how many elements you're going to write to the file, as you write the bytes in the file without knowing how many to write in advance. As you don't write the elements immediately, you could serialize the number of elements in the first 4 bytes in the file. And when you read from it, read the first 4 bytes to know how many doubles lying ahead.
Related
I used to print data from a C code in a text file as,
fp = fopen("MD.txt", "a+");
//saving iteratively
fprintf(fp,"%f %f %f \n", x, y, z);
This way the data saved in the text file becomes huge (in several GBs) as I am saving positions from a molecular dynamics code at each time step. I wanted to know If there is any other file format which can save the same amount of data but in a smaller file.
You can save this data as binary data, it will not be human readable but it should take less space. For typical architecture each float should take only 4 bytes.
Code example:
fp = fopen("data.bin", "wb");
if(fp == NULL)
{
printf("Error opening file\n");
exit(1);
}
for (...) {
float x, y, z;
fwrite( &x, 1, sizeof(x), fp );
fwrite( &y, 1, sizeof(y), fp ) ;
fwrite( &z, 1, sizeof(z), fp ) ;
}
Read can be done using http://www.cplusplus.com/reference/cstdio/fread/
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
This way you will get rid of spaces, new line sign and each float will take less space. For example float 132.002 takes 7 bytes and binary form will always take 4 bytes.
Only downside is that there are no delimiters between each float so read function has to assume how data was written to file.
Why not save the values as binary? (Also more accurate)
i.e to write fwite:
float x = 123.45;
fwrite(&x, sizeof(float), 1, fh) // and check the return value
To read fread
fread(&x, sizeof(float), 1, fh) // and check the return value
This should save a lot of space
I have a file in csv format look like this:
0.0060862,0.31869
0.025889,0.21183
0.064364,0.094135
0.10712,-0.0081176
0.15062,-0.073904
I would like to load the first column to array a and second column to array b. This is what the code looks like:
double a[5];
double b[5];
int i=0;
FILE* fileHandle = NULL;
fopen_s(&fileHandle, fileName.csv, "r+");
for(i=0;i<5;i++)
{
fscanf_s(fileHandle,"%lf,%lf",a[i],b[i]);
}
fclose(fileHandle);
Now I am converting the csv file to a binary file; the data is represented in 2's complement in unsigned int. How should I change my code?
I changed the code to
unsigned x[5];
unsigned y[5];
double a[5];
double b[5];
int i=0;
FILE* fileHandle = NULL;
fopen_s(&fileHandle, fileName.csv, "rb+");
for(i=0;i<5;i++)
{
fscanf_s(fileHandle,"%u,%u",x[i],y[i]);
a[i] = x[i]/(2^15);
b[i] = y[i]/(2^15);
}
fclose(fileHandle);
But x[i] and y[i] read from the binary is always 3435973836. How should I change my code to make it work?
When your data is binary, you don't need to convert it with fprintf and fscanf.
You can just read and write you array with fread and fwrite.
If your data alternates a and b records, you will better organize your variables the same way :
struct ab {
int a, b;
} ab[5];
and read it all in one shot with
fread(ab, sizeof (int), 10, fileHandle);
Then process it the way you like.
(see man fread, and man fwrite for details)
I need to be able to make sure my array is correctly receiving values from the file card.raw through fread.
I am not confident about using arrays with pointers, so if anybody could help me with the theory here, it would be GREATLY appreciate it. Thanks in advance.
The code is supposed to take literally one block of size 512 bytes and stick it into the array. Then I am just using a debugger and printf to examine the arrays output.
/**
* recover.c
*
* Computer Science 50
* Problem Set 4
*
* Recovers JPEGs from a forensic image.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char* argv[])
{
//Size of EACH FAT JPEG in bytes
#define FILESIZE 512
unsigned char* buffer[FILESIZE];
///Step 1: Open jpeg
FILE* readfrom = fopen("card.raw", "rb");
if (readfrom == NULL)
{
printf("Could not open");
}
///Step 2: Find Beginning of JPEG. The first digits will be 255216255 Then 224 or 225
fread(&buffer, FILESIZE, 1, readfrom);
for(int x = 0; x < FILESIZE; x++)
{
printf("%d = %c\n", x, buffer[x]);
}
fclose(readfrom);
}
Use return values from input functions. fread() reports how many elements were read - code might not have read 512. Swap FILESIZE, 1 to detect the number of characters/bytes read.
// fread(&buffer, FILESIZE, 1, readfrom);
size_t count = fread(&buffer, 1, FILESIZE, readfrom);
Only print out up to the number of elements read. Recommend hexadecimal (and maybe decimal) output rather than character.
for(size_t x = 0; x < count; x++) {
// printf("%d = %c\n", x, buffer[x]);
printf("%3zu = %02X % 3u\n", x, buffer[x], buffer[x]);
}
If the fopen() failed, best to not continue with for() and fclose().
if (readfrom == NULL) {
printf("Could not open");
return -1;
}
The second parameter is size, in bytes, of each element to be read.
The third parameter is Number of elements each one with a size of the <second parameter> bytes.
So, swap your second and first parameters.
Replace unsigned char* buffer[FILESIZE]; with unsigned char buffer[FILESIZE];. For now, you have an array of unsigned char *, when you need unsigned char. Because buffer is already a pointer, you don't need to take its address. In fread call, replace &buffer with buffer.
It must go like this: fread(buffer, 1, FILESIZE, readfrom);
One more thing: add return with a specific error code after printf("Could not open");, because if file hasn't been open, you cannot read from it, can you? And add return 0; in the end of main.
And take your #define out of main.
Read more about fread here: http://www.cplusplus.com/reference/cstdio/fread/
I have been trying to make this program to convert a tga image for color into black and white. But i have no clue how to go about it. I am verry new to C and have yet to get the hang of the syntax and even proper usage of ubuntu.
I think my problem is somthing with tha tga files header cant be read. Because the result i get when trying this program on a tga file is an unopenable picture with no height. "height = 0".
Is there some good links for one to read up on C?
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct pixel {
uint8_t r, g, b, a;
};
static uint8_t *load_image(char *filename, int *sizex, int *sizey)
{
uint8_t *image;
char buf[512];
char *bufptr;
int ret;
FILE *fp = fopen(filename, "r");
bufptr = fgets(buf, 512, fp);
ret = fscanf(fp, "%d %d\n", sizex, sizey);
bufptr = fgets(buf, 512, fp);
image = malloc(*sizex * *sizey * 4);
int i;
uint8_t *ptr = image;
for (i=0; i<*sizex * *sizey; ++i) {
ret = fread(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);
return image;
}
static int save_image(const char *filename, uint8_t *image, int sizex, int sizey)
{
FILE *fp = fopen(filename, "w");
fprintf(fp, "P6\n%d %d\n255\n", sizex, sizey);
int i;
uint8_t *ptr = image;
for (i=0; i<sizex * sizey; ++i) {
fwrite(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);
return 1;
}
void convert_grayscale(uint8_t *input, uint8_t *output, int sizex, int sizey)
{
// Y = 0.299 * R + 0.587 * G + 0.114 * B
int i;
for (i = 0; i < sizex * sizey; ++i)
{
struct pixel *pin = (struct pixel*) &input[i*4];
struct pixel *pout = (struct pixel*) &output[i*4];
float luma = 0.299 * pin->r + 0.587 * pin->g + 0.114 * pin->b;
if (luma > 255)
luma = 255;
uint8_t intluma = (int) luma;
pout->r = intluma;
pout->g = intluma;
pout->b = intluma;
pout->a = 255;
}
}
int main()
{
uint8_t *inputimg, *outputimg;
int sizex, sizey;
inputimg = load_image("image.tga", &sizex, &sizey);
outputimg = malloc(sizex * sizey * 4);
convert_grayscale(inputimg, outputimg, sizex, sizey);
save_image("output.tga", outputimg, sizex, sizey);
}
(Personal note: A longer answer after reading Why Stackoverflow sucks. That should be Required Reading for everyone who gets Moderator privileges.)
The problem is your load_image code seems designed to read PPM (ASCII-based) images:
Each PPM image consists of the following:
1. A "magic number" for identifying the file type. A ppm image's magic number is the two characters "P6".
2. Whitespace (blanks, TABs, CRs, LFs).
3. A width, formatted as ASCII characters in decimal.
4. Whitespace.
5. A height, again in ASCII decimal.
6. Whitespace.
7. The maximum color value (Maxval), again in ASCII decimal. Must be less than 65536 and more than zero.
8. A single whitespace character (usually a newline).
9. A raster of Height rows [...]
-- your first fgets reads, then discards, the "magic number" line, followed by reading the width and height, and then discarding the "maxval" line.
It ought to work for PPM images (and you could rename this routine load_ppm_image) were it not for a single important issue: after all that ASCII stuff, you switch to fread, and so here is Warning #1.
Before opening your file, decide whether you are going to read exclusively ASCII text, or might need to read binary data.
The problem is that 'text mode' "w" converts certain characters when reading and writing into others. That's built-in behavior in all common C libraries; it attempts to fix the end-of-line characters mess that a previous generation of programmers left us with. Now, reading text files in text mode got a bit simpler, but reading binary data is impossible. You can't be sure you got exactly what was in the file.
Let's get on with Warning #2: not all file formats are the same.
The above routine works (mostly) for PPM images, but it will fail on TGA because its header is organized differently. The TGA header is described rather well here (a random pick of Google results).
The specification describes bytes, so first thing to do is change your fopen line to
FILE *fp = fopen(filename, "rb");
and, by the way, a good practice is to test if it was successful:
if (fp == NULL)
{
printf ("Opening the file '%s' failed\n", filename);
return NULL;
}
Then you can use fgetc or fread to read one or more bytes. Here comes Warning #3: use fread with care.
fread reads multiple bytes in the order in which they are stored into the file, and so you would think it may read an item such as width and height -- each a 2-byte integer value -- in one 'read' operation. But fread does not know the order of the bytes in your system (nor in the file itself), and so it could be it reads "lo-hi", as in the specification I pointed to, while in your computer the order of bytes in an integer is "hi-lo". To clarify: if the file contains this
80 00
and you read, then store, this with fread (&width,1,2, fp), these 2 bytes get stored into computer memory in that same order. The bytes are in Big-Endian order; the "large" byte is at the end. But if your computer happens to be a Little-Endian order system, you would not get the value 0x0080 = 128 but 0x8000 = 32768 instead!
The way to circumvent this is to read one byte at a time:
width = fgetc(fp) + (fgetc(fp)<<8);
will always read the data in the correct order: low first, then high. Only the sum gets stored (in the order for your system, but that's now irrelevant!).
With the above, I think I'm out of warnings. Using the TGA specifications as a guide, you can now open the file, read the header one byte at a time until you have all information that's needed, and continue to fread your raw image data into memory. You can safely use fread to read your image bytes three at a time because they will appear in the same order into memory as they were read (they are not integers or larger, so the "memory order" is not an issue).
A good approach to ensure you are reading the correct information is this:
Read one byte at a time, to prevent endianness issues.
Add a comment in your code detailing what it is
Print out the value
Check with the specifications if the value is allowed.
To get you started, after the fopen line (and the required check if it worked):
int idLength = fgetc(fp); /* length of id string after header */
printf ("id length: %u bytes\n", idLength);
int colorMapType = fgetc(fp); /* 0 = RGB */
printf ("color map type: %u\n", colorMapType);
if (colorMapType != 0)
{
printf ("unexpected color map type!\n");
return NULL;
}
int imageType = fgetc(fp); /* 0 = None, 1 = Indexed, 2 = RGB, 3 = Greyscale */
.. and so on. When the entire header has been read and you didn't encounter surprises, you are ready to set up things to read the actual image data. No changes needed there, your existing code should work just fine.
Post-edit: I see I used
int colorMapType = fgetc(fp);
where the 'color map type' is in fact a byte, not an integer. That is to allow a belt-and-suspenders approach. If you encounter the end of the file while you are reading the header, the code that fgetc returns is EOF. EOF cannot be stored into a char, because it is an integer value: 0xFFFFFFFF (more accurately: (int)-1). If you store it into a char, you cannot distinguish it from the perfectly okay value 0x000000FF (the value 255).
The belt-and-suspender approach is to check each and every single byte:
if (colorMapType == EOF)
{
printf ("encountered unexpected end of file!\n");
return NULL;
}
Overkill if you are working with a known file, and you know it's a valid TGA (you can view and edit it with bitmap editors), but if you ever plan to work on files of which you don't know if they are valid, you might need this.
I want to write data into the file in binary form.
I was trying using the mentioned below
FILE *fp = fopen("binaryoutput.rgb888", "ab+");
for(int m=0; m<height; m++)
{
for (int n=0; n< width; n++)
{
temp = (pOutputImg+m*3+n*3); // here pOutputImg & temp is a pointer to a unsigned char
fprintf(fp,"%u",*temp);
}
}
fclose(fp);
I am able to get data which is strored at pOutputImg but not in binary form.
Can anyone guide me the correct step..
Thanks in advance
Replace fprintf() with fwrite().
Ex:
fwrite(temp, sizeof(*temp), 1, fp);
The whole purpose of fprintf() is to format binary data as readable ascii ... the exact opposite of what you want. fwrite() is for directly writing binary data.
If this is a pixmap of rgb triplets, you can write the binary data with one line:
fwrite(pOutputImg, 3, height * width, fp);