Understanding fseek() in C - c

I was learing File I/O in C and was interested in using it to read and write structures to files via fwrite() and fread() functions, now after my code ran successfully I was wondering if I could read a specific structure from an array of structures and put it in some given structure.
Here is my attempt at it
#include <stdio.h>
#include <stdlib.h>
typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;
void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}
int main() {
FILE * fp;
fp = fopen("file.txt", "rb+");
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i < 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = 'a';
a[i].toolname[1] = '\0';
a[i].quantity = 0;
a[i].recordno = i + 1;
}
for (int i = 0; i < 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when\
it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]
recordprinter(a[3]);
// this gives output 26 and not 51
return 0;
}
Now when I ran the programm I expected 51 a 0 0.00000 as output,
but to my surprise it is picking up the 26th structure and putting it in a[3]
Any help will be appritiated!!

Try changing fopen to use w+ instead of rb+
Also, remove the fseek when creating the file, as mentioned, fwrite definitely advances the file offset after writing data (provided fwrite does write data at all).
Here is the output observed using the modified code below.
gcc main.c
./a.out
51 a 0 0.000000
// main.c
#include <stdio.h>
#include <stdlib.h>
typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;
void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}
int main() {
FILE * fp;
// recommend for this example using w+
// w because it creates the file if the file doesn't exist
// r fails if the file doesn't exist (and that doesn't seem useful here)
// + because you are reading and writing
// avoiding b and choosing POSIX - linux
// may be wrong, if libc docs says b is needed then use b
// my doc "man fopen" says b is ignored
fp = fopen("file.txt", "w+");
// check return values, file pointer exist? fail if not
if (fp==NULL) { printf( "oops file not opened\n" ); return 1; }
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i < 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = 'a';
a[i].toolname[1] = '\0';
a[i].quantity = 0;
a[i].recordno = i + 1;
}
// alternative way to save 100 objects
// if ( fwrite(a, sizeof(tools), 100, fp) != 100 )
// {
// printf( "oops 100 objects not written to file\n" );
// return 1;
// }
for (int i = 0; i < 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
// remove fseek, not needed, fwrite does what is needed here
//fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when
// it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
// no review after this line, it seems to do what author intends
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]
recordprinter(a[3]);
// this gives output 51 as desired
return 0;
}

Related

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.

Writing to/reading from file using pointers, C

I've written a program to mess around with writing pointers into files(fwrite) and reading into pointers from files(fread). However the program doesn't seem to write a single thing into the file, nor does it seem to read anything from the file; it just prints the final incrementation of my pointer 5 times and exits. Can anyone spot the error/mistake in my syntax that seems to be doing this?
#include <stdio.h>
int main() {
FILE *fTest;
int *testPtr;
int x = 10;
if ((fTest = fopen("test.c", "wb")) == NULL) {
printf("Error!");
}
testPtr = &x;
int i;
for (i = 0; i < 5; i++) {
fwrite(testPtr, sizeof(int), 1, fTest);
*testPtr += 1;
}
for (i = 0; i < 5; i++) {
fread(testPtr, sizeof(int), 1, fTest);
printf("%d", *testPtr);
}
fclose(fTest);
}
Steps to take:
Write the data to the file.
Close the file.
Open the file again in read mode.
Read the data from the file.
That should work.
Also, the output file name, test.c, seems a bit strange. Is that on purpose?
#include <stdio.h>
int main() {
FILE *fTest;
int *testPtr;
int x = 10;
char const* file = "test.data"; // Using .data instead of .c
testPtr = &x;
int i;
// Write the data.
if ((fTest = fopen(file, "wb")) == NULL) {
printf("Error!");
}
for (i = 0; i < 5; i++) {
fwrite(testPtr, sizeof(int), 1, fTest);
*testPtr += 1;
}
fclose(fTest);
// Read the data.
if ((fTest = fopen(file, "rb")) == NULL) {
printf("Error!");
}
for (i = 0; i < 5; i++) {
fread(testPtr, sizeof(int), 1, fTest);
printf("%d", *testPtr);
}
fclose(fTest);
}
Left aside the fact that you don't check thre return value of fwrite() I would assume that you do write into "test.c", after you run the program the file should exist with a size of 5 * sizeof(int) bytes. But you can't read from it for two reasons:
you open the file write-only. Change "wb" to "w+b" to allow reading
after writing, you must reset the read-write pointer to the beginning of the file: call fseek(fTest, 0, SEEK_SET ); before reading
The problem is that you're reading from the file while it's opened in write mode.
Add this code between your write loop and read loop and it will work:
fclose(fTest);
if ((fTest = fopen("test.c", "rb")) == NULL) {
printf("Error!");
}

