Writing and printing strings from an array in a file in C - c

I have an array being written to the file, but then I need a way to print that same information out from the file when I call the function. The first part of the code is in the main function, and the second is a second function that prints out the values that are supposed to be from the file (fp).
fp = fopen("Grue.txt", "wb");
for(i = 0; i < 5; i++)
{
char newLine[3] = {"\n"};
char space[2] = {" "};
fwrite(array[i].name, strlen(array[i].name), sizeof(char), fp);
fwrite(space, strlen(space), sizeof(char), fp);
fwrite(array[i].height, strlen(array[i].height), sizeof(char), fp);
fwrite(space, strlen(space), sizeof(char), fp);
fwrite(array[i].weight, strlen(array[i].weight), sizeof(char), fp);
fwrite(space, strlen(space), sizeof(char), fp);
fwrite(array[i].items, strlen(array[i].items), sizeof(char), fp);
fwrite(newLine, strlen(newLine), sizeof(char), fp);
}
fclose(fp);
fp = fopen("Grue.txt", "rb");
PrintAGrue(fp);
void PrintAGrue(FILE *a)
{
// create End of file character onto the array being saved,
int i;
char n;
char h;
char w;
char m;
for (i=0; i<5; i++)
{
n = fread(a[i].name, strlen(array[i].name, sizeof(char), a);
h = fread(array[i].height, strlen(array[i].height, sizeof(char), a);
w = fread(array[i].weight, strlen(array[i].weight, sizeof(char), a);
m = fread(array[i].items, strlen(array[i].items, sizeof(char), a);
printf("This grue is called %s and is %s feet tall, and weighs %s pounds, and has eaten %s things.", n, h, w, m);
}
}

In PrintAGrue, it looks like you're using strlen() calls to decide how much data to read -- but how
can you know the size of the string before you've read it? (Also, the parentheses don't look balanced...)
Perhaps your file format should explicitly include a length field for each string -- then you
can do one fread to find the string size, and another to actually read the string.

Related

C - Add an array of integers in a binary file

I have to add an array of int passed as parameter in a binary file as argument of the function. In parameter of the function there is also the size of the array.
If the file is empty we write the array but if the file already contains an array, we concatenate the two arrays.
My concern is that at each execution, I am reported a crash.
Here is my code:
void appendIntArray(char* filename, int* array, int N){
int* buffer = (int*) malloc(sizeof(int)*200);
FILE* fp;
if(fp == NULL) {
return(N);
}
fp = fopen(filename, "rb");
fread(N, sizeof(int), 1, fp);
fread(buffer, sizeof(int), N, fp);
fclose(fp);
fp = fopen(filename, "wb");
fwrite(&N, sizeof(int), 1, fp);
fwrite(buffer, sizeof(int), 1, fp);
fwrite(array, sizeof(int), N, fp);
fclose(fp);
return(N, buffer,array);
}
`
Could someone please tell me why my program crashes and correct me.
If the file is empty we should have an array. If the file already contains an array, I should have two arrays concatenated.
Before allocating the buffer, read the current length from the file. Add N to that to get the size of the final resulting array, and use that in malloc(). Then you can use memcpy() to copy the new array to the end of the buffer after the old file contents.
To return the new N to the caller, pass this parameter as a pointer.
You need to call fopen() before you check if fp is null.
To return the new array of file contents, you have to declare the function to return int *, not void.
char *appendIntArray(char* filename, int* array, int *N){
FILE* fp = fopen(filename, 'rb');
if(!fp) {
return NULL;
}
int currentsize;
fread(&currentsize, sizeof(int), 1, fp);
int* buffer = (int*) malloc(sizeof(int)*(currentsize + *N));
if (!buffer) {
return array;
}
fread(buffer, sizeof(int), currentsize, fp);
fclose(fp);
fp = fopen(filename, "wb");
if (!fp) {
return NULL;
}
memcpy(&buffer[currentsize], array, N * sizeof(int));
*N += currentsize;
fwrite(N, sizeof(int), 1, fp);
fwrite(buffer, sizeof(int), *N, fp);
fclose(fp);
return buffer;
}

I want to save quantized int8 weights from a convolutional neural network, are my code edits in c correct?

Here is a post I made on the GitHub page: https://github.com/AlexeyAB/darknet/issues/1405#issuecomment-927394677
Here is all the source code: https://github.com/AlexeyAB/yolo2_light/tree/781983eb4186d83e473c570818e17b0110a309da/src
The closing bracket mistake is easy to fix. I noticed that I got outputs when I added an & to the multipliers. Is & the correct pointer for structs? I put the function in additionally.c, referenced it in additionally.h, and officially referenced it in main.c.
void save_weights_int8(network net, char *filename, int cutoff)
{
fprintf(stderr, "Saving weights to %s\n", filename);
FILE *fp = fopen(filename, "wb");
if(!fp) file_error(filename);
int major = 0;
int minor = 1;
int revision = 0;
fwrite(&major, sizeof(int), 1, fp);
fwrite(&minor, sizeof(int), 1, fp);
fwrite(&revision, sizeof(int), 1, fp);
fwrite(net.seen, sizeof(int), 1, fp);
int i;
for(i = 0; i < net.n && i < cutoff; ++i){
layer l = net.layers[i];
if(l.type == CONVOLUTIONAL){
//save_convolutional_weights(l, fp);
int num = l.n*l.c*l.size*l.size;
fwrite(l.biases, sizeof(float), l.n, fp);
fwrite(l.weights_int8, sizeof(uint8_t), num, fp);
fwrite(&l.weights_quant_multipler, sizeof(float), 1, fp);
fwrite(&l.input_quant_multipler, sizeof(float), 1, fp);
}
}
fclose(fp);
}

SHA - Output of program is different from sha512sum command

In summary, I program for first time with openssl/sha.h and everything goes right in compilation. here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <openssl/sha.h>
int main()
{
int j;
FILE *hash_file = fopen("hash.txt", "wb");
for(j = 0; j < 256; j++)
{
unsigned char md[SHA512_DIGEST_LENGTH];
char* fileName = malloc(sizeof(int));
sprintf(fileName, "%X%s", j, ".txt");
int i;
FILE *file = fopen(fileName, "rb");
SHA512_CTX mdcontext;
int bytes;
unsigned char data[2048];
if(file == NULL)
{
printf("%s can not be opened\n", fileName);
return;
}
SHA512_Init(&mdcontext);
while((bytes = fread(data, 1, 2048, file) != 0))
SHA512_Update(&mdcontext, data, bytes);
SHA512_Final(md, &mdcontext);
for(i = 0; i < SHA512_DIGEST_LENGTH; i++)
{
printf("%x", md[i]);
fprintf(hash_file, "%x", md[i]);
}
// fprintf(hash_file, "\n");
printf("\n");
free(fileName);
fclose(file);
}
fclose(hash_file);
return 0;
}
and I have this output :
711c22448e721e5491d8245b49425aa861f1fc4a15287f735e23799b65cffec5b5abdfddd91cd643aeb3b530d48f5e258e7e230a94ed525c1387bb4e1b
But when I hash same file with sha512sum command in Linux i got this output:
6e3ea4bec3cd738f06f011c2f4ee4f6cd6d12205cafe41c083d52f94d9de4ab8b9e702664a367b633be14024a96e88a140a2e7fee4dc2c6e2f0bd436e281e35b make.sh
what is the problem?
Oh boi!
A tiny little parantheses can make you pull your hair out.
The problem is in this statement while((bytes = fread(data, 1, 2048, file) != 0)). You see, in this statement the != condition will be evaluated first. So, when fread reads (and returns), let's say n number of characters, it checks if n!=0. If it evaluates to true then it sets bytes to 1 (true is casted to 1).
And now, the function SHA512_Update(&mdcontext, data, bytes); becomes SHA512_Update(&mdcontext, data, 1); while it should have been SHA512_Update(&mdcontext, data, n); (where n is the number of characters successfully read).
Solution
Change while((bytes = fread(data, 1, 2048, file) != 0)) to while((bytes = fread(data, 1, 2048, file)) != 0).
Update [Saving the hash in a char array]:
The output of SHA512 is of 128 characters. So, we need a char array of size twice that of SHA512_DIGEST_LENGTH (64). Then, we can just store it in the char array using sprintf.
char hash[SHA512_DIGEST_LENGTH*2];
for(i = 0; i < SHA512_DIGEST_LENGTH; i++)
sprintf(&hash[i*2], "%02x", md[i]);
Why i*2? Because output has a width of 2 bytes. So, result will be stored at hash[i] and hash[i+1].
Now, to print it:
for(i = 0; i < SHA512_DIGEST_LENGTH*2; i++)
printf("%c", hash[i]);
PS:
Read about precedence.
And don't forget to follow the advices in comments to your post, especially the one about using %02x by Steve.

Misunderstanding of binary file writing/reading in C

Can someone please explain why the following code segfaults whenever I attempt to do anything with either of the character arrays inside of the struct after I read it in from the binary file? The code is as follows:
struct my_struct {
int filename_len;
char *filename;
int size;
char *contents;
};
int main() {
FILE *fp = fopen("test.bin", "wb");
char *one = "list1";
char *two = "test file";
int one_len = strlen(one);
int two_len = strlen(two);
fwrite(&one_len, sizeof(int), 1, fp);
fwrite(&one, one_len, 1, fp);
fwrite(&two_len, sizeof(int), 1, fp);
fwrite(&two, two_len, 1, fp);
fclose(fp);
struct x *temp = malloc(sizeof(struct x));
fp = fopen("test.bin", "rb");
fread(&(temp->filename_len), sizeof(int), 1, fp);
fread(&(temp->filename), sizeof(char), temp->filename_len, fp);
fread(&(temp->size), sizeof(int), 1, fp);
fread(&(temp->contents), sizeof(char), temp->size, fp);
// This does not segfault
printf("%d\n", temp->filename_len);
// This does
printf("%s\n", temp->filename);
fclose(fp);
return 0;
}
Thank you!
fwrite(&one, one_len, 1, fp);
&one is the address of the pointer one on the stack, not the location it points to. This means that, instead of writing the string pointed to by one, you're writing the bytes that make up its address, potentially along with whatever happens to come after that in memory.
fread(&(temp->filename), sizeof(char), temp->filename_len, fp);
Similarly, this reads a pointer (or part of a pointer) into temp->filename, and may additionally overwrite whatever happens to be after it.
What you need to do is:
fwrite(one, one_len, 1, fp);
Write the actual contents of the string, not its address.
temp->filename = calloc(temp->filename_len + 1, sizeof(char));
fread(temp->filename, sizeof(char), temp->filename_len, fp);
Allocate a buffer sized appropriately for the filename, then read data into that buffer.
1) You are calling fread with the address of temp->filename.
fread(&(temp->filename), sizeof(char), temp->filename_len, fp)
You don't want to do this. temp->filename is already a pointer to a char. Instead pass simply temp->filename.
2) You aren't allocating any space for temp->filename. You need to do this after you read temp->filename_len.
fread(&(temp->filename_len), sizeof(int), 1, fp);
temp->filename = malloc((temp->filename_len + 1) * sizeof(char))
fread(temp->filename, sizeof(char), temp->filename_len, fp);
temp->filename[temp->filename_len] = '\0';
Similarly for temp->contents

C fwrite() writes amount of characters doubled

When I use this code
FILE *f = fopen(file, "wb");
fflush(f);
if (f==NULL) {
//perror(f);
return 0;
}
else{
fwrite(text, sizeof(char), strlen(text), f);
int i = fprintf(f, "%s", text);
if (i>0) {
fclose(f);
return 1;
}
(text is const char text[1024000], which is set as one of the arguments in the function)
if I write
This is a test
This is a test
to test if it can write multiple lines, it writes this
This is a test
This is a testThis is a test
This is a test
why do I get this weird behavior?
You're writing twice:
fwrite(text, sizeof(char), strlen(text), f);
int i = fprintf(f, "%s", text);
Pick one
These two lines write "text" twice. They do same thing.
fwrite(text, sizeof(char), strlen(text), f);
int i = fprintf(f, "%s", text);
The only difference is fprintf write one more byte '\0' than fwrite.

Resources