Hi All,

Thanks for all your help and advise. Here is a code for printing sales record. I don't understand what is the error in this code. When I try to complie and run, it says it cannot open the "sper.dat" file. Please help. Here is the 2 input files

sales.dat file

943 BusterBurger 4650000.00 1432567.88
245 PetRocks 8130000.00 95679.10

Salesper.dat file

Johnsonbaugh Epp IL 98450.00 29324.18 # 127 812
Cheessare Cruz TX 102300.00 15671.90 # 245 943

The output should be

Sales report by salesperson:

Salesperson: Chessare
Sales coach: Cruz
Sales region: TX
Base salary and bonus: 102300.00 15671.90
2 Account(s):

Name: PetRocks
Id: 245
Projected: 8130000.00
Actual: 95679.10

Name: BusterBurger
Id: 943
Projected: 4650000.00
Actual: 1432567.88

Salesperson: Johnsonbaugh
Sales coach: Epp
Sales region: IL
Base salary and bonus: 98450.00 29324.18
2 Account(s):

Name: AceRecords
Id: 127
Projected: 6780000.00
Actual: 2762890.50

Name: TacosAndThings
Id: 812
Projected: 2345000.00
Actual: 1412987.50

Here is the code

/***** BEGIN sales.h *****/

/** structure member macros **/
#define MaxName  (100) /* last name */  
#define MaxReg     (2) /* 2 character region code */      
#define MaxYear    (4) /* current year */
#define MaxAccs  (100) /* maximum number of accounts */ 

/** array sizes **/
#define MaxSales      (100)
#define MaxSalesPer   (100)

/** input file names **/
#define SalesFile    "sales.dat"
#define SalesPerFile "sper.dat"

/** miscellany **/ 
#define MaxBuffer  (500) /* input buffer */
#define AccDel     '#'   /* delimits accounts from other fields */

typedef struct sales {   
  int    accId;                  /* account id */   
  char   accName[ MaxName + 1 ]; /* account name */
  float  act;                    /* actual sales */
  float  proj;                   /* projected sales */
} Sales;

typedef struct salesPer { 
  Sales*  accs[ MaxAccs ];     /* accounts */  
  int     accCnt;              /* accounts count */
  char    name[ MaxName + 1 ]; /* salesperson */
  char    boss[ MaxName + 1 ]; /* supervisor */
  char    reg[ MaxReg + 1 ];   /* sales region */
  float   base;                /* base salary */
  float   bonus;               /* year to date */
} SalesPer;
 
/***** END sales.h *****/

/***** BEGIN sales.c *****/
#include <stdio.h>
#include <stdlib.h>  
#include <string.h>


/** arrays **/
Sales salesTbl[ MaxSales ];           /* sales by account */ 
Sales* salesPtr[ MaxSales ];          /* pointers to salesTbl */
SalesPer salesPerTbl[ MaxSalesPer ];  /* sales personnel */ 
SalesPer* salesPerPtr[ MaxSalesPer ]; /* pointers to salesPerTbl */

/** array counts **/                         
int salesCnt, salesPerCnt;
  
/** function declarations **/
void 
  readSales( const char* infile ),
  readSalesPer( const char* infile ),
  quicksort( void* array,
             size_t count,
             size_t size,
             int ( *comp )( const void* e1, const void* e2 ) ),
  report( void ); 
void* 
  findPivot( const void* array,
             size_t count,
             size_t size,
             int ( *comp )( const void* e1, const void* e2 ) );
int 
  partition( void* array, 
             size_t count, 
             size_t size, 
             int ( *comp )( const void* e1, const void* e2 ),
             void* pivot ),
  compAccId( const void* e1, const void* e2 ),
  compName( const void* e1, const void* e2 );
FILE* 
  openOrExit( const char* file, const char* mode );

main()
{                         
  /* read sales data and sort */
  readSales( SalesFile ); 
  quicksort( salesPtr, 
             salesCnt,
             sizeof ( salesPtr[ 0 ] ),
             compAccId );

  /* read salesperson data and sort */
  readSalesPer( SalesPerFile ); 
  quicksort( salesPerPtr,
             salesPerCnt,
             sizeof ( salesPerPtr[ 0 ] ),
             compName );  
          
  /* print sales report */
  report();             

  return EXIT_SUCCESS;
} 

/* Read data into array salesTbl and set SalesCnt */
void readSales( const char* infile )
{
  FILE* fptr; 
  int i = 0; 
  char buffer[ MaxBuffer + 2 ]; /* input buffer */
  
  fptr = openOrExit( infile, "rb" );
  salesCnt = 0;
  
  while ( fgets( buffer, MaxBuffer, fptr ) ) { 
    sscanf( buffer, "%d %s %f %f",
           &salesTbl[ i ].accId,
            salesTbl[ i ].accName,
           &salesTbl[ i ].act,
           &salesTbl[ i ].proj );
    i++;  
  } 
  fclose( fptr ); 
  salesCnt = i; 
  
  /* Set pointers in salesPtr to addresses of 
   * corresponding elements in salesTbl.
   */
  for ( i = 0; i < salesCnt; i++ )
    salesPtr[ i ] = &salesTbl[ i ]; 
}        
 
