The function read a matrix from a file, and print it on the screen. but there is something wrong when library fscanf(fp, "%u", &elem); read file from fp.
It's OK when I change uint8_t elem to uint8_t *elem .
I want to know why! What should pay attention when program transfers a FILE pointer to the library. Thx!
main function:
int main(int argc, char *argv[]){
Matrix8g mat;
FILE *fp;
if((fp = fopen("mat.dat","r")) == NULL){
printf("can't open the file");
}
//matrix with 24 rows and 11 cols
mat.Make_from_file(fp, 24, 11);
//print the matrix
mat.Print();
fclose(fp);
}
Part of library file (Make_from_file):
/* Set the matrix from a file */
int Matrix8g::Make_from_file(FILE *fp, int rows, int cols){
int i, j;
uint8_t elem;
this->rr = rows;
this->cc = cols;
Resize_matrix();
try{
for(i = 0; i < rows; i++){
for(j = 0; j < cols; j++){
fscanf(fp, "%u", &elem);
Set(i, j, elem);
}
}
}catch(...){
NOTE("Error when set the matrix from a file");
return 0;
}
return 1;
}
If you look at this reference c reference
You would see that fscanf needs a reference to the data structure to which the extracted date should be written. fscanf copies from the given file/stream to the given pointer. It has no information about what type the data has. It uses the format string to interpret the byte from the input. Its similar to a type casting. fscanf can't know which type is needed as target structure but a pointer allows a straight copy operation.
Related
I'm trying to initialize an array of integers dynamically, since the size of the array changes based on input.
The program is as follows:
int main()
{
int* list = createList("dis.bin");
for (int i = 0; i < sizeof(list) / sizeof(int); i++)
{
printf("%d\n", list[i]);
}
}
With createList() function as written:
int* createList(const char* file_name)
{
int counter = 1;
int* inst{};
FILE* myFile = fopen(file_name, "rb");
if (myFile == nullptr)
{
printf("\nFile not opened\n");
return 0;
}
int x = 0;
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
inst = new int[counter];
inst[i] = x;
printf("%08x #%-4d | Int equiv: %-12d | Bin equiv: %s\n", x, counter, inst[i], ToBinary(inst[i], 0));
counter += 1;
x = 0;
}
return inst;
}
createList reads from a .bin file (basically containing an array of bytes) and inserts each pair of 4 bytes to an item in the array inst. I do this by allocating a new amount of space for the array based on the counter variable. (So whatever value counter is becomes the size of the array with inst = new int[counter]) Then I set the contents of the array at the given index i equal to x (the pair of bytes read) I would assume it is working correctly in createList at least, because of the printf statement which is printing each element in inst[].
However, when I call createList("dis.bin") in main and assign it to the variable int* list, I try to iterate through each value. But this just prints out one uninitialized value (-842150451, if you're curious). So I'm not sure what I'm doing wrong here?
I should mention that I am NOT using vectors or really any std container. I am just working with arrays. I also am using printf for specific reasons.
This question is tagged as C++, but OP is showing C code and says they need it in C, so I will show this in C... but the pre-req is that it uses new and not malloc
int* createList(const char* file_name, int& count)
{
// initialize count, so that way if we return early, we don't have invalid information
count = 0;
// open the file ad "READ" and "BINARY"
FILE* myFile = fopen(file_name, "rb");
if (!myFile)
{
printf("\nFile not opened\n");
return 0;
}
// calculate how many 4-byte integers exist in the file using
// the file length
fseek(myFile, 0, SEEK_END);
count = ftell(myFile) / sizeof(int);
rewind(myFile);
// allocate the memory
int* returnData = new int[count];
// read in 4-byte chunks to our array until it can't read anymore
int i = 0;
while (fread(&returnData[i++], sizeof(int), 1, myFile) == 1);
// close the file
fclose(myFile);
// return our newly allocated data
return returnData;
}
int main()
{
int count;
int* myInts = createList("c:\\users\\andy\\desktop\\dis.bin", count);
for (int i = 0; i < count; ++i) {
printf("%d\n", myInts[i]);
}
// don't forget to delete your data. (another reason a vector would be better suited... no one remembers to delete :)
delete myInts;
}
Two things here:
The usage of new was misinterpreted by me. For whatever reason, I thought that each time I allocated new memory for inst that it would just be appending new memory to the already allocated memory, but this is obviously not the case. If I wanted to simulate this, I would have to copy the contents of the array after each iteration and add that to the newly allocated memory. To solve this, I waited to allocate memory for inst until after the file iteration was complete.
As Andy pointed out, sizeof(list) / sizeof(int) would not give me the number of elements in list, since it is a pointer. To get around this, I created a new parameter int &read for the createList() function in order to pass the number of items created.
With these points, the new function looks like this and works as intended:
int* createList(const char* file_name, int &read)
{
int counter = 1;
FILE* myFile = fopen(file_name, "rb");
if (myFile == nullptr)
{
printf("\nFile not opened\n");
return 0;
}
int x = 0;
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
printf("%08x #%-4d | Int equiv: %-12d | Bin equiv: %s\n", x, counter, x, ToBinary(x, 0));
counter += 1;
}
int* inst = new int[counter];
read = counter;
rewind(myFile); // rewind to beginning of file
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
inst[i] = x;
x = 0;
}
return inst;
}
With main changed a bit as well:
int main()
{
int read;
int* list = createList("dis.bin", read);
for (int i = 0; i < read; i++)
{
printf("%d\n", list[i]);
}
}
As for the comments about the invalidity of !(feof(myFile)), although helpful, this was not a part of my question and thus not of my concern. But I will source the solution to that for the sake of spreading important information: Why is "while ( !feof(file) )" always wrong?
I want to convert the following code from objective C to C++.
In the class myClass, I have this attribute:
float tab[dim1][dim2][dim3];
In an objective-C file, the multidimensional array is filled from a binary file:
NSData *dataTab=[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pathOfMyTab" ofType:#""]];
[dataTab getBytes:myClass -> tab length:[dataTab length]];
How could I translate this part into C++ ?
I am assuming that your file contains the byte-representation of the array. If this is the case, then to mimic the behaviour of your Objective-C code using only C++ (the only thing that makes this C++ is the reinterpret_cast<>, otherwise it is just straight C), you could use the following code. I have not added any error checking, but left some comments where you might want to perform some.
float tab[dim1][dim2][dim3];
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef dataTabURL = CFBundleCopyResourceURL(mainBundle, CFSTR("pathOfMyTab"), NULL, NULL);
CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, dataTabURL); // check for NULL return value
CFReadStreamOpen(stream); // check for errors here
CFReadStreamRead(stream, reinterpret_cast<UInt8 *>(tab), sizeof tab); // check that this function returns the number of bytes you were expecting (sizeof tab)
CFReadStreamClose(stream);
// we own "stream" and "dataTabURL" because we obtained these through functions
// with "create" in the name, therefore we must relinquish ownership with CFRelease
CFRelease(stream);
CFRelease(dataTabURL); // ditto
If you already have the path available in a std::string, then you can use the following C++ code to mimic the behaviour of your Objective-C code:
// make sure to include this header
#include <fstream>
// ... then elsewhere in your .cpp file ...
float tab[dim1][dim2][dim3];
std::string path = "path/to/mytab"; // obtain from somewhere
std::ifstream input(path, std::ios::binary); // check that the file was successfully opened
input.read(reinterpret_cast<char *>(tab), sizeof tab); // check that input.gcount() is the number of bytes you expected
I believe in this case we have to use reinterpret_cast<> because the file contains the actual representation of the array (assuming it was previously written to the file in a similar manner).
You can use a hybrid approach, once you have the CFURLRef containing the path to the resource, you can obtain a file system representation of the URL using this function (providing a suitably sized output buffer to store the result), and from there you should be able to pass that to one of std::ifstream's constructors (although, you may need to cast to the appropriate type).
C++ doesn't support variable-length arrays (the size of arrays must be known at compile time). There is also no matrix type provided by the standard library, so if the dimensions of your table vary at run time, then you will need a completely separate approach to the one in my answer. You could consider serialising the output from Objective-C (using e.g. JSON or another format) such that the dimensions of the matrix are also written to the output, making it easier to parse the file in C++.
Take a look at fstream, fread and read, all read binary files, pick the approach that suits.
On my mind the simplest and fastest way is to use memcpy() to copy NSData' bytes into target array with same structure (dimensions) as a source one. See, for example:
https://github.com/Voldemarus/MultiDimensionalArrayDemo/tree/master
#import "DemoClass.h"
#define DIM1 3
#define DIM2 4
#define DIM3 2
#interface DemoClass() {
int src[DIM1][DIM2][DIM3]; // source (initial) array
int dst[DIM1][DIM2][DIM3]; // destination array
}
#end
#implementation DemoClass
- (instancetype) init
{
if (self = [super init]) {
for (int i = 0; i < DIM1; i++) {
for (int j = 0; j < DIM2; j++) {
for (int k = 0; k < DIM3; k++) {
int value = i*100 + j*10 + k;
src[i][j][k] = value;
}
}
}
}
return self;
}
int getIntFromArray(int *array, int i, int j, int k) {
int offset = j*DIM3 + i*DIM2*DIM3;
return array[offset];
}
void putIntToArray(int *array, int i, int j, int k, int value) {
int offset = j*DIM3 + i*DIM2*DIM3;
array[offset] = value;
}
- (void) run
{
// Step 1. Save array into NSData
NSInteger s = sizeof(int)*DIM1*DIM2*DIM3;
NSData *data = [[NSData alloc] initWithBytes:src length:s];
NSAssert(data, #"NSData should be created");
//Step2 - Create new array
int *bytes = (int *)[data bytes];
memcpy(dst,bytes,s);
// Step 3. Compare src and dst
for (int i = 0; i < DIM1; i++) {
for (int j = 0; j < DIM2; j++) {
for (int k = 0; k < DIM3; k++) {
int template = i*100 + j*10 + k;
int s = src[i][j][k];
int d = dst[i][j][k];
// NSLog(#"i %d j %d k %d -->s = %d d = %d",i,j,k,s,d);
NSAssert(s == template, #"Source array should have value from template");
NSAssert(d == s, #"Destination array should be identical to the source");
}
}
}
}
#end
float tab[dim1][dim2][dim3] looks like a three-dimensional array. The standard implementation is with three nested FOR loops.
So your C++ implementation can look like this:
read dim1, dim2, dim3 from somewhere, usually the first values in the file (for example 12 bytes, 4 bytes for each number)
read the rest of the file in three nested FOR loops
Something like:
for (size_t i = 0; i < dim1; ++i)
for (size_t j = 0; j < dim2; ++j)
for (size_t k = 0; k < dim3; ++k)
tab[i][j][k] = read_float_value(inputFile);
In Objective-C you can write the file in a similar way.
Here are some examples to get you started:
Three dimensional arrays of integers in C++
3D array C++ using int [] operator
Im trying to read a .txt file with the values of a matrix [n]x[m] by using a function and then call it in my main but I am having some problems... Here is the read function:
bool read_file(int row, int column, char *file_name, float **elems)
{
int i, j;
FILE *pfile;
fopen_s(&pfile, file_name, "r");
if (pfile == NULL) {
return false;
}
fscanf_s(pfile, "%d", &row);
fscanf_s(pfile, "%d", &column);
//printf_s("%d %d\n", row,column);
for (i = 0; i < row; i++)
{
for (j = 0; j < column; j++) {
fscanf_s(pfile, "%f", &elems[i][j]);
//printf("%f\n", elems[i][j]);
}
}return true;
}
My program asks me to do product between two matrices and i have to do it by 2 types of input, keybord or file. I used in my main if-else to choose between the 2 inputs. When it does keybord input, everything goes right (dinamic alocation is working as well as the product of matrices). I then call the function like this in the main:
int main(){
int i, j, row1, column1, row2, column2;
char* file_name1 = { "C:\\Users\\Lc\\Documents\\Matrix1.txt" };
char* file_name2 = { "C:\\Users\\Lc\\Documents\\Matrix2.txt" };
if (...) {
...
/* Input by keybord. */
...
}
else if(...){ /*Input by file*/
read_file(row1, column1, file_name1, matrix1);
read_file(row2, column2, file_name2, matrix2);
...
}
...
And then it says matrix1 and matrix2 are undefined... I understand why they are undefined but my problem is that i dont know how to define them like i did with the keybord input
float **elems is a pointer to an array of pointers to arrays of floats. You can create such a thing by calling malloc() in a loop.
Note the way it's used in your code:
fscanf_s(pfile, "%f", &elems[i][j]);
So elems[0..N] are meant to point to the rows. First, allocate the outer array:
float** elems = malloc(row * sizeof(float*));
assert(elems);
That's one float* for each row. Then, allocate each row:
for (i = 0; i < row; i++)
{
elems[i] = malloc(column * sizeof(float));
assert(elems[i]);
}
Now elems points to an array of float* initialized with each element pointing to an array of float (which numbers are uninitialized).
What is the best way to go about reading signed multi-byte words from a buffer of bytes?
Is there a standard way to do this that I am not aware of, or am I on the right track reading in 4 chars and raising them to their respecting power of 16 and summing them together?
int ReadBuffer(int BuffPosition, int SequenceLength){
int val = 0;
int limit = BuffPosition + SequenceLength;
int place = 0;
for( BuffPosition; BuffPosition < limit; BuffPosition++ ){
int current = Buff[BuffPosition];
current *= pow(16, (2*place));
val += current;
place++;
}
return val;}
Assuming you read/write your file on the same machine (same endianness), you can use a 32 bit type like int32_t (#include <cstdint>) and read directly. Small example below:
#include <iostream>
#include <fstream>
#include <cstdint>
int main()
{
std::fstream file("file.bin", std::ios::in | std::ios::out | std::ios::binary);
const std::size_t N = 256; // length of the buffer
int32_t buf[N]; // our buffer
for (std::size_t i = 0; i < N; ++i) // fill the buffer
buf[i] = i;
// write to file
file.write((char*)buf, N * sizeof(int32_t));
for (std::size_t i = 0; i < N; ++i) // zero-in the buffer
buf[i] = 0; // to convince we're not cheating
// read from file
file.seekg(0); // rewind to beginning
file.read((char*)buf, N * sizeof(int32_t));
// display the buffer
for (std::size_t i = 0; i < N; ++i) // fill the buffer
std::cout << buf[i] << " ";
}
I now realize that I can take a char* buffer and cast it to a data type with the correct size.
char* 8BitBuffer[4000];
int* 32BitBuffer;
if(sizeof(int) == 4){
32BitBuffer = (int*)8BitBuffer;
}
dostuffwith(32BitBuffer[index]);
I am trying to process a wav file, so In an attempt to maximize efficiency I was trying to avoid reading from the file 44100 times a second. Whether or not that is actually slower than reading from an array I am not actually sure.
I am trying to simply write an array of float values to a file and then read it back.
I have tried writing it directly from an array, but when reading it back I keep hitting a problem for arrays with length greater than 153. The code example writes each float value one by one for clarity.
For values with index greater than or equal to 153 they have the value 153.0, where they should be 153.0, 154.0, 155.0, ...
Why doesn't this code work for me?
int length = 160;
char* fileName = "testFile.dat";
// Write data to file
FILE* file = fopen (fileName, "w");
for(int i = 0; i< length; i++){
// We are just storing the indices, so value at i is equal to i
float f = (float) i;
fwrite(&f, sizeof(float), 1, file);
}
fclose(file);
// Read data from file into results array
file = fopen(fileName, "r");
float* results = new float[length];
for(int i = 0; i< length; i++){
float f;
fread(&f, sizeof(float), 1, file);
results[i] = f;
}
fclose(file);
// Now check data in results array
bool fail = false;
for(int i = 0; i< length; i++){
if(results[i]!=(float)i){
fail = true; // This should not be hit, but it is!
}
}
delete [] results;
Thanks,
Dave
FILE* file = fopen (fileName, "wb");
FILE* file = fopen (fileName, "rb");