I am reading a file full of 2-byte-long ints into an array
FILE *f = fopen("file.bin", "rb");
int *arr;
int len = 2;
This works:
// method 1
for (int i = 0; i < numberOfElements; i++)
fread(arr + i, len, 1, f);
I want this to work the same way:
// method 2
fread(arr, len, numberOfElements, f);
The goal is to increase performance.
If you are reading a bunch of 2-byte ints, you need to read them into an array of 2-byte ints. The most straightforward way is to use the standard type int16_t from <stdint.h>. You would want something like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
FILE *f = fopen("file.bin", "rb");
int16_t *arr;
int len = 2;
assert(sizeof(*arr) == len);
arr = malloc(numberOfElements * len);
if(arr == NULL) {
fprintf(stderr, "malloc failed\n");
exit(1);
}
int r = fread(arr, len, numberOfElements, f);
if(r != numberOfElements) {
fprintf(stderr, "incorrect number of items read\n");
exit(1);
}
You'll notice that I have added code to allocate arr, check that malloc succeeded, check that the type we chose matches len, and check that fread did in fact read the number of items expected.
Related
I have an array, which holds 6 words and a secret word
char boardInputs[7][6];
I need to autosave to binary file this array every time when user entered the word. After restarting the program, I need to read the saved array of words from the binary file and install it into the input data array of the board
void readArray(int rows, int cols, char array[rows][cols]) {
FILE *data;
data = fopen("autosave.bin", "rb");
fread(array, sizeof(char[rows][cols]), 1, data);
}
void autoSave() {
int result = EXIT_SUCCESS;
char file_name[] = "autosave.bin";
FILE *fp = fopen(file_name, "wb");
if (fp == NULL) {
result = EXIT_FAILURE;
fprintf(stderr, "fopen() failed for '%s'\n", file_name);
} else {
size_t element_size = sizeof *boardInputs;
size_t elements_to_write = sizeof boardInputs;
size_t elements_written = fwrite(boardInputs, element_size, elements_to_write, fp);
if (elements_written != elements_to_write) {
result = EXIT_FAILURE;
fprintf(stderr, "fwrite() failed: wrote only %zu out of %zu elements.\n",
elements_written, elements_to_write);
}
fclose(fp);
}
}
int main() {
int cols = 7;
int rows = 6;
char (*myArray)[cols] = allocArray(rows, cols);
readArray(rows, cols, myArray);
strcpy(boardInputs, myArray);
free(myArray);
}
I created this code, but the words from the binary file are set incorrectly. How to fix it?
There are multiple problems in your code:
you do not test for fopen() failure in readArray;
you do not close the file in read_array;
result is unused in autoSave;
strcpy is incorrect to copy the whole board. You should test if readArray succeeded and use memcpy;
the sizes in autoSave are incorrect: size_t element_size = sizeof *boardInputs evaluates to the size of a word, ie 6 bytes, and size_t elements_to_write = sizeof boardInputs is the size in bytes of the whole array. fwrite will attempt to write 6 * 42 bytes, causing undefined behavior as it accesses boardInputs beyond its boundaries. The length of an array is its size divided by the element size. In this case, it is probably best to use bytes, not words as the unit;
to ensure consistency between boardInputs and myArray, they should be defined with the same size by construction.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_COUNT 7
#define WORD_LEN 6
char boardInputs[WORD_COUNT][WORD_LEN];
const char *autoSaveFilename = "autosave.bin";
int readArray(int rows, int cols, char array[rows][cols]) {
FILE *fp = fopen(autoSaveFilename, "rb");
if (fp == NULL)
return -1;
int n = fread(array, sizeof(char[rows][cols]), 1, fp);
fclose(fp);
return n == 1 ? 0 : -1;
}
int autoSave(void) {
int result = EXIT_SUCCESS;
FILE *fp = fopen(autoSaveFilename, "wb");
if (fp == NULL) {
result = EXIT_FAILURE;
fprintf(stderr, "fopen() failed for '%s': %s\n",
autoSaveFilename, strerror(errno));
} else {
size_t element_size = 1;
size_t elements_to_write = sizeof(boardInputs);
size_t elements_written = fwrite(boardInputs, 1, elements_to_write, fp);
if (elements_written != elements_to_write) {
result = EXIT_FAILURE;
fprintf(stderr, "fwrite() failed: wrote only %zu bytes out of %zu.\n",
elements_written, elements_to_write);
}
fclose(fp);
}
return result;
}
int main() {
char myArray[WORD_COUNT][WORD_LEN];
if (!readArray(WORD_COUNT, WORD_LEN, myArray))
memcpy(boardInputs, myArray, sizeof boardInputs);
return 0;
}
autoSave() is calling fwrite() with incorrect arguments, sizeof boardInputs is the total size of the 2d array so number of elements is 1. This was the key issue.
autoSave() doesn't return anything so eliminate result.
autoSave() and readArray() hard-code the same path, so make it a define instead of duplication.
readArray() relies on a global variable, so elevated rows and cols to macro constants and simplified number of arguments.
readArray() should close the data file handle.
main() should return an int.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 7
#define COLS 6
#define PATH "autosave.bin"
char boardInputs[ROWS][COLS];
void autoSave() {
FILE *fp = fopen(PATH, "wb");
if(!fp) {
fprintf(stderr, "fopen() failed for '%s'\n", PATH);
return;
}
size_t elements_to_write = sizeof boardInputs;
size_t elements_written = fwrite(boardInputs, 1, elements_to_write, fp);
if (elements_written != elements_to_write) {
fprintf(stderr, "fwrite() failed: wrote only %zu out of %zu elements.\n",
elements_written, elements_to_write);
}
fclose(fp);
}
void printArray(char array[ROWS][COLS]) {
for(int i = 0; i < ROWS; i++) {
printf("%d: %s\n", i, array[i]);
}
}
void readArray(char array[ROWS][COLS]) {
FILE *data = fopen(PATH, "rb");
fread(array, sizeof(char[ROWS][COLS]), 1, data);
fclose(data);
}
int main() {
for(unsigned i = 0; i < 7; i++) {
char s[7];
sprintf(s, "%u", i);
strcpy(boardInputs[i], s);
}
printArray(boardInputs);
autoSave();
char myArray[ROWS][COLS];
readArray(myArray);
printArray(myArray);
return 0;
}
The output demonstrate the read and write have the same values:
0: 0
1: 1
2: 2
3: 3
4: 4
5: 5
6: 6
0: 0
1: 1
2: 2
3: 3
4: 4
5: 5
6: 6
I want sign a tar.gz file and verify the signature for do this i put a signature (in char) in my file. Then i have an another executable who check the sign and if she is good delete this, and to do that i get the content of the file whitout my signature and copy on an other file that a create.
But here is the problem, When a do this my tar.gz original file make a size of 141 and my newly created file make a size of 140. Then when a decompress them i have this error message:
gzip: stdin: unexpected end of file tar:
Child returned status 1 tar:
Error is not recoverable: exiting now
I think when i get the content i forgot a charactere. I tried to use clearerr or feof whitout success.
This is my code for get the content of the signed file:
#define SIZE_SIGNATURE (423)
int get_size(char *file)
{
struct stat sb;
int size = 0;
if (stat(file, &sb) == -1) {
fprintf(stderr, "Cant access the %s file\n", file);
return (-1);
}
size = sb.st_size - SIZE_SIGNATURE;
size = size / 4;
if (size <= 0) {
fprintf(stderr, "The content of the file is invalid\n");
return (-1);
}
return (size);
}
int *get_content(char *file, int size)
{
FILE *fp = NULL;
int *content = NULL;
int i = 0;
content = malloc(sizeof(int) * size);
if (!content) {
fprintf(stderr, "Error, malloc fail\n");
return (NULL);
}
fp = fopen(file,"rb");
if (!fp) {
fprintf(stderr, "Cant open %s file\n", file);
return (NULL);
}
fread(content, sizeof(int), size, fp);
fclose(fp);
return (content);
}
And when i have created my new file i put the content on them like this:
fp = fopen(new_name, "a");
if (!fp) {
fprintf(stderr, "A problem has occured during file creation.\n Cant delete signature\n");
free(new_name);
return;
}
fwrite(content, sizeof(int), size, fp);
Why i do: size = size / 4 (i dont know if is the thing to do)
He is a little code for understanding the thing i simply put three int in non lisible charactere
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
void ecriture1()
{
FILE* F;
int a = 5;
int b = 6;
int d = 42;
F = fopen("test.bin","wb");
fwrite(&a,sizeof(int),1,F);
fwrite(&d,sizeof(int),1,F);
fwrite(&b,sizeof(int),1,F);
fclose(F);
}
void lecture1()
{
int *tab;
int i = 0;
int size;
struct stat sb;
FILE* F;
stat("test.bin", &sb);
F = fopen("test.bin","rb");
size = sb.st_size;
tab = malloc(sizeof(int) * size);
while (i < size) {
fread(&tab[i], sizeof(int), 1, F);
i++;
}
for (i = 0; i < size; i++)
printf("[i] = %d,", tab[i]);
printf("\n");
fclose(F);
}
int main()
{
ecriture1();
lecture1();
return 0;
}
He is the resultat when i dont put the / 4:
[i] = 5,[i] = 42,[i] = 6,[i] = 0,[i] = 0,[i] = 0,[i] = 0,[i] = 0,[i] = 0,[i] = 0,[i] = 0,[i] = 0,
And when i put / 4:
[i] = 5,[i] = 42,[i] = 6,
EDIT:
In my programe when i delete the / 4 and i decompresse the new .tar.gz i have this error message:
gzip: stdin: invalid compressed data--length error
tar: Child returned status 1
tar: Error is not recoverable: exiting now
So i think without error on my part that i should put the / 4 but i cant explain this.
You have a rounding error because you divide the size by 4.
I think the reason why you do size / 4 is because you later do sizeof(int) * size and if you have 4 byte integers then that will cause your size to be 4 times larger than you want. So I think you wrote two bugs there that cancel each other out.
I would suggest you remove the / 4 as well as also removing the sizeof(int) * and thus always just let size be the byte count.
As a bonus, this will remove the rounding error that you might have which is probably the whole reason for your problem. Because 141/4 = 35,25 which will be rounded to 35. Then 35 * sizeof(int) = 35 * 4 = 140.
Also I would not recommend storing arbitrary binary data of arbitrary size in an array of int because an int array should have a size evenly divisible by 4. I would probably go for a char * or just a void * rather than int *.
I have a large file containing floating point numbers and I want to read them.
52.881 49.779 21.641 37.230 23.417 7.506 120.190 1.240 79.167 82.397 126.502 47.377 112.583 124.590 103.339 5.821 24.566 38.916 42.576
This is just the beggining of the file. It has 10000000 numbers.
I got this code but I don't know how to print the numbers.
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <fcntl.h>
#include <sysexits.h>
#include <unistd.h>
int main()
{
int fd;
size_t bytes_read, bytes_expected = 1000000*sizeof(double);
double *data;
char *infile = "file.dat";
if ((fd = open(infile,O_RDONLY)) < 0)
err(EX_NOINPUT, "%s", infile);
if ((data = malloc(bytes_expected)) == NULL)
err(EX_OSERR, "data malloc");
bytes_read = read(fd, data, bytes_expected);
if (bytes_read != bytes_expected)
err(EX_DATAERR, "Read only %d of %d bytes",
bytes_read, bytes_expected);
/* print all */
free(data);
exit(EX_OK);
}
You are attempting to read a text file as if the data was binary, so you will read some bytes but the double values stored in the array will not be the values that you wanted to read from the file, you can probably do this
FILE *file;
double *array;
size_t count;
const char *infile = "file.dat";
file = fopen(infile, "r");
if (file == NULL)
return -1;
count = 0;
while (fscanf(file, "%*lf") == 1)
count += 1;
rewind(file);
array = malloc(count * sizeof(*array));
if (array == NULL) {
fprintf(stderr, "cannot allocate %zu bytes!\n", count * sizeof(*array));
fclose(file);
return -1;
}
// Read the values into the array
for (size_t i = 0; i < count; ++i) {
fscanf(file, "%lf", &array[i]);
}
// Print the array
for (size_t i = 0; i < count; ++i) {
fprintf(stdout, "%f\n", array[i]);
}
// Release memory
free(array);
Since you want a fast solution, maybe you have to sacrifice memory.
The faster manner of reading a file is in binary form.
Thus, I would obtain the file size with an efficient method,
then I would allocate memory accordingly,
with the idea of uploading the entire file to memory.
There, since memory reading is faster than file reading,
the data can be quickly read by using sscanf(...).
We can also observe that each floating point number
needs at least 3 characters to be stored in a text file:
1 char for the dot ('.'),
1 char for some digit,
and 1 char for
a space (' ') used to separating a value from its succesor in the
file.
Thus, the file size divided by 3 will be the upper bound for the size of the array of doubles.
#include <stdio.h>
int main(void) {
char *filename = "file.dat";
FILE *F = fopen(filename, "rb");
fseek(F, 0L, SEEK_END);
long int filesize = ftell(F);
rewind(F);
char *data = malloc(filesize+1);
fread(data, filesize, 1, F);
data[filesize] = '\0'; // End of string, just in case
fclose(F);
// The desired data will be stored in array:
double *array = malloc(sizeof(double) * filesize/3);
int ret;
int n; // represents the no chars in a sscanf(...) reading
double *a = array;
while (1) { // Infinite loop...
ret = sscanf(data, " %lg%n", a, &n);
if (ret == EOF) break; // <<---- EXIT POINT of the loop
a++;
data += n;
}
long int array_size = a - array + 1;
}
I am trying to write a program to compile with Xeon Phi and it says there is a segmentation fault? I think it is when I try to fill the arrays with the getc function. I have written this code several different formats, and I understand that this might not be the most efficient, but I need to test it out to see if it will work by parallelizing it
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <omp.h>
int main()
{
struct stat buf1;
struct stat buf2;
FILE *fp1, *fp2;
int ch1, ch2;
clock_t elapsed;
char fname1[40], fname2[40];
printf("Enter name of first file:");
fgets(fname1, 40, stdin);
while (fname1[strlen(fname1) - 1] == '\n')
{
fname1[strlen(fname1) -1] = '\0';
}
printf("Enter name of second file:");
fgets(fname2, 40, stdin);
while (fname2[strlen(fname2) - 1] == '\n')
{
fname2[strlen(fname2) -1] = '\0';
}
fp1 = fopen(fname1, "rb");
if (fp1 == NULL)
{
printf("Cannot open %s for reading\n", fname1);
exit(1);
}
fp2 = fopen(fname2, "rb");
if (fp2 == NULL)
{
printf("Cannot open %s for reading\n", fname2);
exit(1);
}
stat(fname1, &buf1);
size_t size1 = buf1.st_size;
stat(fname2, &buf2);
size_t size2 = buf2.st_size;
printf("Size of file 1: %zd\n", size1);
printf("Size of file 2: %zd\n", size2);
elapsed = clock(); // get starting time
size_t smallest = 0;
if(size1 < size2)
{
smallest = size1;
}
else
{
smallest = size2;
}
printf("Smallest Value: %zu\n", smallest);
size_t i, j, k;
size_t data[smallest];
size_t arry1[smallest];
size_t arry2[smallest];
unsigned long long counter = 0;
for(i = 0; i < smallest; i++)
{
data[i] = 1;
arry1[i] = getc(fp1);
arry2[i] = getc(fp2);
}
//#pragma omp for //reduction(+:counter)
for(k = 0; k < smallest; k++)
{
if((arry1[k] ^ arry2[k]) == 0)
{
counter+= data[k];
}
}
fclose (fp1); // close files
fclose (fp2);
float percent = (float)counter / (float)smallest * 100.0f;
printf("Counter: %zu Total: %zu\n", counter, smallest);
printf("Percentage: %.2f%\n", percent);
elapsed = clock() - elapsed; // elapsed time
printf("That took %.2f seconds.\n", (float)elapsed/CLOCKS_PER_SEC);
return 0;
}
Thanks for your help in advance!
You cannot declare an array with a size that's not known at compile time:
int smallest;
smallest = .... // some computation
size_t data[smallest]; // this is wrong!
You should instead use malloc() to accomplish that:
size_t *data;
smallest = ... // whatever
data = malloc(smallest * sizeof(size_t));
This loop:
while (fname1[strlen(fname1) - 1] == '\n')
fname1[strlen(fname1) -1] = '\0';
will read off the start of the string if the line was blank (i.e. "\n"). Change while to if.
Also, check that smallest > 0 before declaring the VLAs.
It might be insightful to output the value of smallest, typical systems default to a stack size of somewhere between 1MB and 8MB, so perhaps you cause a stack overflow here. You could eliminate this possibility by using malloc, as ocho88 suggests (but without the bogus cast):
size_t *data = malloc(smallest * sizeof *data);
size_t *arry1 = malloc(smallest * sizeof *arry1);
size_t *arry2 = malloc(smallest * sizeof *arry2);
if ( !data || !arry1 || !arry2 )
// exit with out-of-memory error
I'm not sure why you use a size_t to store the result of getc.
If this does not solve the problem then it would be useful to identify which line is segfaulting. If you can't get a debugger working, then you can output (to stderr, or to stdout with fflush) to find out where it is getting up to.
iv'e written a part of a code which basically transfers text from a txt file into a variable and prints it(as a part of a program),yet it does not print the contents at all.
#include <stdio.h>
#include <stdlib.h>
#define WRONG_ARGUMENTS (-1)
int Lines(FILE * file);
int Length(FILE * file);
int Read(FILE * file);
int Lines(FILE * file)
{
int c=0,count=0;
++count;
while(c!=EOF)
{
c=fgetc(file);
if(c=='\n')
++count;
}
return count;
}
int Length(FILE * file)
{
int c,count=0;
while((c=fgetc(file))!=EOF)
{
++count;
}
return count;
}
int Reader(FILE * Text,char * File)
{
int counter=0;
while(fscanf(Text,"%s",File)!=EOF)
{
++counter;
strcat(File," ");
}
return counter;
}
int main(int argc,char * argv[]) {
FILE * Text=NULL;
if(argc!=2)
{
printf("usage:library text dictionary\n");
return -1;
}
Text = fopen(argv[1],"r");
if(Text==NULL)
{
printf("file %s could not be opened\n",argv[1]);
return -1;
}
char * File = "";
File=malloc(Length(Text)*(sizeof(char)));
int r = Reader(Text,File);
printf(File);
return 0;
}
i will be more than glad to understand the problem in the partial code
the output is x>
thanks,
Consider the following cut-down example. You'll notice that the getFileLength function (a) doesn't actually read anything from the file and (b) makes use of the fseek and ftell functions - fseek is the function that you use to reposition the file-pointer when it reaches EOF.
Imagine that you weren't printing the data, but doing something else with it. What if the file is a billion bytes long? We sure don't want to read 1,000,000,000 times from it just to determine its length!
As for the use of calloc - it zero initializes the data it allocates. Since you're reading text, you want to ensure that the text is NULL-terminated. (NULL generally = 0, though I've seen evil macros that change this) This NULL terminator is also why I allocate 1 byte more than the file contains.
#include <stdio.h>
#include <stdlib.h>
long getFileLength(FILE *input)
{
long result;
long origPos = ftell(input);
fseek(input, 0, SEEK_END);
result = ftell(input);
fseek(input, origPos, SEEK_SET);
return result;
}
int main (void)
{
FILE *fp;
long fileLen, numBytesRead;
char *data;
fp = fopen("main.cpp", "rb");
fileLen = getFileLength(fp);
data = (char*)calloc(sizeof(char), fileLen+1);
numBytesRead = fread(data, sizeof(char), fileLen, fp);
if (numBytesRead != fileLen)
printf("Error reading all bytes from file. Expected: %d, Read %d\n", fileLen, numBytesRead);
else
printf("%s", data);
free(data);
fclose(fp);
}