I am generating 500 random points (each point is of dimension=4) and writing them into a binary file as the following:
FILE *fp = fopen("file.bin", "wb+");
float *buf = (float *) calloc(500 * 4, sizeof(float));
srand(1);
for (i = 0; i < (500 * 4); ++i) {
buf[i] = (float) rand() / (float) RAND_MAX; // Later I shall treat every 4 values as one point.
}
fwrite(buf, sizeof(float), 500 * 4 * sizeof(float), fp);
fclose(fp);
Later in my code, I want to read only the first 100 points (i.e., 100*4 as each point is of dim=4). I use the following code to do so but I am having a problem and it does not really print anything:
FILE *fp = fopen("file.bin", "rb+");
fseek(fp, 0, SEEK_SET);
int c, cnt=0;
while(1)
{
c = fgetc(fp);
if(feof(fp) || (cnt == 100)) { break; }
printf("%c", c);
cnt++;
}
printf("\n");
fclose(fp);
If you want to read back just 100 elements (as in 4 floats), that's the number you put into fread like so...
fread(buf, sizeof(float), 100 * 4, fp);
as per the various comments above your call to fwrite should look similar as you don't need the extra sizeof(float)
fwrite(buf, sizeof(float), 500 * 4, fp);
Related
I want to print the position of every array in a binary file. The structure of the array is: n, then n numbers (all long, n too).
This is the code:
int main() {
FILE \*f = fopen("a.bin", "rb");
while(!feof(f)) {
printf("-(%d)\\n", ftell(f));
long n; fread(&n, 1, sizeof(long), f);
fseek(f, n \* sizeof(long), SEEK_CUR);
}
}
My idea was to read until the end of the file, but it loops infinitely.
I am applying a basic tutorial on image processing in C and I am having problems with this program to convert RGB into grayscale but the output pic is somehow corrupted and although the code runs with no errors, and I cant put my hands on the problem. The code is below.
FILE *fIn = fopen("tiger.bmp","rb"); //Input File name
FILE *fOut = fopen("tiger_gray.bmp","wb"); //Output File name
int i,j,y;
unsigned char byte[54];
if(fIn==NULL)
{
printf("File does not exist.\n");
}
for(i=0;i<54;i++) //read the 54 byte header from fIn
{
byte[i] = getc(fIn);
}
fwrite(byte,sizeof(unsigned char),54,fOut); //write the header back
// extract image height, width and bit Depth from image Header
int height = *(int*)&byte[18];
int width = *(int*)&byte[22];
int bitDepth = *(int*)&byte[28];
printf("width: %d\n",width);
printf("height: %d\n",height );
int size = height*width;
unsigned char buffer[size][3]; //to store the image data
for(i=0;i<size;i++) //RGB to gray
{
y=0;
buffer[i][2]=getc(fIn); //blue
buffer[i][1]=getc(fIn); //green
buffer[i][0]=getc(fIn); //red
y=(buffer[i][0]*0.3) + (buffer[i][1]*0.59) + (buffer[i][2]*0.11); //conversion formula of rgb to gray
putc(y,fOut);
putc(y,fOut);
putc(y,fOut);
}
fclose(fOut);
fclose(fIn);
There were two major problems in your code.
You had the width and height reversed.
You were not accounting for
the required padding at the end of every row to make it a multiple
of 4 bytes.
You were also allocating a large buffer that you did not need based on how the rest of the code was written. Generally I'd prefer to read/process either one full row at a time or even the full image at once, but to do that you want to use malloc or calloc because the data may be larger than the available stack. In this case, to keep things simple, I just process one pixel at a time.
I also got rid of getc/putc because I prefer fread/fwrite and you're never really dealing with 1 byte at a time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fIn = fopen("tiger.bmp", "rb");
FILE *fOut = fopen("tiger_gray.bmp", "wb");
if (!fIn || !fOut)
{
printf("File error.\n");
return 0;
}
unsigned char header[54];
fread(header, sizeof(unsigned char), 54, fIn);
fwrite(header, sizeof(unsigned char), 54, fOut);
int width = *(int*)&header[18];
int height = abs(*(int*)&header[22]);
int stride = (width * 3 + 3) & ~3;
int padding = stride - width * 3;
printf("width: %d (%d)\n", width, width * 3);
printf("height: %d\n", height);
printf("stride: %d\n", stride);
printf("padding: %d\n", padding);
unsigned char pixel[3];
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
fread(pixel, 3, 1, fIn);
unsigned char gray = pixel[0] * 0.3 + pixel[1] * 0.58 + pixel[2] * 0.11;
memset(pixel, gray, sizeof(pixel));
fwrite(&pixel, 3, 1, fOut);
}
fread(pixel, padding, 1, fIn);
fwrite(pixel, padding, 1, fOut);
}
fclose(fOut);
fclose(fIn);
return 0;
}
basically my problem is that when I use the following program:
#include <stdlib.h>
#include <stdio.h>
#define SIZE 1000
int main() {
FILE *fp;
int r, i;
char fp_string[600] = "/Users/mac/Library/Mobile Documents/com~apple~CloudDocs/College/Program With Persistent Data/Lab 3/num1000.bin";
fp = fopen(fp_string, "rb+");
r = 11;
fseek(fp, 3 * sizeof(int), SEEK_SET);
fwrite(&r, sizeof(int), 1, fp);
fseek(fp, 10 * sizeof(int), SEEK_SET);
fwrite(&r, sizeof(int), 1, fp);
fclose(fp);
return 0;
}
It updates the binary file (which is 1000 integers) with the 3rd and 10th digits to be 11.
But when I do the following:
#include <stdlib.h>
#include <stdio.h>
#define SIZE 1000
int main() {
FILE *fp;
int r, i;
char fp_string[600] = "/Users/mac/Library/Mobile Documents/com~apple~CloudDocs/College/Program With Persistent Data/Lab 3/num1000.bin";
fp = fopen(fp_string, "rb+");
r = 11;
printf("\n\n Before making any changes:\n");
for (i = 0; i < SIZE; i++) {
fseek(fp, i * sizeof(int), SEEK_SET);
fread(&r, sizeof(int), 1, fp);
printf("%d ", r);
}
fseek(fp, 3 * sizeof(int), SEEK_SET);
fwrite(&r, sizeof(int), 1, fp);
fseek(fp, 10 * sizeof(int), SEEK_SET);
fwrite(&r, sizeof(int), 1, fp);
printf("\n\n After making changes:\n");
fseek(fp, 0, SEEK_SET);
for (i = 0; i < SIZE; i++) {
fread(&r, sizeof(int), 1, fp);
printf("%d ", r);
}
fclose(fp);
return 0;
}
It doesn't change anything at all. Just in case you where wondering, to check if the first program worked what I did is:
I would run the program you have underneath this text to check the integers stored in the binary file.
I would run the program you have on top of this text (the second one I posted) to change the 3rd and 10th integer to 11.
I would run the program you have underneath to check that those integers were changed to 11.
That way it worked, but the first program doesn't seem to change anything, it shows the exact same numbers again.
#include <stdlib.h>
#include <stdio.h>
#define SIZE 1000
int main() {
FILE *fp;
int r, i;
char fp_string[600] = "/Users/mac/Library/Mobile Documents/com~apple~CloudDocs/College/Program With Persistent Data/Lab 3/num1000.bin";
fp = fopen(fp_string, "rb");
for (i=0;i<SIZE;i++) {
fread(&r, sizeof(int), 1, fp);
printf("%d ", r);
}
fclose(fp);
return 0;
}
The first for loop is reading every number in the file into rbefore printing them. At the end of the loop, r contains the last number in the file, and that gets written into the places where you seek.
Either use a different variable in the loop, or put the r = 11; assignment after the loop.
void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *file)
I want to read in two matrices from an external file that reads like this:
3
2
4
1 2
3 4
5 6
7 8 9 10
11 12 13 14
Where the first line is the number is the number of rows for Matrix A, number 2 is the number of columns for Matrix A and number of rows for Matrix B, and the third number is the number of columns for matrix B. I've tried this to get the m, n, and p but get a seg fault
FILE * fp = fopen(file, "r");
char a, b, d;
char c = getc(fp);
int i = 0;
while (c != EOF) {
if (i == 0) {
a = c;
i++;
}
else if (i == 1) {
b = c;
i++;
}
else if (i == 2) {
d = c;
i++;
}
else
break;
}
fclose(fp);
It is obvious you need a bit of help. Here is an example that is only 1 way of many to do this. Note: instead of complicating the example reading a variable number of elements in B, it is simply coded to read 4 elements as they exist in the data file. Also, fscanf is used to read from the file since you have a variable number and differing data to read in each line. This simplifies the code compared to reading the file character by character since the type of information read is int. Read through the example (comments inline) and let me know if you have questions:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv) {
int *A, *B, *C, m, n, p; /* note *C is unused */
char *file;
/* test for required filename */
if (argc < 2) {
fprintf (stderr, "\n Error: insufficient input. usage: %s filename\n\n", argv[0]);
return 1;
}
/* assign filename, open file, validate opening */
file = argv[1]; /* you don't need 'file', you can simply use argv[1] */
FILE *fp = fopen (file, "r");
if (!fp) {
fprintf (stderr, "\n Error: file open failed for file '%s'\n\n", argv[0]);
return 1;
}
/* read & output m, n, p */
fscanf (fp, "%d\n%d\n%d\n", &m, &n, &p);
printf ("\n m: %d\n n: %d\n p: %d\n\n", m, n, p);
/* allocate memory for A and set values to null */
A = calloc (m * 2, sizeof(int));
/* read A */
int i = 0;
for (i = 0; i < m; i++)
fscanf (fp, "%d %d\n", &A [i*2], &A[i*2 + 1]);
/* output A */
printf ("Array A\n");
for (i = 0; i < m; i++)
printf (" [ %d %d ]\n", A [i*2], A[i*2 + 1]);
/* allocate memory for B and set values null */
B = calloc (n * p, sizeof(int));
/* read B */
for (i = 0; i < n; i++)
fscanf (fp, "%d %d %d %d\n", &B [i*p], &B[i*p + 1], &B[i*p + 2], &B[i*p + 3]);
/* output B */
printf ("\nArray B\n");
for (i = 0; i < n; i++)
printf (" [ %2d %2d %2d %2d ]\n", B [i*p], B[i*p + 1], B[i*p + 2], B[i*p + 3]);
printf ("\n");
/* close FP & free allocated memory */
fclose (fp);
if (A) free (A);
if (B) free (B);
return 0;
}
output:
$ ./bin/rmf dat/array.dat
m: 3
n: 2
p: 4
Array A
[ 1 2 ]
[ 3 4 ]
[ 5 6 ]
Array B
[ 7 8 9 10 ]
[ 11 12 13 14 ]
for the bit of code you provided,
which fails to set the m, n, p variables
and fails to read/set the contents of the matrices A, B
and fails to read/set the contents of matrix C.
It is also very dangerous to pass parameters pointing to predefined matrix sizes
as there is no guarantee that the size values read from the file
will fit into the pre-allocated areas.
Much better to only pass a pointer to each matrix pointer,
then malloc the matrix sizing after the actual values are read
and set the passed matrix pointer A,B,C to point to the malloc'd areas
and read the matrix data into the malloc'd areas.
void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *file)
{
FILE * fp = fopen(file, "r");
if( NULL == fp ) // then handle fopen() error
else
{
int aRows = getc(fp);
int aCols = getc(fp);
int bRows = aCols;
int bCols = getc(fp);
// need to add code to read the A, B matrix contents
// need to add code to read the C matrix contents
// need to add code to set m,n,p
fclose(fp);
}
}
The way being suppose the data is
123 134 2312 32131 2131231 211212
It should take them as different numbers and store them in an integer array .
You can use fscanf with %d format specifier to read successive integer values from a text file.
int i = 0, cap = 10;
int *a = malloc(cap * sizeof(int));
int n;
while (scanf("%d", &n))
{
if (i == cap)
a = realloc(a, (cap *= 2) * sizeof(int));
a[i++] = n;
}