There is 2 files: EMPLOYEES.DAT and STUDENTS.DAT(*** DOWNLOAD ATTACHMENT ***)
EMPLOYEES.DAT (3 records) SURNAME NAME SALARY Hunter Rick 1000 Tokisada Amakusa S. 1000 Duncan Seymour 1200 --------------------------------------- STUDENTS.DAT (2 records) SURNAME NAME AVERAGE Hunter Rick 8 Tokisada Amakusa S. 9
update_salary function must allow user to update salary field of those employees who are also students and average >7, in other words:
(if employees.name==students.name && employees.surname==students.surname && students.prome >7) /* prome == average */
Therefore, update_salary should show these records:
Hunter Rick 8 Tokisada Amakusa S. 9
But it doesn't, it only shows one of them.
I know the problem is in the update_salary's nested whiles, I really don't know hot to use "fseek".
Enough talk, HEEEELP PLEASE!!!!
1 | #include <stdio.h> |
2 | #include <conio.h> |
3 | #include <stdlib.h> |
4 | #include <string.h> /* Usado para strcpy */ |
5 | |
6 | struct employees_{ |
7 | char surname[20]; |
8 | char name[20]; |
9 | float salary; |
10 | }; |
11 | |
12 | struct students_{ |
13 | char surname[20]; |
14 | char name[20]; |
15 | float prome; |
16 | } ; |
17 | |
18 | |
19 | /* Prototipos */ |
20 | void show_employees(void); |
21 | void show_students(void); |
22 | void update_salary(void); |
23 | |
24 | void main() |
25 | { |
26 | |
27 | show_employees(); |
28 | show_students(); |
29 | update_salary(); |
30 | } |
31 | |
32 | /*----------------- Show students records stored in STUDENTS.DAT ------------------------- */ |
33 | void show_students(void) |
34 | { |
35 | FILE *archi_est; |
36 | struct students_ students; |
37 | if((archi_est=fopen("STUDENTS.DAT","rb"))==NULL) { |
38 | printf("\nFile error"); |
39 | getch(); |
40 | exit(0); |
41 | } |
42 | printf("\nLIST DE STUDENTS"); |
43 | fread(&students, sizeof(struct students_), 1, archi_est); |
44 | while(!feof(archi_est)) { |
45 | printf("\n SURNAME:%-15s NAME:%-15s AVERAGE:%4.1f ", students.surname, students.name, |
46 | students.prome); |
47 | fread(&students, sizeof(struct students_), 1, archi_est); |
48 | } |
49 | fclose(archi_est); |
50 | printf("\nPress a key to continue . . . . . . \n"); |
51 | getch(); |
52 | } |
53 | |
54 | /*----------------show employees records stored in EMPLOYEES.DAT----------------------------- */ |
55 | void show_employees(void) |
56 | { |
57 | FILE *archi_emp; |
58 | struct employees_ employees; |
59 | printf("\nPress a key ..."); |
60 | getch(); |
61 | /* Abro archivo y muestro los datos que se grabaron */ |
62 | if((archi_emp=fopen("EMPLOYEES.DAT","rb"))==NULL) { |
63 | printf("\nFile error"); |
64 | getch(); |
65 | exit(0); |
66 | } |
67 | printf("\nLIST DE EMPLOYEES"); |
68 | fread(&employees, sizeof(struct employees_), 1, archi_emp); |
69 | while(!feof(archi_emp)) { |
70 | printf("\n SURNAME:%-15s NAME:%-15s SALARY:%4.1f ", employees.surname, employees.name, |
71 | employees.salary); |
72 | fread(&employees, sizeof(struct employees_), 1, archi_emp); |
73 | } |
74 | fclose(archi_emp); |
75 | printf("\nPress a key to continue . . . . . . \n"); |
76 | getch(); |
77 | } |
78 | |
79 | /*Lee registros de EMPLOYEES.DAT, y si se encuentran en STUDENTS.DAT && promedio > 7 entonces |
80 | update salary de dichos registros. */ |
81 | void update_salary(void) |
82 | { |
83 | FILE *archi_emp; |
84 | FILE *archi_est; |
85 | struct employees_ employees; |
86 | struct students_ students; |
87 | |
88 | |
89 | int i=0; |
90 | |
91 | /* Abro archivo employees para lectura y escritura */ |
92 | if((archi_emp = fopen("EMPLOYEES.DAT","r+b"))==NULL){ |
93 | printf("\nFile error"); |
94 | getch(); |
95 | exit(0); |
96 | } |
97 | |
98 | /* Abro archivo students para lectura */ |
99 | if((archi_est = fopen("STUDENTS.DAT","rb"))==NULL) { |
100 | printf("\nFile error"); |
101 | getch(); |
102 | exit(0); |
103 | } |
104 | |
105 | |
106 | fread(&employees, sizeof(struct employees_), 1, archi_emp); |
107 | while(!feof(archi_emp) && !feof(archi_est)){ |
108 | |
109 | fread(&students, sizeof(struct students_), 1, archi_est); |
110 | while(!feof(archi_est) && !feof(archi_emp) ){ |
111 | if(strcmpi(employees.name, students.name)==0 && strcmpi(employees.surname, students.surname)==0 && (students.prome>7)) { |
112 | printf("\nThis employeeo %s %s is also a student and he has an average higher than 7", |
113 | employees.name, employees.surname); |
114 | printf("\nUpdate salary please "); |
115 | fflush(stdin); |
116 | scanf("%f",&employees.salary); |
117 | |
118 | fseek(archi_emp, -1L*sizeof(struct employees_), SEEK_CUR); |
119 | fwrite(&employees, sizeof(struct employees_), 1, archi_emp); |
120 | fseek(archi_emp, 1L*sizeof(struct employees_), SEEK_CUR); |
121 | i++; |
122 | } |
123 | fread(&students, sizeof(struct students_), 1, archi_est); |
124 | } |
125 | fread(&employees, sizeof(struct employees_), 1, archi_emp); |
126 | fseek(archi_est, 0L, SEEK_SET); |
127 | } |
128 | if(i>1) printf("\n%d records updated.",i); |
129 | if(i==0) printf("\nno employees met the required requiriments"); |
130 | fclose(archi_est); |
131 | fclose(archi_emp); |
132 | getch(); |
133 | |
134 | } |
If I remember, fwrite moves the position in the file along by however much it writes, so that second fseek is not needed:
I'd also ask you to watch your brackets and indentations:
{ it will make stuff { a lot clearer } honest! }
h2g2bob
looks like homework!
which bit of the fseek documentation dont you understand ?
Why are you writing structs directly to the file?
If I remember, fwrite moves the position in the file along by however much it writes, so that second fseek is not needed:
I did what you said, and it almost works, but it really doesn't, because it get trapped in a neverending loop.
which bit of the fseek documentation dont you understand ?
I don't know how to control file pointers, I mean, fwrite and fread automatic moves the file pointer forward, but fseek doesn't work sometimes, look at my source, it must show 2 aforementioned records, but it doesn't.
Why are you writing structs directly to the file?
Because I can add unlimited records to my files, that wouldn't be possible using static arrays, and we are not allowed to use dynamic memory allocation yet.
Any advice?
Any advice?
Never, ever use fread and fwrite.
That said, there are situations when they're useful, but this is not one of them.
For advise, I'd tell you to store data on disk as a text file. This is not a direct answer to your question, however.
we are not allowed to use dynamic memory allocation yet.
Were you told not to, or haven't they told you how to do it? If the former, that sucks. If the latter, just use it if you think it's best.
Never, ever use fread and fwrite.
What can I use instead?
For advise, I'd tell you to store data on disk as a text file.
Only binary files must be used, that's an order, that limitation is part of the problem.
Were you told not to...
Yes, another order.
I try to do the best I can with the tools they allow me to use, that's part of the problem, and yes, it sucks.
However, the posted code almost works, it only needs a minor tweak, but I can't figure out!
Wow.. what kind of programming class is this if they limit what you can do and teach you to fread/fwrite structs.
Dynamic memory allocation, LIFO, FIFO, binary trees, all that stuff is comming later, but now they force us to use these "basic tools", don't ask me why, I am just a student.
BTW, if you look at the code, I am defining the file pointer in every function, why? because we are not allowed to use global variables, it sounds stupid, but now I see why they do it.
Look at this tread, they forced me to use pointer notation in a 2d array, that wasn't easy at first, but now I have a better understanding of how it works in a deeper view.
for any text file you plan to parse, if its less than 100k, just read it into memory and use regular char* on it, it will be
1. faster.
2. safer.
3. easier.
4. easier to modify/upgrade/improve later.
infact, i would go as far as 200k or 300k before reconsidering what i just said.
Or use some PACKFILE routines, with compressed-or-not PACKFILE *file. All of them are endian-safe.
little example:
PACKFILE *in; int value = 10; . . in = pack_fopen( "file.dat" , "rp" ); . pack_iputl( in , value ); /* write a number */ . value = pack_igetl( in ); /* read a number */ . pack_fclose( in );
for any text file you plan to parse, if its less than 100k, just read it into memory and use regular char* on it, it will be
Only binary file must be used.
Or use some PACKFILE routines
Only ANSI C must be used.(I must remove conio.h)
I appreciate all your help, and I am going to use it in my own projects, but I can't use it here, because of the aforementioned restrictions, thanks.
You can just read/write your data in some (opaque, binary) file instead of dynamically allocating memory for it. The file size will automagically grow as you write things into it, so you even have an automatically resizing container. It'll be ridiculously slow for any real-world application, but it may work for your case.
Also, you may want to use fgets() to read the file one line at a time (although you'll need to deal with the really long line problem). Or, if you get to use C++, then std::readline(std::istream&, std::string&) will do the trick.
You can just read/write your data in some (opaque, binary) file instead of dynamically allocating memory for it.
That's exactly what I am doing right now.
Also, you may want to use fgets() to read the file one line at a time
Can I use fgets in binary files?
Or, if you get to use C++. . .
ANSI C I must only use.