fread failing C program - c

double buf[1000];
double value;
double *ptr = &value;
for(i=0; i < no_of_iterations; i++) {
for(j=0; j < chunkSize; j++) {
num_bytes_read = fread(ptr,1,pcm_sample_size,fptr); //read one sample
if(num_bytes_read == 2) {
sum_sq += (*ptr) * (*ptr); //calculate power of each sample
buf[j] = *ptr;
}
else {
flag = 0;
break;
}
}
if(!flag) {
printf("exiting loop");
break;
}
power = sum_sq/chunkSize;//calculate rms value of signals for chunkSize samples
if(power < threshold) //compare with some value
printf("power is lower than threshold"); //silence-don't write
else { //write
ret = fwrite(buf,1,pcm_sample_size,optr);
if(ret != 1)
printf("error in fwrite %d", ret);
}
}
printf("done");
fclose(fptr);
fclose(optr);
Above is my code for writing some pcm samples to a file depending on some condition but I'm getting fread error.
The control does not enter the if(num_bytes_read==2) block. I think the error is because I want to read pcm samples which are 2 bytes in size and I need somewhere to store it. What datatype can I use to store a 2 byte pcm value(the pcm value is not an int value).
Please advise.

On this line:
num_bytes_read = fread(ptr,1,pcm_sample_size,fptr);//read one sample
ptr is pointing to the address of value so it must be sizeof(double) and 1, as you read in just one value.
The result of an fread is the number of items read, not the number of bytes.
Are you initialising sum_sq where you need to?
To read 2 doubles:
double readbuf[2];
num_items_read = fread( readbuf, sizeof(double), 2, fptr );
if( num_items_read == 2 )
{
covariance_sum += readbuf[0] * readbuf[1];
}
Not sure exactly what you are trying to multiply, but obviously if it is 2 different values it is not a "square". I will let you fix your code to your actual logic.

Related

Access Binary form of Text saved in memory using an Array

The storage representation of the string or equivalently text from a file, is the ASCII code for each character of the string or text from a file, I have been told that I/O functions like fread and fgets will read a string from disk into memory without conversion. The C compiler always works with the storage representation, so when we "retrieve" a string in C, it's always in binary form.
I need to access this binary form to use in my code (without saving this as a binary file, also not asking to print in binary format).
For example, the text string "AA" is saved in memory as "0100000101000001", I need to access directly, without any conversion (like we do when we print, integer using %s, %d) this binary form "0100000101000001" of "AA" using an integer array, say, D[16] which has elements 0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1. So if I use an index int i, I will get 0 from D[4] for i=0.
Array-index operations like buffer[i] (for example, in the sample code in the below) will extract one character from a string:
FILE *fp = fopen("a.txt", "r");
if (fp == NULL)
return 1;
char buffer[100];
int r = fread(buf, 1, sizeof(buffer), fp);
if (r <= 0)
return 1;
printf("As string: %.*s", r, buffer);
printf("As integers:");
for (i = 0; i < r; i++)
printf(" %d", buffer[i]);
But I would like to have the complete text as an array of 0 and 1, whereas here, buffer[i] contains 8 bits which I cannot access individually each bit, how can I do that?
I have been told that I/O functions like fread and fgets will read a string from disk into memory without conversion.
This is true if the file has been open as binary, ie: with "rb". Such streams do not undergo any translation when read into memory, and all stream functions will read the contents as it is stored on disk, getc() included. If your system is unix based, there is no difference with "r", but on legacy systems, there can be substantial differences: text mode, which is the default, may imply end of line conversion, code page translation, end of file mitigation... If you want the actual file contents, always use binary mode ("rb").
You should also avoid the char type when dealing with binary representation, because char is signed by default on many architectures, hence inappropriate for byte values which are usually considered positive. Use unsigned char to prevent this issue.(*)
The most common way to display binary contents is using hexadecimal representation, where each byte is output as exactly 2 hex digits.
If you want to output binary representation, there is no standard printf conversion to output base-2 numbers, but you can write a loop to convert the byte to its bit values.
(*) among other historical issues such as non two's complement signed value representations
Here is a modified version:
#include <stdio.h>
int main() {
FILE *fp = fopen("a.txt", "r");
if (fp == NULL) {
perror("a.txt");
return 1;
}
unsigned char buffer[100];
unsigned char bits[100 * 8];
int r = fread(buffer, 1, sizeof(buffer), fp);
if (r <= 0) {
fprintf(stderr, "empty file\n");
fclose(fp);
return 1;
}
printf("As a string: %.*s\n\n", r, (char *)buffer);
int pos;
pos = printf("As 8-bit integers:");
for (int i = 0; i < r; i++) {
if (pos > 72) {
printf("\n");
pos = 0;
}
pos += printf(" %d", buffer[i]);
}
printf("\n\n");
pos = printf("As hex bytes:");
for (int i = 0; i < r; i++) {
if (pos > 72) {
printf("\n");
pos = 0;
}
pos += printf(" %02X", buffer[i]);
}
printf("\n\n");
pos = printf("Converting to a bit array:");
for (int i = 0; i < r; i++) {
for (int j = 8; j-- > 0;) {
bits[i * 8 + 7 - j] = (buffer[i] >> j) & 1;
}
}
/* output the bit array */
for (int i = 0; i < r * 8; i++) {
if (pos > 72) {
printf("\n ");
pos = 4;
}
pos += printf("%d", bits[i]);
}
printf("\n");
fclose(fp);
return 0;
}
Use bit masking to check the value of individual bits. Checkout a brief description here https://www.learn-c.org/en/Bitmasks
Then you can write the result to your array for the corresponding bit.

