0

first time using this site. Someone recommended I come here. So, I have an assignment due soon and I'm struggling to write the code. I completed it to the best of my ability and everything seems to be in order for me, however when I run the program, the result does not change regardless of what I input. The assignment is:

Write a C program to read from a file called “input.txt” information about 5 workers. Each line of input would contain two values respectively, an employee ID and the employee’s monthly salary.

Assume that the data from the input file is stored in a format as shown in this example. Note: for testing purposes, the following data may not necessarily be used. It is just to give you an idea of the format of the data:

Sample contents of input.txt: 10 2000 20 6800 30 9700 40 1500 50 8000

Store the employee information into a 2D array. Assume that the data types are as follows: id (integer data type) and income (integer data type).

Read the information and store the 5 employee records into the 2D array.

Use a function that prints the sum of all incomes of workers.

Create another function that prints the number of workers who has an income of greater than $5000 and also the ID and income of each worker who has an income of greater than $5000.

And my code is as follows:

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

int employeeID, salary;
int id[5][2], income[5][2];
int sum();
int greater();
FILE *worker;

int main()
{


    worker=fopen("input.txt", "w");
        printf("Enter Employee ID and Salary:\n");
    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            scanf("%d", &id[employeeID][salary]);
        }
    }
    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            fprintf(worker,"%d", &id[employeeID][salary]);
        }       
    }
        fclose(worker);

    worker=fopen("input.txt", "r");
        while(!feof(worker)){
            for(employeeID=0;employeeID<5;employeeID++){
                for(salary=0;salary<2;salary++){
                    fscanf(worker,"%d", &income[employeeID][salary]);

                }
            }
        }
    sum();
    greater();
}
int sum()
{
    int totalincome, totalsum;
    int income[5][2];

totalsum=income[0][1]+income[1][1]+income[2][1]+income[3][1]+income[4][1];
totalincome=printf("\nSum of all workers incomes:$%d\n");
    return totalincome;
}
int greater()
{
    int employeeID, salary;
    int income[5][2];
    int num=0;
    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            if(income[employeeID][salary+1]>5000){
                num++;
            }
        }
    }
    printf("\nWorkers that have income greater than $5000:\t");

        if(income[0][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[0][0], income[0][1]);
        }

        if(income[1][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[1][0], income[1][1]);
        }       

        if(income[2][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[2][0], income[2][1]);
        }

        if(income[3][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[3][0], income[3][1]);
        }

        if(income[4][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[4][0], income[4][1]);
        }

    return 0;   //End of Program
}

I know this is a lot to read, but I would truly appreciate any help from anyone. I am really struggling. Thank you.

Kerbfrost
  • 1
  • 1
  • 1
    It seems it is time for you to [learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – Some programmer dude Nov 25 '17 at 02:36
  • Why do you `fprintf(worker,"%d", &id[employeeID][salary]);`?? (more importantly -- what is it you are actually trying to print?) You will want to look at [**Why is while ( !feof (file) ) always wrong?**](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). – David C. Rankin Nov 25 '17 at 03:35
  • please specify what problem/error are you getting? – nikoo28 Nov 25 '17 at 03:44

2 Answers2

3

For starters, avoid the use of global variable unless absolutely required (which is almost never when you are first learning C). Instead, declare required variables in main() and pass as parameters to any functions.

You initially invite Undefined Behavior by failing to validate the return or either:

worker=fopen("input.txt", "w");

or

        scanf("%d", &id[employeeID][salary]);

It is imperative you validate all input aspects of your code. Otherwise, you don't know if you are actually reading from a file (or a NULL stream pointer) and failing to validate the return of scanf leaves you with absolutely no idea whether a valid conversion took place or whether an input or matching failure occurred.

You read from your file into a 2D array and then you do the following??

for(employeeID=0;employeeID<5;employeeID++){
    for(salary=0;salary<2;salary++){
        fprintf(worker,"%d", &id[employeeID][salary]);
    }       
}

You cannot print the address of id[employeeID][salary] with a "%d" format specifier -- that invokes Undefined Behavior. (the & should not be there...) Further, why the heck are you attempting to write the values back to the file you just read them from in the previous set of nested loops with scanf?? Doing so would remove all whitespace between the values leaving you one long string of digits.

You only need one 2D array. It will hold the employeeid in the first column and salary in the second column of each row.

Let's look at how you can properly do this, first, do not use magic numbers or hardcoded filenames sprinkled throughout your code:

/* if you need constants, #define them or use an enum */
enum { SALCOL = 1, NCOL = 2, NROW = 5, HISAL = 5000 };

The proper definition for main() taking arguments is:

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

You can pass the filename as the first argument to your program and avoid hardcoding "input.txt" in your code.

Define your variables in main(), open your file (this code also reads from stdin by default if no filname is given) and always validate the file is open for reading.

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

    int rows = 0,   /* row index */
        cols = 0,   /* col index */
        wrkrs[NROW][NCOL] = {{0}};  /* 2d array for workers */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }
    ...

