C: fread does not read the full block - c

Here's my code so far:
#include <stdio.h>
#include <stdint.h>
#define N_DET 432
#define N_PROJ 500
int readSinogram(uint16_t mess[],char filename[], int sample){
//init
FILE *fp;
int i;
//open file
fp=fopen(filename,"r");
//read sinogram
fseek(fp,sizeof(uint16_t)*N_DET*N_PROJ*sample*2,SEEK_SET); //move pointer
fread(mess,sizeof(uint16_t),N_DET*N_PROJ,fp); //read sinogram
return 0;
};
int main()
{
uint16_t mess[N_DET*N_PROJ];
char filename[]="C:\\Path\\MyFile.fxc";
double curr;
int i,DET,PROJ;
readSinogram(mess,filename,0); //read the data
printf("\nDET?"); //ask for input
scanf("%u", &DET);
printf("\nPROJ?");
scanf("%u", &PROJ);
curr=mess[DET+N_DET*PROJ]; //get the data
printf("Data: %f",curr); //print the data
return 0;
}
This reads in the .fxc file, which is just a binary file containing uint16_t formatted numbers. "readSinogram" reads one data set which contains N_DET*N_PROJ numbers. (The pointer is moved by twice the block size, because there are alternating blocks of two measurements in the file.)
After reading it, one can put in a DET and PROJ and have a look at the data at this point.
So far, everything works fine. The data is correct for a certain data range but when asking for too big DET and/or PROJ the data is incorrect.
I do have the same file read in in Matlab and can confirm that the data in it is fine.
To be more exact: every index above [DET+N_DET*PROJ] > 248835 will return 52428 instead of the correct value (ranging from 0 to 4088). The values up to those work fine. So there's got to be something wrong with the "mess" array above that index, I guess.
What am I doing wrong? Thanks in advance!

you need allocate a larger array to get to index value greater than 248835
currently you have the following defines
#define N_DET 432
#define N_PROJ 500
which leads to the array size of 432*500 = 216000
now if your indexing the array at value 248835 248835 > 216000 you would cause to access the memory out of the allocated memory for the array which would lead to undefined behavior. What you need is a bigger size array which can accommodate more than 248835 entries. a simple #define N_DET 500 would do that, but you have to make sure that is the requirement. A basic index check would be helpful to avoid having a out of range problem something on the lines of
#define MAX_RANGE 500*500
if((DET+N_DET*PROJ) < MAX_RANGE)
curr=mess[DET+N_DET*PROJ]; //get the data
else
//error handling
you also need error handling in fopen fseek and check the return for fread plus optionally you can close the opened file discriptor by close(fd)

Related

How to use more than one dynamic allocation on C programming?

