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.