-1

My program needs to take people's input and calculate salary and withholds and print all of it out. I have the print outs but I'm having trouble storing it in the array.

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

typedef char *string;

#define MaxEmployees 100

typedef struct {
    string name;
    string title;
    string ssnum;
    double salary;
    int withholding;
} employeeRecordT;

typedef struct {
    string name;
    string title;
    string ssnum;
    double salary;
    int withholding;
} *employeeT;

Type: payrollT

This type represents an entire collection of employees. The type definition uses a dynamic array of employeeT values to ensure that there is no maximum bound imposed by the type. The cost of this design is that the programmer must explicitly allocate the storage for the array using NewArray.

typedef struct {
    int nEmployees;
    employeeT *employees;
} *payrollT;

Global variables

staff       -- Array of employees  
nEmployees  -- Number of employees  
manager     -- Used to produce a figure for the code
static employeeT staff[MaxEmployees];
static int nEmployees;

static employeeRecordT manager = {
    "Ebenezer Scrooge", "Partner", "271-82-8183", 250.00, 1
};

Private function declarations:

 static void InitEmployeeTable(void);
 static payrollT CreatePayroll(employeeT staff[], int nEmployees);
 static void ListEmployees(payrollT payroll);
 static double AverageSalary(payrollT payroll);
 static void  WeeklyPayroll(payrollT payroll);
 //static void GetPayroll(void);
 static double ssnum(payrollT payroll);

Main program:

int main(void)
{
    payrollT payroll;
    //GetPayroll(payroll);
    InitEmployeeTable();
    payroll = CreatePayroll(staff, nEmployees);
    ListEmployees(payroll);
    WeeklyPayroll(payroll);
}

static void InitEmployeeTable(void)
{
    employeeT empRec;
    int condition = 1;
    int emp_id = 2;
    empRec = (employeeT)malloc(sizeof (employeeT));
    empRec->name = "Ebenezer Scrooge";
    empRec->title = "Partner";
    empRec->ssnum = "271-82-8183";
    empRec->salary = 250.00;
    empRec->withholding = 1;
    staff[0] = empRec;
    empRec->name = "Bob Cratchit";
    empRec->title = "Clerk";
    empRec->ssnum = "314-15-9265";
    empRec->salary = 15.00;
    empRec->withholding = 7;
    staff[1] = empRec;
    nEmployees = 2;

    do {
        //malloc(sizeof ());
        char name;
        char title;
        char ssnum;
        float salary;
        double withholding;
        printf("enter name or input stop to quit!\n");
        printf("enter first and last name\n");
        scanf("%s", empRec->name);
        //empRec->name = name;
        printf("\nenter title\n");
        scanf("%s", empRec->title);
        //empRec->title = title;
        printf("\nenter social xxx-xx-xxxx\n");
        scanf("%s", empRec->ssnum);
        //empRec->ssnum = ssnum;
        printf("\nenter salary xx.xx\n");
        scanf("%lf", &empRec->salary);
        //empRec->salary = salary;
        printf("\nenter withhodling x\n");
        scanf("%d", &empRec->withholding);
        //empRec.withholding = withholding;
        printf("printed %d", emp_id++);
        staff[emp_id] = empRec;
        emp_id++;
        if (strcmp(empRec->name,"stop") == 1) {
            condition = 0;
            break;
        }
        //staff[emp_id]=empRec;
        //emp_id++;
    } while (condition = 1);

    return 0;
}
RastaJedi
  • 641
  • 1
  • 6
  • 18

1 Answers1

2

You aren't allocating storage for any of your strings (name, title, ssnum [in your records, and now that I looked, in your do-while loop too--you can't use char name;, you need e.g. char name[100]; or pointer with malloc]). Using your typedef for string is somewhat hiding that fact. The only time you can assign to a string variable and have the allocation taken care of for you is at declaration time, since the size is known at compile-time e.g.:

char *str = "Hello";
char *str2 = { 'w', 'o', 'r', 'l', 'd', '\0' };

In your case, the assignment of the strings for manager is fine since they are in the initializer, but you still do need to give explicit sizes for the character arrays in your employeeRecordT.

What you need to do is either give explicit sizes for these character arrays or explicitly allocate storage for them (malloc etc.); and instead of assigning, you must use strcpy() (<string.h>) (or strncpy() in cases where overflow is a possibility).

One thing you could do for something like your title variable to save space is to declare a statically allocated list of strings and then just have title be a pointer to the appropriate element in the list, e.g. (the consts are optional, but just makes sure this array doesn't get messed up in any way):

const char const *titles[] = { "Partner", "Clerk", "etc." };

typedef struct {
    const char *title;
    // ...
} *employeeT;

// ...
empRec->title = titles[0];    // Points title to "Partner"

You could even use an enum as well to help with the index (all of the rest of the code would be the same):

enum { PARTNER, CLERK, ETC };
// ...
empRec->title = titles[CLERK];    // Points title to "Clerk"

Another issue with your code is that you are only allocating storage for a single employeeT record; you can't reuse empRec without calling malloc() again. What is going to happen is every time you change empRec, it's going to change all of the previous staff elements because they all point to the same location (i.e., staff[0] will contain exactly what you set staff[1] to). Another issue is that you are taking the sizeof (employeeT) but this is wrong since that is only giving you the size of a pointer to your struct. This is one reason why typedefs can make things more confusing. You should create your struct (and typedef to it if you want), but when you need a pointer to it, you should honestly just use the '*' right there in the code (optionally making a second typedef, i.e. typedef struct { // ... } node; typedef node *node_ptr; or even at the same time: typedef struct { // ... } node, *node_ptr;). You have two options, you can either call malloc() again for empRec before you start assigning its members the second (and subsequent) times, or you can simply discard the empRec variable and use staff directly, e.g.:

staff[0] = malloc(sizeof *staff[0]);
// Note I couldn't use employeeT above since you need struct size, not ptr.
// (`sizeof (employeeRecordT)` could have been used though)
strcpy(staff[0]->name, "Ebenezer Scrooge");
// ...
staff[0]->salary = 250.00;
// ...

Be sure to free() every element in staff[] later on.

Furthermore, I don't see why you have this payrollT type which is essentially a copy of your staff array? If you want payrollT you can just have a pointer to an employee record (which by the way, you probably didn't want employeeT *employees;, you probably wanted either employeeT employees; (since it is already a pointer type) or employeeRecordT *employees). I think this is really the only other thing I see wrong with your program snippet.

If you wanted to, you could get rid of your condition variable, and instead of using a do-while loop, just use a while (1) and your break in your if will exit it for you. This way you can be sure it is still evaluated at least once.

By the way, you don't have to cast the return value of malloc(). It's unnecessary since void pointers are safely and automatically promoted to any other type (and vise versa). See here for more info. Also, I see you mention NewArray but never reference it anywhere.

Community
  • 1
  • 1
RastaJedi
  • 641
  • 1
  • 6
  • 18