C: One pointer for reading and one pointer for updating the same file

I need to build a program that reads each record, and according to that record information would update some other records on the same file. For that, I was thinking in this approach:
int main(int argc, char *argv[]) {
FILE *my_file;
int files_read;
struct my_struct an_struct;
my_file = fopen("myfile.dat", "rb");
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("main->files_read: %d \n", files_read); //This prints one
while (files_read == 1) {
do_update();
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("main->files_read: %d \n", files_read); //This prints one
}
fclose(archivo_paises);
return 0;
}
In the main function I'm reading the contents of the file, and every time I call read I get one as a response until I reach the end of the file. The problem is in the do_update function:
void do_update() {
FILE *my_file;
int files_read;
struct my_struct an_struct;
struct my_struct another_struct;
my_files = fopen("myfile.dat", "wb+"); //Using rb+ solves it
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("do_update->files_read: %d \n", files_read);
//This printed zero!. Prints one using rb+
while (files_read == 1) { //This never gets executed. Unless you use rb+
if(something){
fwrite(&another_struct, sizeof(struct my_struct), 1, my_file);
// Using rb+, this returns zero and didn't update
}
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("do_update->files_read: %d \n", files_read);
}
fclose(my_file);
}
What's happening is that the files_read variable gets the value of zero after the read call, so the logic to update the file is never executed.
Why is read returning zero when opening a file for wb+?
Update:
Using rb+ as file mode on do_update() works, but now the call to fwrite() always returns zero, and it didn't update the file. Is is related to the mode?
fwrite is moving the position in the file to the end of the file. The fread then has nothing to read.
Use fgetpos to save the file position before the fwrite, and fsetpos to set the position back after the fwrite.
The meaning of the flag "w+" (from http://www.cplusplus.com/reference/cstdio/fopen/):
write/update: Create an empty file and open it for update (both for input and output). If a file with the same name already exists its contents are discarded and the file is treated as a new empty file.
When you open a file with "w+", you will need to write to it first before you can read from it.
Update
Example program to demonstrate use of "rb+".
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void createFile(char const* filename, int num)
{
int i = 0;
int data = 0;
FILE* out = fopen(filename, "wb");
if ( out == NULL )
{
return;
}
for (i = 0; i < num; ++i )
{
data = rand()/10000;
fwrite(&data, sizeof(data), 1, out);
}
fclose(out);
}
void displayFileContents(char const* filename, int num)
{
int i = 0;
int data = 0;
FILE* in = fopen(filename, "rb");
if ( in == NULL )
{
return;
}
for (i = 0; i < num; ++i )
{
fread(&data, sizeof(data), 1, in);
printf("%d\n", data);
}
fclose(in);
}
void testReadAndWrite(char const* filename, int num)
{
int i = 0;
int data = 0;
long int pos = 0;
FILE* in = fopen(filename, "rb+");
if ( in == NULL )
{
return;
}
for ( i = 0; i < num; ++i )
{
pos = ftell(in);
fread(&data, sizeof(data), 1, in);
printf("%d\n", data);
// Rewind to previos position.
fseek(in, pos, SEEK_SET);
// Write at the previus position.
data = rand();
printf("%d\n", data);
if ( fwrite(&data, sizeof(data), 1, in) != 1 )
{
printf("Unable to write using fwrite.\n");
}
// Rewind to previos position.
fseek(in, pos, SEEK_SET);
// Read from the previus position.
if ( fread(&data, sizeof(data), 1, in) != 1 )
{
printf("Unable to read using fread.\n");
}
printf("%d\n\n", data);
}
fclose(in);
}
int main()
{
char const* filename = "test.txt";
int num = 10;
// See the random number generator.
srand(time(NULL));
// Create a file with some random data.
createFile(filename, num);
// Display the contents of the file.
displayFileContents(filename, num);
printf("\n");
// Test read and write using a single FILE*
testReadAndWrite(filename, num);
}
Sample output:
51830
169074
141071
61921
145333
101195
139074
9535
164668
49552
51830
1030292590
1030292590
169074
1003635396
1003635396
141071
1060541073
1060541073
61921
474399692
474399692
145333
1467401071
1467401071
101195
830521014
830521014
139074
1186142943
1186142943
9535
1759682963
1759682963
164668
848798825
848798825
49552
60932215
60932215

Unclear reading file in C

I tried cyclically read file in buffer of 100 byte.
When i read file first time - buffer was full. Returned value is 0. No error and no eof (functions "ferror" and "feof" shows no error). Then i tried read file second time and again returned value is 0, no error and no eof. But then i have empty buffer. I don't know what is the problem?
if(fopen_s(&file_in, argv[1], "rb") == 0){
printf("File was opened.\n");
while(!feof(file_in)){
read_code = fread_s(file_data, 100, sizeof(unsigned char), 100, file_in);
if(ferror(file_in)) {
printf("Error!\n");
}
if(feof(file_in)) {
printf("Eof!\n");
}
printf("Read result: %d\n", read_code);
/*Using the buffer*/
memset(file_data, 0, 100);
}
fclose(file_in);
}
For the reasons given in comments regarding fopen_s, et. al., Here is an alternative implementation of reading a binary file using getc(), along with fopen(), fclose(), etc. (I am not using a Microsoft implementation, but am using ANSI C99)
It has a commented section I used to create a test binary file. Other than that it sizes the file you are reading so you can allocate the right amount of memory, then reads the binary data into a buffer.
For navigating your file, take a look at fseek() with its stdio.h defined arguments:
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
In this example, everything is closed or freed before exiting:
#include <windows.h>
#include <ansi_c.h>
long int getFileSizeFromPath(char * path)
{
FILE * file;
long int fileSizeBytes = 0;
file = fopen(path,"r");
if(file){
fseek(file, 0, SEEK_END);
fileSizeBytes = ftell(file);
fseek(file, 0, SEEK_SET);
fclose(file);
}
return fileSizeBytes;
}
int main(int argc, char *argv[])
{
FILE *fp=0;
char *binBuf;
long int size=0;
int i=0;
int byte=0;
//create 100 byte test file (c:\\dev\\tessst.bin)
// fp = fopen(argv[1], "wb");
//
// srand(clock());
// for(i=0;i<100;i++)
// {
// byte = rand();
// putc(byte, fp);
// }
// putc(EOF, fp);
//
// fclose(fp);
size = getFileSizeFromPath(argv[1]);
binBuf = calloc(size + 1, sizeof(char));
fp = fopen(argv[1], "rb");
byte = getc(fp);
while(byte != EOF)
{
binBuf[i++] = (char)byte;
byte = getc(fp);
}
fclose(fp);
free(binBuf);
return 0;
}

i need to copy bitmap image file in c language using a buffer

i have to copy a bitmap image file using a buffer.
here is an example of what i need to do.
i have to read different parts of a bitmap into the buffer first at once and then write it to the target file.
when i read different parts into the buffer , the previous string gets overwritten and the last string that is read is only written. i dont want to use read and write function for every part that has to be written.
please help me with the code.
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
void fskip(FILE *fp, int num_bytes) {
int i;
for (i = 0; i < num_bytes; i++)
fgetc(fp);
}
int main() {
FILE *fp, *fp1;
fp = fopen("c:\\users\\tapan\\desktop\\splash.bmp", "rb");
fp1 = fopen("c:\\users\\tapan\\desktop\\splash2.bmp", "wb");
int *j;
j = (int *)malloc(3000);
int k = 223121;
int *i = &k;
fread(j, 2, 1, fp);
fread(j, 10, 1, fp);
fwrite(j, 12, 1, fp1);
fclose(fp1);
fclose(fp);
getch();
}
First of all, I will try to address your specific question and avoid any comments about other things in the code.
It looks like the fread() and fwrite() statements are not correct. The following code might be more exact.
int main() {
FILE *fp, *fp1;
fp = fopen("c:\\users\\tapan\\desktop\\splash.bmp", "rb");
fp1 = fopen("c:\\users\\tapan\\desktop\\splash2.bmp", "wb");
int *j;
j = (int *) malloc(3000);
int k = 223121;
int *i = &k;
// read 2 items of sizeof(int) into j from fp
fread(j, sizeof(int), 2, fp);
// read 10 items of sizeof(int) into j + 2 from fp
fread(j+2, sizeof(int), 10, fp);
// write 12 items of sizeof(int) from j to fp1
fwrite(j, sizeof(int), 12, fp1);
fclose(fp1);
fclose(fp);
getch();
}
// Note. The above code has NOT been tested, it is thrown-up here for discussion.
Format of fread() and fwrite() is per K&R, second edition, page 247.

Resources