Re: writing strings instead of rabish to file using fprintf

From: Thomas Matthews (Thomas_MatthewsSpitsOnSpamBots_at_sbcglobal.net)
Date: 05/21/04


Date: Fri, 21 May 2004 16:45:00 GMT

hpy_awad@yahoo.com wrote:
> I am writing stings ((*cust).name),((*cust).address)to a file using
> fgets but rabish is being wrote to that file ? Look to my source
> please and help me finding the reason why this rabish is being
> written.

Lew Pitcher has already posted an excellent reply, so I will
indicate some alternative methods for what you are doing.

>
>
> /* Book name :
> File name : E:\programs\cpp\iti01\ch10\ex09_5p1.cpp
Paths should not be inside files. Files don't know where they
are located. Their location may change without their knowledge.
If this file moves, then this comment will have to change.

> Program discription: Adding name,Address to customer_record SETUP
> PROGRAM
>
> */
> #include <conio.h>
This is a platform specific header file.
I suggest you do without it.

> #include <stdio.h>
> #include <stdlib.h>
> struct customer_record
> {
> int customer_no;
> int no_of_weeks;
> char tv_type;
> char name[40];
> char address[60];
>
> };
"Magic Numbers". That's what 40 and 60 are called above.
A common guideline is to use named constants:
#define MAX_NAME_LENGTH 40
#define MAX_ADDRESS_LENGTH 60

...
   char name[MAX_NAME_LENGTH];
   char address[MAX_ADDRESS_LENGTH];

Also, is tv_type a letter or just a small number or perhaps
an enumeration? If it is a number, use either int or unsigned
int. Unless you are writing code for a system that has a small
amount of memory, don't use short or char for numbers. For
many platforms, the processor is more efficient using int than
char or short.

If your no_of_weeks field cannot be negative, I suggest you
use an unsigned int. I haven't run across a occasion where
someone checked out a video for -2 weeks.

And similarly with customer number. However, some systems use
a negative customer number as an indicator. (Such as customer
doesn't exist anymore.)

>
> main()
> {
> clrscr();
No need to clear the screen. Also, on windowing platforms,
are you clearing the whole screen or the window?

> printf ("-----------------------------------------------------------------------------");
> printf ( "\nThis is run of program") ;
> printf ( "E:\programs\\cpp\\iti01\\ch09\\ex09_5p1.cpp\n");
> printf ( "
> -------------------------------------------\n");
>
Hey, try this one out:
   static const char program_header_text[] =
      "--------------------------------------------------\n"
      "This is run of program ex09_5p1.cpp\n"
      "--------------------------------------------------\n";
   fwrite(program_header_txt,
          sizeof(char), /* to be explicit */
          sizeof(program_header_text) - 1, /* don't write the '\0' */
          stdout);

or this:
   puts(program_header_text);

> void customer_input(struct customer_record *cust);
> struct customer_record customer;
> char another_customer;
>
> //open file for output
> FILE *fp_rental;
>
> if ((fp_rental=fopen("input","w"))==NULL)
To make your program easier to read, split this into more
lines:
   const char OUTPUT_FILENAME[] = "input";

   fp_rental = fopen(OUTPUT_FILENAME, "w");
   if (!fp_rental)
   {
     fprintf(stderr, "\nCannot open %s for output\n",
             OUTPUT_FILENAME);
     fprintf(stderr, "Program terminated.\n");
     return EXIT_FAILURE;
   }
Using a constant literal for the filename allows you to
only have to change one line when that filename is modified.

The main() is a function, so it must return a value.
Two defined values are EXIT_SUCCESS and EXIT_FAILURE, which
are defined in <stdlib.h>.

> {
> printf ("\n can not open 'input' for output");
> printf ("\n Program terminated");
> exit (0);
> }
>
> // do while more customers
>
> do {
> //input customer date
> customer_input(&customer);
> //write customer date to file
> fprintf(fp_rental,"%4d %2d %c %s %s",customer);
This should only be performed if the customer data is valid.

> printf("\n Another customer");
> scanf("\n");
> scanf("%c",&another_customer);
> } while ((another_customer)=='y');
     while ( toupper(another_customer) == 'Y');
or
     while (tolower(another_customer) == 'y');

> //write end of record
> fprintf(fp_rental,"%4d %2 d %c %s %s",9999,99,' ',' ',' ');
Magic Numbers and literals. Use named constants.

> //clsoe files
> fclose(fp_rental);
> return 0;
return EXIT_SUCCESS;

> }
>
>
>
>
>
> void customer_input(struct customer_record *cust)
> {
> printf("\n Enter customer number : ");
> scanf ("%4d",&(*cust).customer_no);
> printf("\n Enter number of weeks : ");
> scanf ("%2d",&(*cust).no_of_weeks);
> printf("\n Enter tv type : ");
> scanf ("\n");
> scanf ("%c",&(*cust).tv_type);
> printf("\n Enter customer name : ");
> scanf ("\n");
> //scanf ("%c",&(*cust).name);
> gets((*cust).name);
> printf("\n Enter customer address : ");
> scanf ("\n");
> //scanf ("%s",&(*cust).address);
> gets((*cust).address);
> }

The scanf function is evil, see the C language
FAQ below.

I suggest that if you have a special input function
for the customer_record, you have a complementary
output function also (and use it). Many programmers
and designers have one set of I/O functions for
file I/O and another for User Interface I/O.

As a matter of encapsulation, I suggest that you
place all of the customer functions into one
module. Create a header file that defines the
customer_record and declares the functions.

-- 
Thomas Matthews
C++ newsgroup welcome message:
          http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq:   http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
          http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
     http://www.josuttis.com  -- C++ STL Library book


Relevant Pages

  • Re: BIG BUG in Deleting detali records
    ... in the database in order to enforce referential integrity. ... when the customer himself is deleted from the master table. ... customerID int identity not null primary key, ...
    (borland.public.delphi.database.ado)
  • Re: Database Design Problem
    ... at your design that you would lose ProductCategoryID from the Orders table ... You should also have a customer and employee table and only include ... [EmployeeID [INT] ... You would also have primarykeys on OrderID in ORders and SerialNumber in ...
    (microsoft.public.sqlserver.programming)
  • Re: How to make a Foreing Key?
    ... Supose I have this tables DETAIL, HEADER and ITEMS and I want to add in the ... Should I ADD a field CUSTOMER in the table DETAIL to do that? ...
    (microsoft.public.sqlserver.programming)
  • Re: Table design teaser
    ... Why do STAFF and CUSTOMER have to be separate tables? ... > CUSTOMER (ID int pk, ... STAFF_CUSTOMER_MESSAGES (FromID int, ToID int) ...
    (microsoft.public.sqlserver.server)
  • Re: Table design teaser
    ... Drop the distinction between staff and customer. ... > CUSTOMER (ID int pk, ... STAFF_CUSTOMER_MESSAGES (FromID int, ToID int) ...
    (microsoft.public.sqlserver.server)