You must keep track of the number of rows of data you read. You cannot just rely on there being a constant number of values in the file that just happens to match the constant you put in your code. Track both column index and row index and reset as appropriate to populate your 2D array:

    /* read values while rows < NROW */
    while (rows < NROW && scanf ("%d", &wrkrs[rows][cols]) == 1)
        if (++cols == NCOL) {   /* increment and check col = NCOL */
            cols = 0;           /* reset col to zero */
            rows++;             /* increment row index */
        }

All that remains is closing your file and outputting all workers and then those making more that HISAL (5000) as salary:

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    prnwrkrs (wrkrs, rows);             /* output all workers */
    prnhighwrkrs (wrkrs, rows, HISAL);  /* output workes making HISAL */

    return 0;
}

For your print function, you need to pass the workers 2D array and the number of rows of data (which could be less than you expected). Note: you can pass a 2D array as int array[][NCOL] which will be converted to a pointer to an array of NCOL meaning you can also pass workers as int (*array)[NCOL] to reflect what the function will actually receive. One way to handle it is:

/* print all workers in 2d array 'a' with `rows' rows.
 * note: a can be passed as 'a[][NCOL] as well
 */
void prnwrkrs (int (*a)[NCOL], int rows)
{
    printf ("\nAll workers:\n");        /* print heading */
    for (int i = 0; i < rows; i++) {    /* loop over each row */
        printf ("  worker[%d] : ", i);  /* output worker[] label */
        for (int j = 0; j < NCOL; j++)  /* loop over each col */
            printf (" %6d", a[i][j]);   /* output integer value */
        putchar ('\n');                 /* tidy up with '\n' */
    }
}

To handle the HISAL workers you simply pass one additional parameter, the salary to compare the workers salary against (note: since you have declared constants, you can omit passing the salary and just use the constant to compare against, but why not make the function useful to show worker making more than any salary you may wish to pass to the function, e.g.

/* print worker earning more than 'sal'
 * same as prnwrkrs, but passes additional parameter 'sal'
 * for comparison. Compre to salary and print if greater.
 */
void prnhighwrkrs (int (*a)[NCOL], int rows, int sal)
{
    printf ("\nWorkers earning %d or more:\n", sal);
    for (int i = 0; i < rows; i++) {
        if (a[i][SALCOL] >= sal) {          /* compare with 'sal' */
            printf ("  worker[%d] : ", i);  /* output if greater */
            for (int j = 0; j < NCOL; j++)
                printf (" %6d", a[i][j]);
            putchar ('\n');
        }
    }
}

Putting it altogether, you can do something like the following:

#include <stdio.h>

/* if you need constants, #define them or use an enum */
enum { SALCOL = 1, NCOL = 2, NROW = 5, HISAL = 5000 };

/* print all workers in 2d array 'a' with `rows' rows.
 * note: a can be passed as 'a[][NCOL] as well
 */
void prnwrkrs (int (*a)[NCOL], int rows)
{
    printf ("\nAll workers:\n");        /* print heading */
    for (int i = 0; i < rows; i++) {    /* loop over each row */
        printf ("  worker[%d] : ", i);  /* output worker[] label */
        for (int j = 0; j < NCOL; j++)  /* loop over each col */
            printf (" %6d", a[i][j]);   /* output integer value */
        putchar ('\n');                 /* tidy up with '\n' */
    }
}

/* print worker earning more than 'sal'
 * same as prnwrkrs, but passes additional parameter 'sal'
 * for comparison. Compre to salary and print if greater.
 */
void prnhighwrkrs (int (*a)[NCOL], int rows, int sal)
{
    printf ("\nWorkers earning %d or more:\n", sal);
    for (int i = 0; i < rows; i++) {
        if (a[i][SALCOL] >= sal) {          /* compare with 'sal' */
            printf ("  worker[%d] : ", i);  /* output if greater */
            for (int j = 0; j < NCOL; j++)
                printf (" %6d", a[i][j]);
            putchar ('\n');
        }
    }
}

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

    int rows = 0,   /* row index */
        cols = 0,   /* col index */
        wrkrs[NROW][NCOL] = {{0}};  /* 2d array for workers */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* read values while rows < NROW */
    while (rows < NROW && scanf ("%d", &wrkrs[rows][cols]) == 1)
        if (++cols == NCOL) {   /* increment and check col = NCOL */
            cols = 0;           /* reset col to zero */
            rows++;             /* increment row index */
        }

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    prnwrkrs (wrkrs, rows);             /* output all workers */
    prnhighwrkrs (wrkrs, rows, HISAL);  /* output workes making HISAL */

    return 0;
}

Example Input File

$ cat dat/workers.txt
 10 2000 20 6800 30 9700 40 1500 50 8000

Example Use/Output

$ ./bin/workers <dat/workers.txt

All workers:
  worker[0] :      10   2000
  worker[1] :      20   6800
  worker[2] :      30   9700
  worker[3] :      40   1500
  worker[4] :      50   8000

Workers earning 5000 or more:
  worker[1] :      20   6800
  worker[2] :      30   9700
  worker[4] :      50   8000