I'm making a program that reads two sets of data (float) from two different .txt files, and then it transfers these data to two different arrays, which will be used in further calculations. However, when I try to use dynamic allocation more than once, something goes wrong and the data seem not to be stored in the array.
The following simplified program seems to be working fine:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
float *VarA;
int n = 0;
int *counter;
int i;
FILE *input1;
input1 = fopen("C:\\Users\\...test.txt","r");
VarA = (float*)calloc(20001, sizeof(float));
for(i = 0; i < 20001; i++)
{
fscanf(input1,"%f",&VarA[i]);
printf("%f\n",VarA[i]);
}
free(VarA);
fclose(input1);
return 0;
}
it successfully shows the data stored in the array VarA. However, if I introduce a new array to count the number of lines in the file (which is necessary for my further calculations), I just get the value 0.000000 from every array element:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
float *VarA;
int n = 0;
int *counter;
int i;
FILE *input1;
input1 = fopen("C:\\Users\\...test.txt","r");
counter = (int*)calloc(100000, sizeof(int));
while(fscanf(input1,"%f",&counter[n]) != EOF)
{
n++;
}
free(counter);
printf("n = %i\n", n);
VarA = (float*)calloc(n, sizeof(float));
for(i = 0; i < n; i++)
{
fscanf(input1,"%f",&VarA[i]);
printf("%f\n",VarA[i]);
}
free(VarA);
fclose(input1);
return 0;
}
I know that I can avoid using another array to count the number of lines. The point is that every time I use another array, for any purpose, I get the same result. For instance, if I don't use an array to count the number of lines, but I make another one to store my other set of data, one of these arrays just won't present the data after the reading. I tried to modify my program several times in order to find the source of such behavior, but without success.
(At least) two major problems: first,
counter = (int*)calloc(100000, sizeof(int));
while(fscanf(input1,"%f",&counter[n]) != EOF) {
n++;
}
free(counter);
is basically saying "Grab me a chunk of memory, fill it with data as I read the file, then throw it away without ever using it." Probably not what you intended. Then,
VarA = (float*)calloc(n, sizeof(float));
for (i = 0; i < n; i++) {
fscanf(input1,"%f",&VarA[n]);
printf("%f\n",VarA[n]);
}
free(VarA);
which says, "Grab a big chunk of memory, then read data from after the end of the file I just read everything from, put it there, then throw it away."
If you want to read the data from the same file again, you'll have to close it an reopen it (or "seek" to the start). And if you want to do anything with it, you'll have to do it before free()ing the memory you loaded it into.
counter = (int*)calloc(100000, sizeof(int));
// ^--- `int*` ^--- `int`
// v--- `int` pointer
while(fscanf(input1,"%f",&counter[n]) != EOF)
// ^--- `float` designator
Do you see any discrepancies here? Your code allocates ints, then passes a pointer to those ints to fscanf telling it they're floats (using the %f designator). According to the C standard draft n1570, section 7.21.6.2p10 this constitutes undefined behaviour:
If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
My suggestion would be to use the * assignment suppression modifier here, for example:
while (fscanf(input1, "%*f") != EOF) n++;
or, alternatively
while (fscanf(input1, "%f", &(float){0}) != 1) n++;
Note also how I've changed the check from EOF to 1. You can find more information about the return values of fscanf here (which you really should read before using any scanf-related function... and stop guessing, because guessing in C can be harmful).
Additionally, you need to rewind your file once it reaches EOF, otherwise every call to fscanf following this loop will return EOF:
rewind(input1);
P.S. Don't cast malloc in C. This goes for calloc and realloc, too. There's a lot of this quoted stuff that has opengroup manuals of its own; I'll leave it as an exercise to you to find (and read) the opengroup manuals.

Storing integers as an array by reading size of array and the elemnts of the array in a single line

I am trying to create an array from the integers that a user inputs. They must be inputted on the same line, e.g. 5 1 2 3 1 6. The number of integers can be any amount.
However, the first number + 1 determines the size of the array. E.g. if the user inputs the number 5 first, it must be followed by 5 other random integers thus making the length of the array 6. I'm getting confused on how to do this because there is so much user input. Thanks in advance!
Here is my code so far, though i don't think it'll be much help:
#include <stdio.h>
int main(void) {
int arr_days[13];
int i = 0;
printf(" ");
while(i < 13) {
scanf("%d", &arr_days[i]);
i = i + 1;
}
printf("%d", arr_days[0]);
return 0;
}
You weren't too far off, you just need to allocate the buffer dynamically and read the first number separately so that you know how much space and how many loops to perform.
You might also want to check if arr_days is NULL after the malloc to protect against 'out of memory' problems.
#include <stdio.h>
int main(void) {
int* arr_days;
int i = 0;
int n;
printf(" ");
// get first number to find out how many more to expect
scanf("%d", &n);
// create memory space to store them
arr_days = malloc(n * sizeof(int));
while(i < n) {
scanf("%d", &arr_days[i]);
i = i + 1;
}
printf("%d", arr_days[0]);
return 0;
}
EDIT: I see from some comments further down that there is some confusion about scanf. This command will trigger an input request if there is no input pending, then it will process any pending input. So when you type in a bunch of numbers in response to a scanf input prompt (or pipe a text file with those numbers in to the program) each invocation of scanf("%d",...) will only extract the next single integer, leaving the rest of the input still available. If you think of it like the string is a file, scanf is reading from that file and leaving the file pointer at the end of the bit it just read ready for the next invocation to read the next bit... (which is exactly what happens if you pipe a text file!)
First you would need to get the number so that you know how many numbers to read and how big to allocate the array.
int num;
scanf("%d", &num);
int *arr = malloc(num * sizeof(int));
Second, read each of the numbers one by one.
int I;
for (I = 0; I < num; I++) {
scanf("%d", &arr[I]);
}
This shows as an example of how to do the task, you will need to take care of check scanf's result to make sure the input was successful, and check malloc for allocation too.
If you want to set the array size based on an input then the input has to be read first. What you want is to input all numbers in a line(including size of the array), which means the numbers will be read after the end of line only(after pressing [Enter]). This case is not possible with static arrays.
You can't read all the inputs i.e. array size & integers to be put in it on the same line & build an static array. But you may build a dynamic array by implementing a dynamic array and taking all inputs in the same line.
A dynamic array is a re-sizable array or array list with random
access, variable-size list data structure that allows elements to be
added or removed.
A static array required the size of the array to be created so
that that memory could be allocated before array elements can be added
to it.
All this being said,
if your array size has an upper-bound size(i.e. the maximum number of elements which you would accept is set) then you may create a static array of the maximum size and read you inputs into it.
int arr[MAX_ARRAY_SIZE ASSUMED];
This allocates an array of size MAX_SIZE_ASSUMED which means all your inputs maybe stored in the static array. But this is a bad way to implement as MAX_SIZE_ASSUMED is always the size of the array even when you may just enter one element into the array.

