I am learning fread and fwrite of c and made a basic code to write a structure using fwrite in a file . Output was there on the
#include<stdio.h>
int main()
{
FILE *f;
int i,q=0;
typedef struct {
int a;
char ab[10];
}b;
b var[2];
f=fopen("new.c","w");
printf("Enter values in structure\n");
for(i=0 ; i<2 ; i++)
{
scanf("%d",&var[i].a);
scanf("%s",var[i].ab);
}
fwrite(var,sizeof(var),1,f);
fclose(f);
return 0;
}
The output was not smooth as it contained weird characters inside the file. I opened the file in binary mode too but in vain. Is this some kind of buffer problem?
The "weird" characters inside your file are probably the bytes of the binary integers you're writing out. fwrite is writing the bits of var directly to the file, not converting that into a human readable format. If you want that, use fprintf instead.
Here's an example directly from your code above:
$ ./example
Enter values in structure
5 hello
8 world
$ hexdump -vC new.c
00000000 05 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 |....hello.......|
00000010 08 00 00 00 77 6f 72 6c 64 00 00 00 00 00 00 00 |....world.......|
00000020
Notice that the first four bytes at offset 0x00 and 0x10 are the numbers entered (little-endian and 32-bit because of my machine), followed by the strings entered, plus a bit of structure padding. All broken down:
File Offset Data (ASCII) Relationship to source
0 05 var[0].a 7:0
1 00 var[0].a 15:8
2 00 var[0].a 23:16
3 00 var[0].a 31:24
4 68 (h) var[0].ab[0]
5 65 (e) var[0].ab[1]
6 6c (l) var[0].ab[2]
7 6c (l) var[0].ab[3]
8 6f (o) var[0].ab[4]
9 00 (NUL) var[0].ab[5]
10 00 (NUL) var[0].ab[6]
11 00 (NUL) var[0].ab[7]
12 00 (NUL) var[0].ab[8]
13 00 (NUL) var[0].ab[9]
14 00 structure padding
15 00 structure padding
16 08 var[1].a 7:0
17 00 var[1].a 15:8
18 00 var[1].a 23:16
19 00 var[1].a 31:24
20 77 (w) var[1].ab[0]
21 6f (o) var[1].ab[1]
22 72 (r) var[1].ab[2]
23 6c (l) var[1].ab[3]
24 64 (d) var[1].ab[4]
25 00 (NUL) var[1].ab[5]
26 00 (NUL) var[1].ab[6]
27 00 (NUL) var[1].ab[7]
28 00 (NUL) var[1].ab[8]
29 00 (NUL) var[1].ab[9]
30 00 structure padding
31 00 structure padding
Related
Unexpected MAC-address value obtained using snprintf function
Why do I get "Unexpected mac-address value. I have big string (unsigned char data[DATA_LEN ]) to parse and copy mac address to the structure member. I am getting completely different string. Please help on this, Thank you.
Input data string:
unsigned char data[512] = "its-STRING: 18 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 12 00 20 00 00 00 C8 8C DF 9D 57 12 20 00 00 00 29 \n";
Output of the program
Parsed Mac from string = 8C DF 9D 57 12 20
copied MacAddress == 32:30:3a:33:38:00
From the above mentioned string i have to extract the mac-address "8C DF 9D 57 12 20"and then i have to copy this mac-address into the following structure
typedef struct my_stuct_s{
uint8_t mac_addr[18];
}my_stuct_t;
Below is how I have the coded.
#define PARSE_OFFSET 89
#define END_OFFESET 19
#define DATA_LEN 512
#define ADDR_LEN 6
typedef struct my_stuct_s{
uint8_t mac_addr[ADDR_LEN];
uint8_t item;
}my_stuct_t;
int main()
{
unsigned char data[DATA_LEN] = "its-STRING: 18 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 12 00 20 00 00 00 C8 8C DF 9D 57 12 20 00 00 00 29 \n";
unsigned char strv6[ADDR_LEN];
unsigned char *data1 = NULL;
my_stuct_t shm_memory;
memset(strv6, 0,sizeof(strv6));
memset(&shm_memory, 0,sizeof(my_stuct_t));
if ((strcmp(data, "") ) != 0)
{
data1 = &data[0];
data1 = data1 + PARSE_OFFSET;
snprintf(strv6, END_OFFESET,"%s\n", data1);
printf("Parsed Mac from string = %s\n", strv6);
snprintf((char *)&shm_memory.mac_addr, ADDR_LEN,
"%02x:%02x:%02x:%02x:%02x:%02x\n",
strv6[0], strv6[1],
strv6[2], strv6[3],
strv6[4], strv6[5]);
printf("copied MacAddress == %02x:%02x:%02x:%02x:%02x:%02x\n ",
shm_memory.mac_addr[0],
shm_memory.mac_addr[1],
shm_memory.mac_addr[2],
shm_memory.mac_addr[3],
shm_memory.mac_addr[4],
shm_memory.mac_addr[5]);
}
else
printf("\n empty string");
return 0;
}
Your parse offset starts at 89 and number of chars to be copied are 18.
#define PARSE_OFFSET 89
#define END_OFFESET 19
should be
#define PARSE_OFFSET 90
#define END_OFFESET 18
Length of the char array which stores the address should be 19.
unsigned char strv6[19];
You need to use sscanf not sprintf as below.
sscanf(strv6, "%02x %02x %02X %02x %02x %02x\n",
&shm_memory.mac_addr[0],
&shm_memory.mac_addr[1],
&shm_memory.mac_addr[2],
&shm_memory.mac_addr[3],
&shm_memory.mac_addr[4],
&shm_memory.mac_addr[5]);
I'm trying to read UTF file and decided to read it in binary mode and skip non-ASCII as file consists of valid english text basically. I'm stuck at fread returning 1 instead of number of bytes requested. First output of print_hex IMHO shows it has read more than 1 char. I've read some examples of reading binary files in C e.g Read and write to binary files in C?, read about fread e.g. here https://en.cppreference.com/w/c/io/fread and here How does fread really work?, still puzzled why it returns 1. File hexdump, and complete C code and output below.
ADD: compiled by gcc, run on Linux.
File:
00000000 ff fe 41 00 41 00 42 00 61 00 0d 00 0a 00 41 00 |..A.A.B.a.....A.|
00000010 41 00 45 00 72 00 0d 00 0a 00 66 00 73 00 61 00 |A.E.r.....f.s.a.|
00000020 6a 00 0d 00 0a 00 64 00 73 00 61 00 66 00 64 00 |j.....d.s.a.f.d.|
00000030 73 00 61 00 66 00 64 00 73 00 61 00 0d 00 0a 00 |s.a.f.d.s.a.....|
00000040 64 00 66 00 73 00 61 00 0d 00 0a 00 66 00 64 00 |d.f.s.a.....f.d.|
00000050 73 00 61 00 66 00 73 00 64 00 61 00 66 00 0d 00 |s.a.f.s.d.a.f...|
00000060 0a 00 0d 00 0a 00 0d 00 0a 00 |..........|
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_hex(const char *s)
{
while(*s)
printf("%02x ", (unsigned char) *s++);
printf("\n");
}
int main(){
#define files_qty 5
const char* files_array[][2]={{"xx","a"},{"zz","b"},{"xxx","d"},{"d","sd"},{"as","sd"}};
const char* file_postfix = ".txt";
char* file_out_name = "XXX_AD.txt";
FILE* file_out = fopen (file_out_name, "w");
printf ("This app reads txt files with hardcoded names and writes to file %s\n",file_out_name);
/* ssize_t bytes_read = 1; //signed size_t */
size_t n_bytes = 10;
unsigned char* string_in;
char* string_out;
char* file_name;
string_in = (char*) malloc (n_bytes+1);
string_out = (char*) malloc (n_bytes+50);
file_name = (char*) malloc (n_bytes+1); /* more error prone would be to loop through array for max file name length */
int i;
size_t n;
for (i=0;i<files_qty;i++)
{
strcpy (file_name,files_array[i][0]);
FILE* file = fopen (strcat(file_name,file_postfix), "rb");
if (file!= NULL)
{
int k=0;
while (n=fread (string_in, sizeof(char), n_bytes, file)>0)
{
printf("bytes read:%lu\n",(unsigned long) n);
print_hex(string_in);
int j;
for (j=0;j<n;j++)
{
switch (string_in[j])
{
case 0x00:
case 0xff:
case 0xfe:
case 0x0a:
break;
case 0x0d:
string_out[k]=0x00;
fprintf (file_out, "%s;%s;%s\n", files_array[i][0], files_array[i][1], string_out);
k=0;
printf("out:\n");
print_hex(string_out);
break;
default:
string_out[k++]=string_in[j];
}
}
}
fclose (file);
}
else
{
perror (file_name); /* why didn't the file open? */
}
}
free (string_in);
free (string_out);
free (file_name);
return 0;
}
Output:
bytes read:1
ff fe 41
bytes read:1
0d
out:
bytes read:1
72
bytes read:1
61
bytes read:1
73
bytes read:1
61
bytes read:1
0d
out:
72 61 73 61
bytes read:1
61
bytes read:1
73
bytes read:1
61
bytes read:1
0a
You have a precedence problem. Simple assignment has lower precedence than comparison. So the following line:
while(n=fread (string_in, sizeof(char), n_bytes, file)>0)
is evaluated as (extra parenthesis)
while (n=(fread (string_in, sizeof(char), n_bytes, file)>0))
Therefore n is being assigned as 1 because fread is returning a value > 0
Instead, explicitly add parenthesis as:
while((n=fread (string_in, sizeof(char), n_bytes, file))>0)
I have tried to look this up in multiple places and I cannot understand why fwrite doesn't work.
If I had a structure with 100 fields I would not want to use fprintf with 100 format specifiers.
struct emp
{
char name[15];
int age;
int salary;
char address[30];
};
int main()
{
char str[60];
struct emp emp1[5] = {{"Yoda",23,45000,"Asia"},{"Darth",34,2344,"NAmerica"},{"Jabba",22,5566,"Africa"},{"Luke",33,3399,"SAmerica"},{"Laya",44,6677,"Europe"}};
FILE *fp;
fp = fopen("C:/.../sampleText.txt","w");`
int i=0;
for(i=0; i<5; i++)
{
fwrite(&emp1[i],sizeof(emp1[i]),1,fp);
//fprintf(fp,"%s, %d, %d, %s\n",&emp1[i].name,emp1[i].age,emp1[i].salary,emp1[i].address);
}
fclose(fp);
getch();
}
There are two answers:
It does work, if everything is set correctly and porting the written data to other machines is not an issue.
It doesn't work if you have any of a large number of common features in data structures, or if you need to move the data from one type of machine (say an Intel machine) to another type (say PowerPC or SPARC).
In your example structure, you have no pointers, so you could write the structure verbatim to a file, and then in another invocation of the program running on the same (type of) machine, you could read it back in, and you would see the same data.
However, if your structure contained pointers, you could not meaningfully write the structure to disk. The pointers in one invocation of the program need not have any significance in another invocation of the program. If you needed to port the data between a little-endian (Intel) and big-endian (PowerPC, SPARC) machine, you'd have to use a platform-neutral way of accessing the data; simply writing the data to disk would not work.
So, where portability is not an issue, this code should work — Unix or Windows. It uses the "wb" and "rb" arguments to fopen() because the data is binary data, not plain text. The b is optional but harmless on Unix; it is crucial on Windows. The code also fixes the file name to sampledata.bin so it can be run on either platform, writing in the current directory. It writes the data; it then reads the data; it then compares the read data with the written data, reporting any problems. If the program says nothing, all is OK.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct emp
{
char name[15];
int age;
int salary;
char address[30];
};
int main(void)
{
char const filename[] = "sampledata.bin";
struct emp emp1[5] =
{
{ "Yoda", 23, 45000, "Asia" },
{ "Darth", 34, 2344, "N America" },
{ "Jabba", 22, 5566, "Africa" },
{ "Luke", 33, 3399, "S America" },
{ "Leia", 44, 6677, "Europe" },
};
struct emp emp2[5];
FILE *ifp;
FILE *ofp;
int i;
ofp = fopen(filename, "wb");
if (ofp != 0)
{
if (fwrite(emp1, sizeof(emp1), 1, ofp) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
exit(1);
}
fclose(ofp);
}
ifp = fopen(filename, "rb");
if (ifp != 0)
{
if (fread(emp2, sizeof(emp2), 1, ifp) != 1)
{
fprintf(stderr, "Failed to read from %s\n", filename);
exit(1);
}
fclose(ifp);
}
for (i = 0; i < 5; i++)
{
if (emp1[i].age != emp2[i].age ||
emp1[i].salary != emp2[i].salary ||
strcmp(emp1[i].name, emp2[i].name) != 0 ||
strcmp(emp1[i].address, emp2[i].address) != 0)
printf("Difference in record %d\n", i);
}
return 0;
}
Content of the file sampledata.bin:
0x0000: 59 6F 64 61 00 00 00 00 00 00 00 00 00 00 00 00 Yoda............
0x0010: 17 00 00 00 C8 AF 00 00 41 73 69 61 00 00 00 00 ........Asia....
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030: 00 00 00 00 00 00 00 00 44 61 72 74 68 00 00 00 ........Darth...
0x0040: 00 00 00 00 00 00 00 00 22 00 00 00 28 09 00 00 ........"...(...
0x0050: 4E 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00 N America.......
0x0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0070: 4A 61 62 62 61 00 00 00 00 00 00 00 00 00 00 00 Jabba...........
0x0080: 16 00 00 00 BE 15 00 00 41 66 72 69 63 61 00 00 ........Africa..
0x0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00A0: 00 00 00 00 00 00 00 00 4C 75 6B 65 00 00 00 00 ........Luke....
0x00B0: 00 00 00 00 00 00 00 00 21 00 00 00 47 0D 00 00 ........!...G...
0x00C0: 53 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00 S America.......
0x00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00E0: 4C 65 69 61 00 00 00 00 00 00 00 00 00 00 00 00 Leia............
0x00F0: 2C 00 00 00 15 1A 00 00 45 75 72 6F 70 65 00 00 ,.......Europe..
0x0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0110: 00 00 00 00 00 00 00 00 ........
0x0118:
You don't specify what you mean by fwrite doesn't work, but I'll assume you're working on Windows, in which case you need to specify "wb" to fopen. By default on Windows, it's writing in text mode (i.e. "wt").
not a good idea to write struct to file or sockets as it is. It is inviting complex to solve problems. the best approach is to use serialization before writing. Also, as Jim pointed out above, make sure to open the file in binary.
Take a look in this question and the answers. there is a pretty good answer and explanation for your question.
Passing a structure through Sockets in C
Data serialization is a non-trivial task. As some others have pointed out, it is possible in some cases to write the contents of your struct to disk as binary data. It's the simplest to write, but it is unlikely to be stable. Each time you recompile your code, it can potentially change the format the data is written and read in.
Your best option is to use a standard data interchange format, such as CSV, XML, or JSON. There are many existing tools to utilize these formats, so you should look into using one of them.
I thought this would be an easy task, after a couple of tries I try the tried and true write to a temp than reopen and rewrite:
#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE *f = fopen("main2.c","r");
FILE *t = fopen("temp","w");
int c;
int count = 0;
while((c = fgetc(f))!=EOF)
{
if(c)
{
fputc(c,t);
}
else
{
printf("null found\n");
}
}
fclose(f);
fclose(t);
FILE *n = fopen("main2.c","w");
FILE *w = fopen("temp","r");
while((c=fgetc(w))!=EOF)
{
fputc(c,n);
}
fclose(n);
fclose(w);
return 0;
}
this just spits out a bunch of chinese characters. Could the underlying character encoding be the issue? Or am I just a total noob here?
My hex editor won't let me copy/paste. I don't know how I can get the file up here in its original condition so I have it zipped in google docs let me know immediately if you cant get it:
https://docs.google.com/open?id=0B4UPOuCR5uRGZzJQZUpVaktKYlk
EDIT: wait wait here it is via HxE Edit:
FF FE 23 00 69 00 6E 00 63 00 6C 00 75 00 64 00 65 00 20 00 3C 00 73 00 74 00 64 00
6C 00 69 00 62 00 2E 00 68 00 3E 00 0D 00 0A 00 23 00 69 00 6E 00 63 00 6C 00 75 00 64 00
65 00 20 00 3C 00 61 00 6C 00 6C 00 65 00 67 00 72 00 6F 00 2E 00 68 00 3E 00 0D 00 0A 00
23 00 69 00 6E 00 63 00 6C 00 75 00 64 00 65 00 20 00 22 00 6D 00 6F 00
Open the files in binary mode:
FILE *f = fopen("main2.c","rb");
FILE *t = fopen("temp","wb");
Odds are that you are removing NULL bytes because the input is UTF-16 Unicode. If so, you also must remove the byte-order mark (BOM) at the start of the file. If the first two bytes are 0xFF, 0xFE then you have a little-endian UTF-16 file. Discard them! If you leave them in, every pair of ASCII characters in your source will be treated as a combined 16-bit character code. Strangeness will ensue.
Likewise if the first two bytes are 0xFE, 0xFF, the file is big-endian UTF-16 and you must also delete those two bytes, else the file will be treated as 16-bit codes again, only with high bytes first.
This is a very small portion of a large project...
These are typedefs defined in standard header file for the project.
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;
typedef uint8_t u_int8_t;
Now this is the actual function causing problem ...
void function(u_int8_t *data1, u_int32_t data1len,
u_int8_t *data2, u_int32_t data2len)
{
FILE *fq,*fr,*fs;
char *data3;
int data3len;
data3len=data1len+data2len;
printf("\n%d",data1len);
printf("\n%d",data2len);
printf("\n%d",data3len);
fq=fopen("data1.txt","wb");
fwrite((char *)data1,data1len,1,fq);
fr=fopen("data2.txt","wb");
fwrite((char *)data2,data2len,1,fr);
data3=(char *)data1;
strcat(data3,(char *)data2);
fs=fopen("data3.txt","wb");
fwrite((char *)data3,data3len,1,fs);
}
Some output Snapshots ...
40
14
54
udit#udit-Dabba ~$ hexdump -C data1.txt
00000000 60 00 00 00 00 8c 06 00 00 00 00 00 00 00 00 00 |`...............|
00000010 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 02 |........|
00000028
udit#udit-Dabba ~$ hexdump -C data2.txt
00000000 00 26 00 26 00 00 00 01 00 00 00 02 34 12 00 65 |.&.&........4..e|
00000010 00 34 00 00 61 62 63 64 |.4..abcd|
00000018
udit#udit-Dabba ~$ hexdump -C data3.txt
00000000 60 00 00 00 00 8c 06 00 00 00 00 00 00 00 00 00 |`...............|
00000010 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 02 00 78 f8 65 00 00 00 02 |.........x.e....|
00000030 f4 1f 96 00 18 34 a6 bf 1c 03 96 00 88 f1 90 08 |.....4..........|
00000040
Why contents of data2.txt are not copied to data3.txt ??? If there is any other possible way then please tell me !!!! Thanx in advance ...
Why contents of data2.txt are not copied to data3.txt?
strcat is specifically for concatenating C strings and only copies up until the null terminator character. So it stops copying from the source once it encounters 00 which it considers the end of the string. Notice how data2 begins with a 00, so it stops immediately.
You'll instead need to memcpy with the destination being 1 past the last byte in data3 and the source being data2. You'll also need to fail gracefully if data3 (which is really data1) does not have enough space to hold data2.
I think you could do it much easier, saving you from ensuring that the respective memory block is large enough.
void function(u_int8_t *data1, u_int32_t data1len,
u_int8_t *data2, u_int32_t data2len)
{
FILE *fq,*fr,*fs;
char *data3;
fq=fopen("data1.txt","wb");
fwrite((char *)data1, data1len, 1, fq);
fclose(fq);
fr=fopen("data2.txt","wb");
fwrite((char *)data2, data2len, 1, fr);
fclose(fr);
fs=fopen("data3.txt","wb");
fwrite((char *)data1, data1len, 1, fs);
fwrite((char *)data2, data2len, 1, fs);
fclose(fs);
}
You try to append data2 to the end of data1.
You intend to put the result into a third string (data3), but in fact data3 is just data1; they point to the same location.
Your code is equivalent to
strcat (data1, data2);
which of course writes beyond data1's end.
(there is another problem: if the caller of the function uses a "string_literal" as argument#1,
data1 will not be writable. )
You probably have to allocate some memory for the resulting string and make point data3 to it.