Unix Programming - problems reading struct from binary file

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > April 2005 > problems reading struct from binary file





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author problems reading struct from binary file
wetherbean

2005-04-22, 6:00 pm

Hey group..I was wondering if someone might be able to tell me what I
am doing wrong here..when I try to out put the string and teh int in my
struct after I read it from the binary file I create it just prints
garbage....here is my code so far

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


struct song_rec{
char* artist;
char* album;
int track;
int song_id;};

struct playlist_rec{
char* list_name;
int playlist_id;
int random;};

struct user_rec{
char* name;
int pw;};

int main(int argc,char**argv) {

FILE* user_file;
FILE* list_file;
FILE* song_file;
struct user_rec user;
int choice=0,found=0,password=0;
char* uname;


printf("1)REGISTER\n");
printf("2)LOGIN\n");
scanf("%d",&choice);


switch(choice){

case 1:
printf("Enter desired login name: ");
scanf("%s",uname);
user_file=fopen("user_file.dat","w");
fclose(user_file);
user_file=fopen("user_file.dat","r");

while(!feof(user_file)){
fread(&user,sizeof(user),1,user_file);
printf("name: %s password:
%d\n",user.name,ntohs(user.pw));
if (strcmp(uname,user.name)==0){
found=1;
printf("Login name already in use\n");
fclose(user_file);
exit(1);}
}//end while
if (found==0){
user_file=fopen("user_file.dat","a");
printf("Enter desired password: ");
scanf("%d",&password);
strcpy(user.name,uname);
user.pw=password;
fwrite(&user,sizeof(user),1,user_file);
fclose(user_file);}



break;
}
}


Thanks in advance,
wetherbean

Fletcher Glenn

2005-04-22, 6:00 pm

wetherbean wrote:
> Hey group..I was wondering if someone might be able to tell me what I
> am doing wrong here..when I try to out put the string and teh int in my
> struct after I read it from the binary file I create it just prints
> garbage....here is my code so far
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
>
> struct song_rec{
> char* artist;
> char* album;
> int track;
> int song_id;};
>
> struct playlist_rec{
> char* list_name;
> int playlist_id;
> int random;};
>
> struct user_rec{
> char* name;
> int pw;};
>
> int main(int argc,char**argv) {
>
> FILE* user_file;
> FILE* list_file;
> FILE* song_file;
> struct user_rec user;
> int choice=0,found=0,password=0;
> char* uname;
>
>
> printf("1)REGISTER\n");
> printf("2)LOGIN\n");
> scanf("%d",&choice);
>
>
> switch(choice){
>
> case 1:
> printf("Enter desired login name: ");
> scanf("%s",uname);
> user_file=fopen("user_file.dat","w");
> fclose(user_file);
> user_file=fopen("user_file.dat","r");
>
> while(!feof(user_file)){
> fread(&user,sizeof(user),1,user_file);
> printf("name: %s password:
> %d\n",user.name,ntohs(user.pw));
> if (strcmp(uname,user.name)==0){
> found=1;
> printf("Login name already in use\n");
> fclose(user_file);
> exit(1);}
> }//end while
> if (found==0){
> user_file=fopen("user_file.dat","a");
> printf("Enter desired password: ");
> scanf("%d",&password);
> strcpy(user.name,uname);
> user.pw=password;
> fwrite(&user,sizeof(user),1,user_file);
> fclose(user_file);}
>
>
>
> break;
> }
> }
>
>
> Thanks in advance,
> wetherbean
>

Your stuct contains pointers. Pointers are not valid things to store
as they may be different the next time you start your program. Instead
you need put the actual data into your struct.

--

Fletcher Glenn

Eric Sosman

2005-04-22, 6:00 pm



wetherbean wrote:
> Hey group..I was wondering if someone might be able to tell me what I
> am doing wrong here..when I try to out put the string and teh int in my
> struct after I read it from the binary file I create it just prints
> garbage....here is my code so far


You've got so many problems here that I lack the energy
to clean the Augean Stables. I'll just spend time on some
of the worst spots and maybe just draw attention to a few of
the others. "FAQ X.Y" means "Refer to Question X.Y in the
comp.lang.c Frequently Asked Questions (FAQ) list at
<http://www.eskimo.com/~scs/C-faq/top.html>."

> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
>
> struct song_rec{
> char* artist;
> char* album;
> int track;
> int song_id;};
>
> struct playlist_rec{
> char* list_name;
> int playlist_id;
> int random;};
>
> struct user_rec{
> char* name;
> int pw;};
>
> int main(int argc,char**argv) {
>
> FILE* user_file;
> FILE* list_file;
> FILE* song_file;
> struct user_rec user;
> int choice=0,found=0,password=0;
> char* uname;
>
>
> printf("1)REGISTER\n");
> printf("2)LOGIN\n");
> scanf("%d",&choice);


No success/failure check.

> switch(choice){
>
> case 1:
> printf("Enter desired login name: ");
> scanf("%s",uname);


FAQ 4.2, FAQ 12.20.


> user_file=fopen("user_file.dat","w");


No success/failure check. Also, if the "user_file.dat"
contained something before the program started, it doesn't
contain it any longer: You've just blown it away. Also
see FAQ 12.38 if you think there's any chance this program
might someday want to run on a non-POSIX system.

> fclose(user_file);
> user_file=fopen("user_file.dat","r");


No success/failure check. FAQ 12.38.

> while(!feof(user_file)){


FAQ 12.2.

> fread(&user,sizeof(user),1,user_file);


No success/failure check.

> printf("name: %s password:
> %d\n",user.name,ntohs(user.pw));


You've read (or tried to read) the `user' struct, but
where does its `name' element point? You certainly haven't
read anything it might point to. Also, ntohs() isn't much
of an encryption scheme (and your program doesn't declare it).

> if (strcmp(uname,user.name)==0){
> found=1;
> printf("Login name already in use\n");
> fclose(user_file);
> exit(1);}


EXIT_FAILURE would be preferable.

> }//end while
> if (found==0){
> user_file=fopen("user_file.dat","a");


No success/failure check. FAQ 12.38.

> printf("Enter desired password: ");
> scanf("%d",&password);


No success/failure check.

> strcpy(user.name,uname);


FAQ 4.2.

> user.pw=password;
> fwrite(&user,sizeof(user),1,user_file);


No success/failure check.

> fclose(user_file);}


No success/failure check.

>
>
> break;
> }
> }


Something seems to be missing here.

>
> Thanks in advance,
> wetherbean


Good luck! I think you're going to need it ...

--
Eric.Sosman@sun.com

John Gordon

2005-04-25, 5:53 pm

In <1114206403.315043.171110@f14g2000cwb.googlegroups.com> "wetherbean" <bjenkin1@gmail.com> writes:

> Hey group..I was wondering if someone might be able to tell me what I
> am doing wrong here..when I try to out put the string and teh int in my
> struct after I read it from the binary file I create it just prints
> garbage....here is my code so far


> struct song_rec{
> char* artist;
> char* album;
> int track;
> int song_id;};


Declaring your strings as "char *" isn't going to work. Declare them
like this instead:

char artist[99]; /* or whatever size you need */

> struct playlist_rec{
> char* list_name;
> int playlist_id;
> int random;};


> struct user_rec{
> char* name;
> int pw;};


Same thing here.

> int main(int argc,char**argv) {


> char* uname;


Same here. Declaring a char pointer doesn't actually allocate any space
for the string, so when you try to read in a value and store it, there
isn't anyplace for it to go, so it gets dumped somewhere random in memory.

For now, declare all your string data like this:

char uname[99];

If you keep using C, you will eventually learn why and how to use char
pointers, but for now, use char arrays.

--
John Gordon "It's certainly uncontaminated by cheese."
gordon@panix.com

Pascal Bourguignon

2005-04-25, 5:53 pm

"wetherbean" <bjenkin1@gmail.com> writes:

> Hey group..I was wondering if someone might be able to tell me what I
> am doing wrong here..when I try to out put the string and teh int in my
> struct after I read it from the binary file I create it just prints
> garbage....here is my code so far


You should consider using text files instead of binary files.

It's easy enough to use printf and scanf, and it's more portable, and
most often it's more space efficient (and speed doesn't count much
here since we're doing I/O which is 1,000,000 times slower than the
processor.

Warning: follows untested _C_ code. Error checking should be added!


-----(gen-c-struct.el)--------------------------------------------------

(defun field-name (f) (first f))
(defun field-type (f) (second f))

(defun generate-c-struct-declaration (name fields)
(insert (format "struct %s {\n" name))
(dolist (field fields)
(case (field-type field)
((string)
(insert (format " %-15s " "char*")))
((char short int long float double)
(insert (format " %-15s " (field-type field))))
(otherwise
(insert "#warning \"The following field won't be written or read.\"\n")
(insert (format " %-15s " (field-type field)))))
(insert (format "%s;\n" (field-name field))))
(insert "};\n"))

(defun generate-c-struct-reader (name fields)
(insert (format "struct %s* %s_read(FILE* in){\n" name name))
(insert (format " struct %s* res=malloc(sizeof(struct %s));\n" name name))
(dolist (field fields)
(case (field-type field)
((string)
(insert (format " res->%s=string_read(out);\n" (field-name field))))
((char short int)
(insert (format " {int buf;fscanf(out,\"%%d\",&buf); res->%s=buf;}\n"
(field-name field))))
((long)
(insert (format " {long buf;fscanf(out,\"%%ld\",&buf);res->%s=buf;}\n"
(field-name field))))
((float double)
(insert (format " {double buf;fscanf(out,\"%%e\",&buf);res->%s=buf;}\n"
(field-name field))))))
(insert (format" return(res);\n"))
(insert "}\n"))

(defun generate-c-struct-writer (name fields)
(insert (format "void %s_write(FILE* out,struct %s* that){\n" name name))
(dolist (field fields)
(case (field-type field)
((string)
(insert (format " string_write(out,that->%s);\n" (field-name field))))
((char short int)
(insert (format " fprintf(out,\"%%d\\n\",that->%s);\n"
(field-name field))))
((long)
(insert (format " fprintf(out,\"%%ld\\n\",that->%s);\n"
(field-name field))))
((float double)
(insert (format " fprintf(out,\"%%e\\n\",that->%s);\n"
(field-name field))))))
(insert "}\n"))

(defmacro gen-c-struct (name &rest fields)
`(progn (generate-c-struct-declaration ',name ',fields)
(generate-c-struct-reader ',name ',fields)
(generate-c-struct-writer ',name ',fields)))

-----(string_io.c)------------------------------------------------------

void string_write(FILE* out,const char* string){
fprintf(out,"%d:",strlen(string));
while(*string){
switch(*string){
case '"': fprintf(out,"\\\""); break;
case '\': fprintf(out,"\\\\"); break;
case '\n': fprintf(out,"\\n"); break;
default: fprintf(out,"%c",*string); break; }
string++;}
fprintf(out,"\n");}


char* string_read(FILE* in){
int length,i;
char* result;
fscanf(in,"%d:",&length);
result=malloc(1+length);
for(i=0;i<length;i++){
char ch=fgetc(in);
switch(ch){
case '\':
ch=fgetc(in);
switch(ch){
case '\n': result[i]='\n'; break;
default: result[i]=ch; break;}
break;
default: result[i]=ch; break;}}
result[length]='\0';
return(result);}

------(in your source.c)------------------------------------------------

/*
(progn
(load "gen-c-struct.el")
(insert "*") (insert "/\n\n")

(gen-c-struct song_rec
(artist string)
(album string)
(track int)
(song_id int))

(gen-c-struct playlist_rec
(list_name string)
(playlist_id int)
(random int))

(gen-c-struct user_rec
(name string)
(pw int)))

;; When you want to add or modify the structures, put the cursor
;; on the line above this comment and type C-x C-e.
;; It' insert the following:

*/

struct song_rec {
char* artist;
char* album;
int track;
int song_id;
};
struct song_rec* song_rec_read(FILE* in){
struct song_rec* res=malloc(sizeof(struct song_rec));
res->artist=string_read(out);
res->album=string_read(out);
{int buf;fscanf(out,"%d",&buf); res->track=buf;}
{int buf;fscanf(out,"%d",&buf); res->song_id=buf;}
return(res);
}
void song_rec_write(FILE* out,struct song_rec* that){
string_write(out,that->artist);
string_write(out,that->album);
fprintf(out,"%d\n",that->track);
fprintf(out,"%d\n",that->song_id);
}
struct playlist_rec {
char* list_name;
int playlist_id;
int random;
};
struct playlist_rec* playlist_rec_read(FILE* in){
struct playlist_rec* res=malloc(sizeof(struct playlist_rec));
res->list_name=string_read(out);
{int buf;fscanf(out,"%d",&buf); res->playlist_id=buf;}
{int buf;fscanf(out,"%d",&buf); res->random=buf;}
return(res);
}
void playlist_rec_write(FILE* out,struct playlist_rec* that){
string_write(out,that->list_name);
fprintf(out,"%d\n",that->playlist_id);
fprintf(out,"%d\n",that->random);
}
struct user_rec {
char* name;
int pw;
};
struct user_rec* user_rec_read(FILE* in){
struct user_rec* res=malloc(sizeof(struct user_rec));
res->name=string_read(out);
{int buf;fscanf(out,"%d",&buf); res->pw=buf;}
return(res);
}
void user_rec_write(FILE* out,struct user_rec* that){
string_write(out,that->name);
fprintf(out,"%d\n",that->pw);
}


Also, instead of putting emacs lisp code in comment in a c source file
to manually update the generated C source, one could put it in a
source.el file, and add some rules to the Makefile:

source.c:source.el
emacs -batch -load source.el

-----(source.el)--------------------------------------------------------
(load "gen-c-struct.el")
(find-file "source.c")
(erase-buffer)

(gen-c-struct song_rec
(artist string)
(album string)
(track int)
(song_id int))

(gen-c-struct playlist_rec
(list_name string)
(playlist_id int)
(random int))

(gen-c-struct user_rec
(name string)
(pw int)))

(save-buffer (current-buffer))
------------------------------------------------------------------------


(Of course, the text file format could be smarter, adding more green
bytes, with things such as lisp s-expressions (see both:
http://theory.lcs.mit.edu/~rivest/sexp.html
http://theory.lcs.mit.edu/~rivest/sexp.txt
) or even XML, which would ask for a parser. You can have fun!).


--
__Pascal Bourguignon__ http://www.informatimago.com/

The world will now reboot. don't bother saving your artefacts.
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com