How do I read in data from an external binary file that needs differing byte lengths per element?

Here's the situation. I have to read in data from an external binary file and display the data in order and so that it makes sense to the user.
The file has data stored as follows: the first 4 bytes are an integer, then the next 8 bytes are a floating decimal, followed by the next 8 bytes (float), etc. So I need to read in 4 bytes initially, then repeatedly 8 bytes after that... until the file has no data left to read.
I have read the file in such a way that it stores its data into an array i[NUM] (where NUM is the number of elements), and each element contains 4 bytes. By doing this, I have accidentally 'split' the floats in half, the first half being stored in i[1] and the second half in i[2], also a float in i[3] and i[4], etc.
Now I am in the process of trying to 'stitch' the two halves of each float back together again in order to display them, but I am stuck.
Any suggestions are greatly appreciated.
My code so far:
#include "stdafx.h"
#include "stdio.h"
#define NUM 15
int main(void)
{
//initialising
int i[NUM], j, k;
float temp[NUM];
char temp_c[NUM];
int element_size = 4;
int element_number = NUM;
for(k=0; k<NUM; k++)
{
i[k] = 0; //clear all cells in i[]
temp[k] = 0; //clear all cells in temp[]
}
//file reading
FILE *fp;
fp = fopen("C:\\data", "rb+");
fread(&i, element_size, element_number, fp); //reads 'data' to the end and then stores each element into array i[]
fclose(fp); //close the file
//arrange and print data here
printf("Data of File\n\nN = %d",i[0]);
//this is where the rest fell apart
//No idea how to go about it
return 0;
}
If you're sure that the float is 8 bytes and the int is 4 then you can do this (probably in a loop with variables instead of the fixed indices I've used):
memcpy(&temp[0], &i[1], 8);
I'm assuming that your code for creating the file was a fwrite where you wrote the 4-byte int, then wrote the 8-byte floats.
Then you can output the floats with printf("%f\n", temp[0]); or whatever.
NB. You can avoid your initialization loop by initializing the arrays directly: int i[NUM] = { 0 }; etc. This only works for 0, not for other values.

Reading pixel data of a PPM file using C

