i'm trying to write a structure to a dat file, everything works fine but the data in the dat file turns into random characters (it's the same in other formats like txt)
#include <stdio.h>
#include <string.h>
struct Product
{
char ProId[20];
char ProName[30];
float Price;
int Quantity;
int CatId;
};
int main(){
FILE *f;
f = fopen ("Product.dat", "w+");
if (f == NULL)
{
fprintf(stderr, "\nError opened file\n");
}
Product p1;
strcpy(p1.ProId, "1");
strcpy(p1.ProName, "Candy");
p1.Price = 4.5;
p1.Quantity = 5;
p1.CatId = 1;
fwrite(&p1, sizeof(p1), 1, f);
fclose(f);
return(0);
}
The data in Product.dat:
1 u ÿÿÿÿCandy Ù$# #
I tried searching for this error but to no avail. Please help me, what is wrong?
Thank you.
I compile and ran your code on my WSL2, and met the same problem, here is the hexdump:
00000000 31 00 00 00 00 00 00 00 e7 6a 5b 66 fd 7f 00 00 |1........j[f....|
00000010 e6 6a 5b 66 43 61 6e 64 79 00 d4 1a 18 56 00 00 |.j[fCandy....V..|
00000020 e8 32 96 dd 70 7f 00 00 80 12 d4 1a 18 56 00 00 |.2..p........V..|
00000030 00 00 00 00 00 00 90 40 05 00 00 00 01 00 00 00 |.......#........|
The string "Candy" is indeed copied to the struct.
I assume the reason it is polluted by some trash data is because this struct is allocated on stack.
So I made a clean up after the declaration of this struct, and here is the effect:
00000000 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |1...............|
00000010 00 00 00 00 43 61 6e 64 79 00 00 00 00 00 00 00 |....Candy.......|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 90 40 05 00 00 00 01 00 00 00 |.......#........|
Here is the code I modified, note the call to memset():
#include <stdio.h>
#include <string.h>
struct Product
{
char ProId[20];
char ProName[30];
float Price;
int Quantity;
int CatId;
};
int main(){
FILE *f;
f = fopen ("Product.dat", "w+");
if (f == NULL)
{
fprintf(stderr, "\nError opened file\n");
}
struct Product p1;
memset(&p1, 0, sizeof(p1));
strcpy(p1.ProId, "1");
strcpy(p1.ProName, "Candy");
p1.Price = 4.5;
p1.Quantity = 5;
p1.CatId = 1;
fwrite(&p1, sizeof(p1), 1, f);
fclose(f);
return(0);
}
Related
I have an assignment that I need to create a program to read (in binary mode) a file and then display them out on the screen. I run it in the command line mode. Here is my source code:
#include <stdio.h>
#include <stdlib.h>
#define MAXWORD 130
typedef struct Node node;
struct Node
{
int stt;
char name[50];
char phonenumber[20];
char email[50];
};
int checktoread(FILE *datain)
{
return (datain == NULL);
}
int readfile(FILE *datain, node *item)
{
int i = 0;
while(fread(&item[i], sizeof(node), 1, datain)>0)
{
i++;
}
return i;
}
void display(node *item, int max)
{
int i = 0;
for(; i < max; i++)
{
printf("%-3d%-30s%-20s%-30s\n", item[i].stt, item[i].name, item[i].phonenumber, item[i].email);
}
}
int main(int argv, char *argc[])
{
if (argv != 2)
{
printf("Wrong syntax\nCorrect Syntax: readfile <source file>\n");
exit(1);
}
FILE *fp = fopen(argc[1], "rb");
if(checktoread(fp))
{
printf("The source file is unable to be opened\n");
exit(1);
}
node *person = (node*) malloc(30*sizeof(person));
int maxline = readfile(fp, person);
printf("%d\n", maxline);
display(person, maxline);
fclose(fp);
free(person);
return 0;
}
My problem is this file do not return or display anything. There is no syntax error here, I confirm. I don't know where I get wrong. Actually, I think it get wrong in the step that convert data from a file into an array.
The file starts like this
0 1 2 3 4 5 6 7 8 9 A B C D E F
0000:0000 01 00 00 00 4A 6F 65 79 4D 61 74 68 65 6C 00 00
0000:0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0060 00 00 00 00 00 00 00 00 30 33 38 35 37 38 38 30
0000:0070 36 30 00 00 00 00 00 00 00 00 00 00 6A 6F 65 79
0000:0080 6D 61 74 68 65 6C 40 67 6D 61 69 6C 2E 63 6F 6D
0000:0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00E0 02 00 00 00 53 63 6F 74 74 79 4A 61 63 6B 00 00
0000:00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I am trying to read the contents of a binary file into a struct, but each time I print out the contents of my struct, I get a pretty strange output. Below is the struct I am trying to set:
struct student {
char name[32];
unsigned int age;
SEX sex;
float gpa;
struct course *courses;
struct student *next;
}
With the course struct defined as:
struct course {
char grade;
unsigned int number;
struct course *next;
}
And SEX defined as:
typedef enum _SEX {MALE = 'M', FEMALE = 'F', OTHER = 'O'} SEX;
Right now, my function is as follows:
void read_bin(char *filename){
FILE *file;
struct student myStudent;
file = fopen(filename, "rb");
if(file == NULL){
printf("Unable to open file!");
return;
}
fread(&myStudent, sizeof(struct student), 1, file);
printf("\nName: %s, Age: %d", myStudent.name, myStudent.age);
fclose(file);
}
But I keep on getting this strange output:
Age: 0
With name not even showing up and age set to an incorrect number. I thought this might be due to padding, so I tried using
fread(&myStudent.name, sizeof myStudent.name, 1, file);
fread(&myStudent.age, sizeof myStudent.age, 1, file);
So that it reads each individual element and pads as needed. However, I get the same output. When I ran hexdump to see what exactly I was dealing with, this is what came out:
f0 0d 03 00 00 00 46 72 65 64 00 00 00 00 00 00 |......Fred......|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 1d 00 00 00 4d 00 00 00 cd cc |..........M.....|
4c 40 01 00 00 00 44 02 00 00 41 4a 6f 65 00 00 |L#....D...AJoe..|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 4d |...............M|
00 00 00 33 33 73 40 03 00 00 00 6e 00 00 00 42 |...33s#....n...B|
dc 00 00 00 41 54 01 00 00 41 53 61 72 61 68 00 |....AT...ASarah.|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 00 00 00 00 16 00 00 00 46 00 |..............F.|
00 00 00 00 40 40 03 00 00 00 78 00 00 00 42 dc |....##....x...B.|
00 00 00 41 4a 01 00 00 43 |...AJ...C|
Any help would be greatly appreciated -- I've been stuck on this function for awhile.
Depending on the filetype the first few bytes can be a fileheader, here information can be stored like version numbers, length of the data etc.
As for the pointers, that won't work like others pointed out since pointers are adresses, not actual relevant data.
You want to fseek to sizeof(fileheader), before you start reading the file.
Also be wary that structs are padded in C and that the order in which you declared the elements in the struct might not be the order the compiler decided for it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NBRCOLOURS 16
#define COLOURSIZE 8
typedef struct
{
char colours[COLOURSIZE];
}BITMAP;
//Main Function
void main(void)
{
int count, count2;
char bm_file[] = "C:\\Coding\\Bitmap Program\\Sample.bmp";
FILE *fptr;
char ch;
int i = 0;
BITMAP bm_data[NBRCOLOURS];
fptr = fopen(bm_file, "rb");
if (fptr != NULL)
{
while ((ch = fgetc(fptr)) != EOF)
{
printf("%02X ", ch);
if (!(++i % 16)) putc('\n', stdout);
}
}
fclose(fptr);
system("pause");
return;
}
I am using this code which I found mostly online to try and read the contents of a bitmap file as its hexadecimal values. For some reason, this code stops right at the end of the header, and unfortunately ultimately I need to count the number of times each colour appears so that I can figure out which occurs most and which occurs least.
If anyone could tell me why this code stops at the end of the header for the bitmap, or lead me towards being able to pull the rest of the hexadecimal data out of the file, I would really appreciate it.
Here is the hex code:
42 4D C6 00 00 00 00 00 00 00 76 00 00 00 28 00
00 00 0A 00 00 00 0A 00 00 00 01 00 04 00 00 00
00 00 50 00 00 00 12 0B 00 00 12 0B 00 00 10 00
00 00 10 00 00 00 FF 00 00 00 00 FF 00 00 00 00
42 00 5A 5A 84 00 00 00 FF 00 FF 00 FF 00 00 FF
FF 00 08 FF FF 00 5A FF FF 00 FF FF FF 00 FF FF
FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF
FF 00 FF FF FF 00 92 59 00 16 47 00 00 00 25 90
01 64 61 00 00 00 59 90 11 64 61 00 00 00 99 00
16 48 11 00 00 00 90 01 64 61 11 00 00 00 00 16
64 61 00 00 00 00 01 16 46 10 09 00 00 00 11 64
41 00 99 00 00 00 16 64 11 09 95 00 00 00 66 48
10 09 53 00 00 00
And here is what prints:
42 4D FFFFFFC6 00 00 00 00 00 00 00 76 00 00 00 28 00
00 00 0A 00 00 00 0A 00 00 00 01 00 04 00 00 00
00 00 50 00 00 00 12 0B 00 00 12 0B 00 00 10 00
00 00 10 00 00 00
Long post, I'm sorry. Any help is greatly appreciated.
fgetc returns an int, not a char. You can't represent EOF with a char, as all of the possible values of a char are valid. EOF is (I think) -1 represented as an int, or 0xfffffff, so if you read 0xff as a char it's the same as EOF.
Change this:
char ch;
to:
int ch;
The number before a format specifier in printf, like %02X only guarantees a minimum number of characters outputted, not a maximum. fgetc returns an int, not a char. If the int is negative two's complement then the entire bitstring representing the int will get printed, including the FF bytes at the start. EOF is not representable as a char; only as an int.
In your case we know that the file we're working with is small enough that loading the entire file into a buffer will probably succeed, so we can just use malloc and free instead:
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char byte;
int main(int argc, char *argv[])
{
FILE *fp = fopen("C:\\Coding\\Bitmap Program\\Sample.bmp", "rb");
byte *buffer = NULL;
size_t len;
int i;
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
buffer = malloc(len);
if(!buffer)
{
perror("malloc");
exit(EXIT_FAILURE);
}
fread(buffer, 1, len, fp);
fclose(fp);
for(i = 0; i < len; i++)
{
if(i%16==0) putchar('\n');
printf("%.2X ", buffer[i]&0xFF);
}
free(buffer);
return 0;
}
I have a C server that uses libwebsockets and I want to save a received audio stream in a file on disk.
Here is my code snippet:
#define FILENAME "/home/ubuntu/Desktop/file.wav"
FILE *received_file;
struct lws_context *Audiocontext;
static int callback_audio(
struct lws *wsi,
enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
{
printf("client is connected\n");
received_file = fopen(FILENAME, "w+");
if (received_file == NULL)
{
printf("Failed to open file\n");
exit(EXIT_FAILURE);
}
}
break;
case LWS_CALLBACK_RECEIVE: {
if(strcmp((char*)in,"EOS")==0)
{
printf("End of stream!\n");
fclose(received_file);
}
else
{
fwrite(in, 1, len, received_file);
}
}
}
}
I got the message "client is connected" and also the file, but the content isn't ok, I cannot play it. I think there is a problem regarding the way I save the stream on file using fwrite().
The client is sending audio chunks encoded as wav, 16Khz, mono. Here is a snippet from client (it's a javascript client, the full code is here:http://kaljurand.github.io/dictate.js/).
if (recorder) {
recorder.stop();
config.onEvent(MSG_STOP, 'Stopped recording');
// Push the remaining audio to the server
recorder.export16kMono(function(blob) {
socketSend(blob);
socketSend(TAG_END_OF_SENTENCE);
recorder.clear();
}, 'export16kMono');
config.onEndOfSpeech();
} else {
config.onError(ERR_AUDIO, "Recorder undefined");
}
The client is working well, I use it for exactly the same task, but using a Java server. I would appreciate if someone could indicate me how to save these audio chunks in a valid file.
I think that you do not write header in your wav file. To do so,
you can write some function to do so see specification here
or you can use a dedicaded library, like libsndfile, which is not so complicated to use:
// instead of fopen, write something like
SF_INFO info;
SNDFILE * sf;
info.samplerate = sample_rate;
info.channels = 1;
info.sections = 1;
info.seekable = 0;
info.frames = 0;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
sf = sf_open(filename, SFM_WRITE, &info);
// instead of fwrite, something like
sf_write_short(sf, in, len / sizeof(short));
// and instead of fclose
sf_close(sf);
I didn't use libsndfile, but I change something on the client side. This is the current hexdump output:
00000000 52 49 46 46 20 60 00 00 57 41 56 45 66 6d 74 20 |RIFF `..WAVEfmt |
00000010 10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00 |........D.......|
00000020 04 00 10 00 64 61 74 61 00 60 00 00 00 00 00 00 |....data.`......|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00006020 00 00 00 00 00 00 00 00 00 00 00 00 52 49 46 46 |............RIFF|
00006030 20 60 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 | `..WAVEfmt ....|
00006040 01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 |....D...........|
00006050 64 61 74 61 00 60 00 00 00 00 00 00 00 00 00 00 |data.`..........|
00006060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0000c050 00 00 00 00 00 00 00 00 52 49 46 46 20 60 00 00 |........RIFF `..|
0000c060 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00 |WAVEfmt ........|
0000c070 44 ac 00 00 10 b1 02 00 04 00 10 00 64 61 74 61 |D...........data|
0000c080 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.`..............|
0000c090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
It seems to be wav encoded, but i don't have a content.
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.