Reading multiple files with different number of lines

I am trying to read arrays from multiple files, and the array size in each file is different. So what I do is, I try to count the number of lines in the file and then store that as the array size.
For example, I have two .txt files, File_1.txt and File_2.txt which contain the following data:
0.000 300.00
0.054 2623.3
1.000 300.00
0.000 300.00
0.054 2623.3
0.500 1500.0
1.000 300.00
respectively.
Here is the code that I use:
int main()
{
char filter[1024];
char filename[60];
FILE *fp;
double *T_SR, Z_SR;
for (int i = 1; i < 3; i++)
{
sprintf(filename, "File_%d.txt", i);
fp = fopen(filename, "r");
if (fp == NULL)
{
exit(1);
}
int count = 0;
for (int j = getc(fp); j != EOF; j = getc(fp))
{
if (j == '\n')
{
count = count + 1;
}
}
T_SR = (double *)malloc(count * sizeof(double));
Z_SR = (double *)malloc(count * sizeof(double));
for (int rows = 0; rows < count; rows++)
{
fscanf(fp, "%lf %lf", &Z_SR[rows], &T_SR[rows]);
printf("%lf %lf\n", Z_SR[rows], T_SR[rows]);
if (feof(fp))
{
break;
}
}
}
}
But instead of printing the given array as output, it prints this:
0.0000 0.0000
0.0000 0.0000
I checked the value of count, it's good. Maybe the problem is simple, but I am not able to find it. Can someone please help?
After you ran the whole file with getc the file indicator will be at the end of the file you must set it back to the beginning before you use fscanf, you can use rewind for that.
rewind(fp); //<--
for (int rows = 0; rows < count; rows++)
{
//...
}
Aside from that, other problems exist as Jaberwocky pointed out, among others, like a memory leak issue, and the fact that you don't close your files or check malloc return, here's how your code could look like (with comments):
double *T_SR, *Z_SR; // fix the pointer issue
//...
char line[1024]; // make sure it's larger than the largest line in the file
while (fgets(line, sizeof line, fp)) // fixes the count issue
{
// doesn't count empty lines, if there are any
if (line[0] != '\n')
{
count++;
}
}
if(count > 0)
{
T_SR = malloc(count * sizeof *T_SR);
Z_SR = malloc(count * sizeof *Z_SR);
if(T_SR == NULL || Z_SR == NULL) // check memory allocation
{
perror("malloc");
return EXIT_FAILURE;
}
rewind(fp);
for(int rows = 0; fscanf(fp, "%lf%lf", &Z_SR[rows], &T_SR[rows]) == 2; rows++)
{
printf("%lf %lf\n", Z_SR[rows], T_SR[rows]);
}
free(T_SR); // free the memory, avoids memory leaks
free(Z_SR);
}
fclose(fp); // and close the file
//...
Live demo
There are several bugs:
The most important one is the rewind issue that has been addressed in anastaciu's anwer.
double * T_SR, Z_SR is wrong, it should be double * T_SR, *Z_SR. I wonder actually if the code you posted is the code you compile.
your line counting method is flawed. If the last line of the file does not end with a \n, the count variable will be 2 and you'll miss the last line.
fscanf returns the number of items read or EOF. If you had check that, you might have found the problem in your code yourself.
the feof check is done too late, if fscanf encounters en EOF you still print the values that have not bee read due to the EOF condition.
I try to count the number of lines in the file and then store that as the array size.
Aside from the key rewind() issue, avoid reading code one way to find line count and another to find the doubles. Far too easy to get a line count that does not match the "line count" of reading two doubles.
Use one approach to find both.
size_t read_SR(size_t count, double *Z_SR, double *T_SR, FILE *inf) {
char line[100];
rewind(inf);
size_t rows;
while (fgets(line, sizeof line, inf)) {
double Z, T;
if (sscanf(line, "%lf %lf", &Z, &T) != 2) return rows;
if (rows < count) {
if (Z_SR) Z_SR[rows] = Z;
if (T_SR) T_SR[rows] = T;
}
rows++;
}
return rows;
}
Usage
// First pass, find size
size_t count = read_SR(0, NULL, NULL, inf);
double *T_SR = malloc(sizeof *T_SR * count);
double *Z_SR = malloc(sizeof *Z_SR * count);
// 2nd pass, save data
read_SR(count, Z_SR, T_SR, inf);