I am trying to read pixel data from a PPM file. I have a function to read the header so I know it's pointing to the beginning of the pixel data. I tried using fgetc(file) but if the value is more than one digit it will not work. I also tried using an array and converting the array to an int or char but I have no way of knowing how many digits each value is. I'm also not sure if the values are separated by whitespace or not. Basically I need a way to extract the pixel data. (I'm using C.)
My code right now is:
char read_byte(FILE *ipt) {
int c, i=0, sum=0;
while (i<16) {
c=fgetc(ipt);
if((i%2)!=0 {
if(c&1) {
sum+=pow(2,i/2);
}
}
i++;
}
return (char)sum;
}
EDIT:
At first I thought the file was stored as the ASCII values, then I realized it's stored as binary. Right now I think I'm making it act like hex. I'm not sure if that's correct. I'm really stuck.
EDIT: changed my code a bit
char read_byte(FILE *ipt) {
int c, i=0, sum=0;
while(i<8) {
c = fgetc(ipt);
c=c&1;
sum+=c*pow(2,i);
i++;
}
return sum;
}
I print the sum as %c
Must you write this for an assignment, or is it for pleasure, or could you use someone else's code?
There is an Open Source solution.
"Netpbm is a package of graphics programs and a programming library. " which includes programs to read PPM at http://netpbm.sourceforge.net/doc/
Edit:
Have you got, or read the definition of the file format, e.g. http://netpbm.sourceforge.net/doc/ppm.html?
It looks like the data is either sequences of one byte RGB triples, or sequences of two byte RGB triples.
The program can detect which format is used from item 7 "The maximum color value (Maxval)". It says "If the Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes."
So you code a function which reads one byte/component RGB data, then code another to read two byte/component RGB data.
The program can choose which to call once it has read the value of Maxval.
Edit {
According to the document at that link, the image data in a 'P6' ppm is binary.
So if MaxValue is <256, and hence the data for each colour component is one byte, then reading three bytes, with three calls of fgetc(fp) would return the binary value of one RGB pixel.
If the program has read the header, it has the values of width and height for the image data. So it could allocate an array for every row (width wide of RGB pixels), and an array of pointers to each allocated pixel row array. Then read the binary data into each row, and the program has something straightforward to operate on; a 2d array.
} end edit
My reading of your question suggests you already know how to read one byte data using fgetc.
Edit - it seems like this is irrelevant:
You can read two byte data by calling fgetc twice, and shifting and bit or-ing the data, e.g. (partly ignoring error checking):
int a = fgetc(fp);
int b = fgetc(fp);
if (a >= 0 && b >= 0) { // then all is okay
unsigned int twobyte = (a<<8) | b; // or (b<<8) | a; depending on byte order
// ...

Error array size

I need to assign a character array containing 300000 data which are fetched from a file Numbers.dat containing 200,0000 numbers arranged in a column format(its a huge data file). The operation is to fetch in data from this file and store it in an array in blocks of 300000 so that these 300000 numbers are again stored in different files.This operation is performed for two files which are therefore subsets of the Numbers are of form
-0.98765
-0.124567
etc
But I am getting TWo errors : First is syntactic error saying the array size is too long and the other is logical error. How to resolve this. The code is as under provided by Gunner in How to read blocks of numbers from a text file in Cbut not working when used for this case
#include <stdio.h>
#include<stdlib.h>
# include <conio.h>
# include <dos.h>
# include <math.h>
void main()
{ FILE *fpt1,*fpt2,*fpt;
fp=fopen("numbers.dat","r");
fpt1=fopen("subset1.dat","w");
fpt2=fopen("subset2.dat","w");
int index=0;
char anum[300000]; //this is the reason for the first syntactic error :Array size too large
// since we are not calculating, we can store numbers as string
while( fscanf(fp,"%s",anum) == 1 )
{
if(index==0)
{
// select proper output file based on index.
fprintf(fpt1,"%s",anum);
index++; }
if(index ==300000)
{
fprintf(fpt2,"%s",anum);
index++; }
}
fclose(fp);
fclose(fpt1);
fclose(fpt2);
}
The logical error is that only one number is being written in file subset1 and subset2 even when I reduce the size to 300 blocks of data.
Your compiler doesn't support static arrays with such a capacity. Use a compiler that allows this(most modern compilers do).
You can also try to allocate the memory dynamically.

Resources