/* Read data into array salesPerTbl and set SalesPerCnt */
void readSalesPer( const char* infile )
{
  FILE *fptr;                  
  int i = 0, j;
  char* del;
  char id[ MaxName + 1 ];
  char buffer[ MaxBuffer + 2 ];  /* input buffer */ 
  Sales temp, *tempPtr = &temp, **ret;
  
  fptr = openOrExit( infile, "rb" );
  salesPerCnt = 0;
  
  while ( fgets( buffer, MaxBuffer, fptr ) ) { 
    /* Read basic fields. */
    sscanf( buffer, "%s %s %s %f %f",
            salesPerTbl[ i ].name,
            salesPerTbl[ i ].boss,  
            salesPerTbl[ i ].reg,
           &salesPerTbl[ i ].base,
           &salesPerTbl[ i ].bonus );
      
    /*** read account ids and set pointers to Sales structures ***/
    salesPerTbl[ i ].accCnt = 0; 
    j = 0;
    /* find accounts delimiter within buffer */ 
    del = strrchr( buffer, AccDel );
    del++;
    while ( *del && sscanf( del, "%s", id ) != EOF ) {
      tempPtr -> accId = atoi( id );  
      del += strlen( id ) + 1; /* move beyond current id */
      /* Search for sales record by account id. */
      if ( ret = bsearch( &tempPtr,
                          salesPtr, 
                          salesCnt, 
                          sizeof ( salesPtr[ 0 ] ),
                          compAccId ) ) {
        salesPerTbl[ i ].accCnt++; 
        salesPerTbl[ i ].accs[ j++ ] = *ret;
      }
    }
    i++; 
  } 
  fclose( fptr ); 
  salesPerCnt = i;
  
  /* Copy address of sales table entries 
   * into pointer array.
   */
  for ( i = 0; i < salesPerCnt; i++ )
    salesPerPtr[ i ] = &salesPerTbl[ i ]; 
}
    
/* Open file in specified mode, returning
 * file pointer if successfull; otherwise, 
 * issue warning message and exit program.
 */
FILE *openOrExit( const char* file, const char* mode )
{
  FILE *fptr;
  if ( NULL == ( fptr = fopen( file, mode ) ) ) {
    fprintf( stderr, 
             "!! Can't open %s in mode %s. Exiting. !!\n", 
             file, mode );
    exit( EXIT_SUCCESS );
  }
  return fptr;
} 

void quicksort( void* array,
                size_t count,
                size_t size,
                int ( *comp )( const void* e1, const void* e2 ) )
{ 
  void* pivot;
  int i;
   
  /* If array not yet sorted: 
   *   (1) find a pivot
   *   (2) partition into two subarrays, left and right
   *   (3) quicksort the left subarray
   *   (4) quicksort the right subarray
   */                                            
  if ( pivot = findPivot( array, count, size, comp ) ) {  
    i = partition( array, count, size, comp, pivot );
    quicksort( array, i, size, comp );  
    quicksort( ( char* ) array + i * size, count - i, size, comp );
  }   
} 

/* Return the larger of the first element and any
 * other that differs from it. If all elements the
 * same, return NULL.
 */
void* findPivot( const void* array,
                 size_t count,
                 size_t size,  
                 int ( *comp )( const void* e1, const void* e2 ) )
{
  int i = 1, flag;
  void* next;
  
  while ( i < count ) {  
    next = ( char* ) array + i * size;
    flag = comp( array, next );
    if ( flag > 0 )         /* array[ 0 ] > array[ i ] */ 
      return array;
    else if ( flag < 0 )    /* array[ i ] > array[ 0 ] */ 
      return next; 
    else                    /* array[ 0 ] == array[ i ] */
      i++;
  }      
  return NULL;  /* all elements the same */
}                                           

/* Partition an array into two subarrays, the first
 * holding elements <= pivot and the second holding
 * elements > pivot.
 */  