Array dynamically allocated by file size is too large

I am working on a class assignment and need some help with dynamically allocated arrays. I am using file_size to try to pull the file size from 3 files to allocate the array to that size, then I need to write and sort the data in the array. My issue right now is with sizing of the array; right now my output (ignoring sorting) is:
1
3
7
9
0
0
0
0
2
4
8
0
0
0
5
6
10
0
0
0
0
0
0
As you can see it is being padded with extra 0s. Here are the input files:
inputFile1:
1
3
7
9
inputFile2:
2
4
8
inputFile3:
5
6
10
0
I need some help figuring out what's going on with this and where the issue is. I want to get rid of those extra 0s, and I'm not even sure where they are coming from. Help with the sorting would also be appreciated.
file_size:
long file_size(FILE *inputFile)
{
if(inputFile == NULL)
return -1;
long pos = ftell(inputFile);
fseek(inputFile, 0, SEEK_END);
long size = ftell(inputFile);
fseek(inputFile, pos, SEEK_SET);
return size;
}
Main:
int main(void)
{
FILE *file0 = fopen("list0.txt", "r");
FILE *file1 = fopen("list1.txt", "r");
FILE *file2 = fopen("list2.txt", "r");
FILE *output = fopen("hw3.out", "w");
long size0 = file_size(file0);
long size1 = file_size(file1);
long size2 = file_size(file2);
long totalSize = size0 + size1 + size2;
int *numbers = malloc(totalSize * sizeof(int));
int i;
int index = 0;
for(i = 0; i < file_size(file0); i++)
{
if(!feof(file0))
{
fscanf(file0, "%i", &numbers[index]);
index++;
}
else
break;
}
for(i = 0; i < file_size(file1); i++)
{
if(!feof(file1))
{
fscanf(file1, "%i", &numbers[index]);
index++;
}
else
break;
}
for(i = 0; i < file_size(file2); i++)
{
if(!feof(file2))
{
fscanf(file2, "%i", &numbers[index]);
index++;
}
else
break;
}
for(i = 0; i < totalSize; i++)
{
fprintf(output, "%i\n", numbers[i]);
}
fclose(file0);
fclose(file1);
fclose(file2);
fclose(output);
free(numbers);
return 0;
}
Your input files have several lines, each of which has the textual representation of a number. Your file size function however is counting the total number of bytes in the file. These are not the same.
While you can still use the file size to allocate space (you'll just get more than you need), you need to instead check the return value of scanf to see if a number was read. If not, you jump out of the loop.
int index = 0;
while (fscanf(file0, "%i", &numbers[index]) == 1) {
index++;
}
while (fscanf(file1, "%i", &numbers[index]) == 1) {
index++;
}
while (fscanf(file2, "%i", &numbers[index]) == 1) {
index++;
}
for(i = 0; i < index; i++)
{
fprintf(output, "%i\n", numbers[i]);
}
The size calculation includes the carriage return "\n" character at the end of the file. Therefore, you are allocating space for 8 integers for the first file, 6 integers for the second file and 10 integers for the third file (10, because the number "10" has two digits).
The correct allocation strategy would be not to count the bytes in the files, but the lines (which actually contain numbers, thus allowing you to skip empty lines).
But that's just too much trouble. Instead, consider just allocating 1000 bytes, read in until you run out, then re-alloc into a larger buffer.

fread fails to read an unsigned int? [C]

I have a Person Struct as the following:
typedef struct Person {
char name[NUM_CHARS];
unsigned int age;
} Person;
where #define NUM_CHARS 20.
I want to write this structure to a binary file, so I wrote two function to handle that:
int writePerson(Person* person, FILE* _fp) {
int i = 0;
int count = 0;
int len = strlen(person->name);
// Write name
for(i = 0; i < len+1; i++) {
count += fwrite(&(person->name[i]), sizeof(char), 1, _fp);
// fseek(_fp, 1, SEEK_CUR);
}
// Continue
// Write age
count += fwrite(&(person->age), sizeof(unsigned int), 1, _fp);
return count;
}
int readPerson(Person* person, FILE* _fp) {
int i = 0;
int count = 0;
// Write name
for(i = 0;person->name[i] != NULL;i++) {
count += fread(&(person->name[i]), sizeof(char), 1, _fp);
}
// Continue
// Write age
count += fread(&(person->age), sizeof(unsigned int), 1, _fp);
return count;
}
So I wrote a Person to a blank file Px.bin that I've created well in advance:
int main() {
FILE* fp = fopen("Px.bin", "r+b");
Person person = {"Billie", 40};
// Person y ;
int x = writePerson(&person, fp);
printf("%d", x);
// printPerson(&y);
getchar();
fcloseall();
return 0;
}
Seems to work well, prints 8.
but when I try to read this file:
int main() {
FILE* fp = fopen("Px.bin", "r+b");
// Person person = {"Billie", 40};
Person y ;
int x = readPerson(&y, fp);
printf("%d\n", x);
printPerson(&y);
getchar();
fcloseall();
return 0;
}
I'm getting this result:
11
Billie
-858993460
Where printPerson is:
void printPerson(Person* p) {
printf("%s\n%d\n", p->name, p->age);
}
What is the problem?
This bit
for(i = 0;person->name[i] != NULL;i++) {
count += fread(&(person->name[i]), sizeof(char), 1, _fp);
}
is going to use uninitialized (IOW, containing garbage) person->name[] as the condition for reading. And it may so happen that the wrong number of bytes will get read here.
After that the following
count += fread(&(person->age), sizeof(unsigned int), 1, _fp);
can read the integer from an incorrect location within the file, not where said integer has been stored.
The fix would be to first read a character and then see if it's '\0' or not. If it is, the string's been fully read. If it's not, keep reading characters.
Your code that reads name does check for likely non-initialized (or zeroed out) person->name[i] elements. As result the loop end at some non-predictable time (i.e. if it is zeroed out loop will not fread even single character).
for(i = 0;person->name[i] != NULL;i++) {
count += fread(&(person->name[i]), sizeof(char), 1, _fp);
}
You want to change it to do/while loop or instead of reading till 0 prefix data in the file string with length and read that many characters.

How to read unlimited characters in C

How to read unlimited characters into a char* variable without specifying the size?
For example, say I want to read the address of an employee that may also take multiple lines.
You have to start by "guessing" the size that you expect, then allocate a buffer that big using malloc. If that turns out to be too small, you use realloc to resize the buffer to be a bit bigger. Sample code:
char *buffer;
size_t num_read;
size_t buffer_size;
buffer_size = 100;
buffer = malloc(buffer_size);
num_read = 0;
while (!finished_reading()) {
char c = getchar();
if (num_read >= buffer_size) {
char *new_buffer;
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
/* Abort - out of memory */
}
buffer = new_buffer;
}
buffer[num_read] = c;
num_read++;
}
This is just off the top of my head, and might (read: will probably) contain errors, but should give you a good idea.
Just had to answer Ex7.1, pg 330 of Beginning C, by Ivor Horton, 3rd edition. Took a couple of weeks to work out. Allows input of floating numbers without specifying in advance how many numbers the user will enter. Stores the numbers in a dynamic array, and then prints out the numbers, and the average value. Using Code::Blocks with Ubuntu 11.04. Hope it helps.
/*realloc_for_averaging_value_of_floats_fri14Sept2012_16:30 */
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
int main(int argc, char ** argv[])
{
float input = 0;
int count=0, n = 0;
float *numbers = NULL;
float *more_numbers;
float sum = 0.0;
while (TRUE)
{
do
{
printf("Enter an floating point value (0 to end): ");
scanf("%f", &input);
count++;
more_numbers = (float*) realloc(numbers, count * sizeof(float));
if ( more_numbers != NULL )
{
numbers = more_numbers;
numbers[count - 1] = input;
}
else
{
free(numbers);
puts("Error (re)allocating memory");
exit(TRUE);
}
} while ( input != 0 );
printf("Numbers entered: ");
while( n < count )
{
printf("%f ", numbers[n]); /* n is always less than count.*/
n++;
}
/*need n++ otherwise loops forever*/
n = 0;
while( n < count )
{
sum += numbers[n]; /*Add numbers together*/
n++;
}
/* Divide sum / count = average.*/
printf("\n Average of floats = %f \n", sum / (count - 1));
}
return 0;
}
/* Success Fri Sept 14 13:29 . That was hard work.*/
/* Always looks simple when working.*/
/* Next step is to use a function to work out the average.*/
/*Anonymous on July 04, 2012*/
/* http://www.careercup.com/question?id=14193663 */
How about just putting a 1KB buffer (or 4KB) on the stack, reading into that until you find the end of the address, and then allocate a buffer of the correct size and copy the data to it? Once you return from the function, the stack buffer goes away and you only have a single call to malloc.

Resources