C is not a language you can just guess at what the code should be, compile it, fail, change it a little with your next guess, compile again, fail... You have to take the time to validate each piece of the puzzle, know what values you are handling, what index they reside at, and how to properly use each function in your code. You learn that by checking man function for each of the standard library functions you use until you know them cold -- and then you still look at man function to make sure.

Look things over. Understand why the code does what it does and ask if you have any further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

There is no need for two 2D arrays here. You just need one, perhaps call it employeeInfo with dimensions: 5 employees and 2 pieces of information [one row is for employee ID numbers, and the other is for the income] employeeInfo[ numberOfEmployees ][ infoTypes ]

| id0 | id1 | id2 | id3 | id4 | <<-- employeeID's

| $s0 | $s1 | $s2 | $s3 | $s4 | <<-- employee's Salary

( Sorry for the poor formatting ^)

So now we want to read the numbers from the file into it so we need to open the file for reading by passing r to the fopen() function:

worker = fopen("input.txt", "r");  //open file for reading
// Since we know exactly how many employees there are
// we can read precisely that many times in a double for loop: 
//  but the hardcoded literals work better as variables in the future
//  (see the comments in the greater() function below for ideas)          
for (int employee = 0; i < 5; employee++) //five employees
{
    for (int infoType = 0; info < 2; infoType++) //two pieces of info per employee
    {
        int info; // for storing the ID/SALARY
        fscanf(worker, " %d", &info); // read the next value  
        employeeInfo[employeeID][infoType] = info ; // store in 2d array(our table)
    }
} 
fclose(worker);

Okay, now our employeeID array (or table) is full! We can now sum up the incomes and print the total:

int sum() # or void sum() unless you have future plans for this
{
    //int income[5][2]; this is empty and not needed. 
    int totalsum; //second variable not needed

    // global scope of the first 2d array means that you can access it here.

    totalsum = 0; // start at 0 and add incomes as we go
    for(int employee = 0; employee < 5; employee++)
    { 
      totalsum += employeeInfo[employee][1];
    }
    // the above for loop has the advantage that we can easily sum for more
    // employees
    //totalsum=income[0][1]+income[1][1]+income[2][1]+income[3][1]+income[4][1];
    //now we're printing totalsum
    printf("\nSum of all workers incomes:$%d\n", totalsum); 

    return totalsum; // this is not used but this is returning the sum
}

The sum() function was doing three major things incorrectly:

  1. Forgetting how scope works: It's declaring a new and empty array income whose values will have nothing to do with the globally scoped 'income' array. Since you declared the first 'income' array outside the main function, it's in the global scope, which means it can be accessed from anywhere. No need to redeclare.

  2. Printf() errors:

    There's actually two mistakes in the code surrounding printf(). First, you have give it the the name of the variable(s) you want to print with the format specifiers(like %d) separated by commas in the order they appear in the quotes. Like this: printf("some text: %d %c", myInteger, myChar)

    The other thing to take note of is that printf() will print to to std out (the console in most cases) but if you store it in a variable like you did you are storing its internal return value, which is actually the number of characters it printed. See this question: Return value of printf() function in C

  3. Not returning the sum:

    I'm guessing you thought that totalincome would have totalsum in it, but as mentioned printf() doesn't return what it prints. Also, note that what sum() returns is not being stored or used in the main function. It could just as well be a void function instead in this case.

The greater() function should work -- but its worth mentioning that it isn't necessary to write the if statements. You can do the check within the for loop and use printf() from there similarly to how the code was reformatted in the sum() function.

Also, the end of the greater() function is not the end of your program. The flow of logic resides in the body of main(). When main() ends (returns), the program ends.

int greater()
{
    // int income[5][2] is empty and not needed
    // all the info is read into the globally declared 2D array (employeeInfo)
    // by the time greater() is called
    int employeeID; // , salary <<--not needed 
                    // but it is good style to avoid "magic numbers"
                    // like the hard-coded '5' or '1' in the loop below
                    // we could instead define static constants before main
                    // for example:
                      // static const int HIGH_SALARY= 5000
                    // or if you need to use the "magic numbers" as an array dimension:
                      // enum {MAX_EMPLOYEES = 5, ID_TYPE = 0, SALARY_TYPE = 1 }

    int totalHighSalaryEmployees= 0;
    // Start building output:
    printf("\nWorkers that have income greater than $5000:\t"); 
    for(employeeID=0;employeeID<5;employeeID++){ // For each employee
        if(income[employeeID][1]>5000){  //check their salary
            totalHighSalaryEmployees++;  // Increment our count of the wealthy
            printf("\nEmployee ID:%d  Salary: $%d", employeeInfo[employeeID][0], employeeInfo[employeeID][1]); 

        }
    } //Done -- 
    // Now print number of high salary employees 
    printf("\nNumber of Workers that have income greater than $5000:%d", totalHighSalaryEmployees);
    return totalHighSalaryEmployees;
}
Elfen Dew
  • 114
  • 1
  • 9