Files in C, fseek
Paul whoknows

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 
6struct employees_{
7 char surname[20];
8 char name[20];
9 float salary;
10};
11 
12struct students_{
13 char surname[20];
14 char name[20];
15 float prome;
16} ;
17 
18 
19/* Prototipos */
20void show_employees(void);
21void show_students(void);
22void update_salary(void);
23 
24void main()
25{
26 
27show_employees();
28show_students();
29update_salary();
30}
31 
32/*----------------- Show students records stored in STUDENTS.DAT ------------------------- */
33void show_students(void)
34{
35FILE *archi_est;
36struct students_ students;
37if((archi_est=fopen("STUDENTS.DAT","rb"))==NULL) {
38 printf("\nFile error");
39 getch();
40 exit(0);
41}
42printf("\nLIST DE STUDENTS");
43fread(&students, sizeof(struct students_), 1, archi_est);
44while(!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}
49fclose(archi_est);
50printf("\nPress a key to continue . . . . . . \n");
51getch();
52}
53 
54/*----------------show employees records stored in EMPLOYEES.DAT----------------------------- */
55void show_employees(void)
56{
57FILE *archi_emp;
58struct employees_ employees;
59printf("\nPress a key ...");
60getch();
61/* Abro archivo y muestro los datos que se grabaron */
62if((archi_emp=fopen("EMPLOYEES.DAT","rb"))==NULL) {
63 printf("\nFile error");
64 getch();
65 exit(0);
66}
67printf("\nLIST DE EMPLOYEES");
68fread(&employees, sizeof(struct employees_), 1, archi_emp);
69while(!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}
74fclose(archi_emp);
75printf("\nPress a key to continue . . . . . . \n");
76getch();
77}
78 
79/*Lee registros de EMPLOYEES.DAT, y si se encuentran en STUDENTS.DAT && promedio > 7 entonces
80 update salary de dichos registros. */
81void update_salary(void)
82{
83FILE *archi_emp;
84FILE *archi_est;
85struct employees_ employees;
86struct students_ students;
87 
88 
89int i=0;
90 
91/* Abro archivo employees para lectura y escritura */
92if((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 */
99if((archi_est = fopen("STUDENTS.DAT","rb"))==NULL) {
100 printf("\nFile error");
101 getch();
102 exit(0);
103}
104 
105 
106fread(&employees, sizeof(struct employees_), 1, archi_emp);
107while(!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}
128if(i>1) printf("\n%d records updated.",i);
129if(i==0) printf("\nno employees met the required requiriments");
130fclose(archi_est);
131fclose(archi_emp);
132getch();
133 
134}

Physics Dave

If I remember, fwrite moves the position in the file along by however much it writes, so that second fseek is not needed:

               fseek(archi_emp, -1L*sizeof(struct employees_), SEEK_CUR);
          fwrite(&employees, sizeof(struct employees_), 1, archi_emp);
/* delete this --->        fseek(archi_emp, 1L*sizeof(struct employees_), SEEK_CUR) */

I'd also ask you to watch your brackets and indentations:

{
   it will make stuff
   {
      a lot clearer
   }
   honest!
}

h2g2bob

A J

looks like homework!

which bit of the fseek documentation dont you understand ?

BAF

Why are you writing structs directly to the file?

Paul whoknows
Quote:

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.

Quote:

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.

Quote:

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?

Evert
Quote:

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.

Quote:

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.

Paul whoknows
Quote:

Never, ever use fread and fwrite.

What can I use instead?

Quote:

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.

Quote:

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!

BAF

Wow.. what kind of programming class is this if they limit what you can do and teach you to fread/fwrite structs. :-/

Paul whoknows

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.

A J

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.

GullRaDriel

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 );

Paul whoknows
Quote:

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.

Quote:

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.

Bob

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.

Paul whoknows
Quote:

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.

Quote:

Also, you may want to use fgets() to read the file one line at a time

Can I use fgets in binary files?

Quote:

Or, if you get to use C++. . .

ANSI C I must only use.

Thread #585501. Printed from Allegro.cc