int partition( void* array, 
               size_t count, 
               size_t size,
               int ( *comp )( const void* e1, const void* e2 ),
               void* pivot )
{  
  int left = 0, right = count - 1, n = count;
  void* next;
  char temp[ MaxBuffer ];
  
  if ( size >= MaxBuffer ) {
    fprintf( stderr,
             "\n!! MaxBuffer too small. Exiting. !!\n\n" );
    exit( EXIT_SUCCESS );
  }              
  
  while ( left <= right ) { 

    /* Search from left to right for 1st element >= pivot. */  
    next = ( char* ) array + left * size;
    while ( left < n && comp( next, pivot ) < 0 ) { 
      left++;
      next = ( char* ) array + left * size;
    }

    /* Search from right to left for 1st element < pivot. */
    next = ( char* ) array + right * size;
    while ( right >= 0 && comp( next, pivot ) >= 0 ) { 
      right--;
      next = ( char* ) array + right * size;
    }   

    /* Swap current left and right elements to put them in
     * relative order with respect to each other and pivot.
     */
    if ( left < right ) {
      char *p1 = ( char* ) array + left * size,
           *p2 = ( char* ) array + right * size; 
      memcpy( temp, p1, size );
      memcpy( p1, p2, size );
      memcpy( p2, temp, size );  
      left++;
      right--;
    } 
  }                           
  return left;
}
          
int compAccId( const void* e1, const void* e2 )
{
  Sales
    *t1 = *( ( Sales** ) e1 ),
    *t2 = *( ( Sales** )  e2 );               
  return t1 -> accId - t2 -> accId;
}

int compName( const void* e1, const void* e2 )
{
  SalesPer
    *t1 = *( ( SalesPer** ) e1 ),
    *t2 = *( ( SalesPer** ) e2 );    
  return strcmp( t1 -> name, t2 -> name );
}     

void report( void )
{
  int i, j;
  
  printf( "\nSales report by salesperson:\n\n" );
  for ( i = 0; i < salesPerCnt; i++ ) {
    printf( "\n\tSalesperson:  %s\n", 
            salesPerPtr[ i ] -> name );
    printf( "\tSales coach:  %s\n", 
            salesPerPtr[ i ] -> boss );
    printf( "\tSales region: %s\n", 
            salesPerPtr[ i ] -> reg );
    printf( "\tBase salary and bonus:  %.2f  %.2f\n", 
            salesPerPtr[ i ] -> base, salesPerPtr[ i ] -> bonus );
    printf( "\t%d Account(s): \n", 
            salesPerPtr[ i ] -> accCnt );
    for ( j = 0; j < salesPerPtr[ i ] -> accCnt; j++ ) {
      printf( "\n" );
      printf( "\t\tName:       %s\n", 
              salesPerPtr[ i ] -> accs[ j ] -> accName );
      printf( "\t\tId:         %d\n", 
              salesPerPtr[ i ] -> accs[ j ] -> accId );
      printf( "\t\tProjected:  %.2f\n", 
              salesPerPtr[ i ] -> accs[ j ] -> proj );
      printf( "\t\tActual:     %.2f\n",
              salesPerPtr[ i ] -> accs[ j ] -> act );
    }
  }
}
/***** END sales.c *****/

> #define SalesPerFile "sper.dat"
Seems pretty obvious, this is the name you used inside the program. Simply change it to match the actual name you've given the file.

Thanks for the reply. The file name given in the program is same as that I created. But still it gives me the same error

Did you recompile it?
Is the file in the right directory?

Typically when running from the IDE, the programs idea of "current directory" can be different to what you get when running the program from the command line.

Dont u need return 0;? or is that only for console ah?

Returning EXIT_SUCCESS is usually 0, which is the value that should be returned to the operating system by a program to indicate success. However, since EXIT_SUCCESS is not guaranteed to be 0, the only way to be sure that your code is completely portable is to return 0 when the program exits.

Many people still try to use void main , which doesn't mean that the program doesn't return a value, it just returns some random junk. So void main() has never been correct.

> However, since EXIT_SUCCESS is not guaranteed to be 0
No, but whatever it's value it, it will be interpreted as success in the calling environment, even if that value is non-zero.

Even return 0; in your program can be converted into some non-zero success value in the host environment (if you're using a VAX say).

>the only way to be sure that your code is completely portable is to return 0 when the program exits.
EXIT_SUCCESS is completely portable. The language standard defines it as such, along with EXIT_FAILURE and 0.

>Crap, that's what I get for believing someone on another forum rather than using an official source.
That post was correct. You can portably depend on EXIT_SUCCESS meaning success, but you can't portably depend on the actual value being 0. Fun stuff, huh? ;)

Which is good, of course, in case some odd operating system decides that 74 is a good value to indicate success, and that 0 will be failure.

Thanks for all your reply. I still don't understand what is wrong in the program. Since iam trying to open a binary file, is there any special way to type the binary file. I have not come across binary file when learning C

When I try to complie and run, it says it cannot open the "sper.dat" file.

No such error for me, the program seems to have found the file, only to crash for the cause of segmentation error.

Are you really including your sales.h file in your sales.c file and are all the files in the same directory as your project is ?

This article has been dead for over six months. Start a new discussion instead.