PDA

View Full Version : Struct và mảng 1 chiều ... làm ơn giúp mình với !



quynh_khoi
02-12-2004, 00:02
Chào các bạn,
Các bạn làm ơn giúp mình cái này chút, mình mới học C/C++ nên không biết cách làm thế nào để đọc được dữ liệu từ một file trên máy sang một mảng 1 chiều gồm các phần tử là các struct. Chẳng hạn mình có file dữ liệu (dulieu.dat) có dạng như sau:

02K1938
02T3
Ngo Ba Quynh Khoi
30
10
1983
Vietnam
7.89
Tot
Gioi
Kha
02K1939
02T3
Hoang Hanh Thao
10
10
1983
Vietnam
8.01
Tot
Gioi
Gioi

Trong file dữ liệu trên thì mỗi dòng trong 11 dòng đầu tiên là một trường của một struct gồm những thông tin về một sinh viên, mình đã khai báo struct như sau:

#define String_Limit 30
#define Array_Limit 200

typedef
char String_Type[String_Limit];
typedef
struct Date
{
unsigned char Day;
unsigned char Month;
unsigned Year;
};
typedef
struct StuInfor
{
char Maso[8];
char Lop[6];
String_Type Name;
Date Birthday;
String_Type Que_Quan;
float GPA;
char Credits[8];
char Hoc_Bong[8];
char XL_Hoc_Tap[8];
} Student_Record;
typedef
Student_Record Array_Of_Records[Array_Limit];

FILE *StuFile, *NewStuFile;
Array_Of_Records Student;
int NumRecs;
char Error;

Vậy các bạn làm ơn chỉ giúp mình cách để đọc nội dung file dulieu.dat đó vào trong từng phần tử của mảng 1 chiều Array_Of_Records, tức là phần tử 0 của mảng Array_Of_Records sẽ là một struct chứa 11 dòng đầu tiên, tiếp đến là các phần tử thứ 1, 2, 3 …Mình đã thử dùng hàm fread để đọc nhưng không thành công, không biết là bị sai ở đâu, mình đã dùng hàm fread như sau:

void Read_File(Array_Of_Records Student, int &Limit, int &NumRecs, char &Error)
{
StuFile = fopen("dulieu.dat","rb");
NumRecs = 0;
Error = FALSE;
while ((!(feof(StuFile))) && (!(Error)))
{
if (NumRecs < Limit)
{
fread(&Student[NumRecs],sizeof(Student_Record),1,StuFile);
NumRecs++;
}
else
Error = TRUE;
}
fclose(StuFile);
}

Các bạn hãy viết lại giúp mình đoạn mã trên được không, mình cảm ơn nhiều !

thailehuy
02-12-2004, 08:40
Nếu file dulieu của bạn ghi kiểu text thì dùng fscanf để đọc, hay dùng fgets thay thế fread cũng được. Ngoài ra dòng:Error = FALSE nên cho vào vòng lặp while
Thêm vào trong dòng lặp 1 lệnh để cho NumRecs trở lại 0 sau khi đọc đủ dữ liệu cho 1 struct:
while ((!(feof(StuFile))) && (!(Error)))
{
if(NumRecs ==Limit )
NumRecs = 0;
Error = FALSE;
if (NumRecs < Limit)
{
fread(&Student[NumRecs],sizeof(Student_Record),1,StuFile);
NumRecs++;
}
else
Error = TRUE;
}

bete
02-12-2004, 13:12
Nếu file dulieu của bạn ghi kiểu text thì dùng fscanf để đọc, hay dùng fgets thay thế fread cũng được.

=> tui đồng ý với thailehuy chỗ này (nếu xài fgets thì cần xài thêm sprintf để đổi từ chuỗi ký tự sang kiểu số)


fread(&Student[NumRecs],sizeof(Student_Record),1,StuFile);

=> không nên xài fread chỗ này (String_Limit là 30; nhưng dữ liệu đọc từ file có thể ngắn hơn 30 ký tự => khi đọc field kế sẽ bị đặt vô trật chỗ)

(có gì sai sót xin các bạn chỉ giúp, cám ơn nhiều)

-thân

quynh_khoi
02-12-2004, 17:01
Chào bạn thailehuy,

Rất cám ơn bạn đã trả lời mình những mình xin có một số ý như thế này:
---> Nếu như mình dùng fscanf để đọc thì mình sẽ không thể đọc được họ tên vì hàm fscanf có tính chất là nó chỉ đọc đến khi có ký tự trống thì sẽ dừng lại, không biết bạn có nhớ tính chất đấy không ...
---> Còn nếu như mình dùng fgets để đọc (mình đã thử rồi) thì phải biến đổi thêm một bước nữa vì tính chất của hàm fgets là nó đọc luôn cả ký tự mã 10 (dấu xuống dòng) vào trong xâu kết quả trả về. Vậy nên nếu để nguyên xâu trả về mà không biến đổi thêm (để loại mã 10 ra khỏi xâu) thì sẽ bị sai ngay, hơn nữa khi đến dòng cuối cùng của file thì vì sau dòng này sẽ không có dấu xuống dòng nên hàm fgets sẽ đọc đúng chiều dài của xâu, vì vậy ta phải loại trừ thêm trường hợp này nữa. Như vậy tóm lại là mình phải đi đường vòng khá mệt, tuy vậy nhưng mình vẫn thử fgets rồi nhưng không thể chạy được (chẳng hiểu vì sao nữa !?) Mình sẽ thử lại cách mà bạn đã chỉ hy vọng rằng sẽ thành công, cám ơn bạn nhiều nha !

Còn bạn bete, mình cũng xin cảm ơn bạn nhiều! ý kiến của bạn cũng có lý, mình sẽ coi lại thử xem sao ... thanks mọi người nhiều!

Bạn nào còn có ý tốt xin hãy giúp mình với nha !!! Thanks in advance!

bete
02-12-2004, 17:54
Thân gửi quynh_khoi:


Còn nếu như mình dùng fgets để đọc (mình đã thử rồi) thì phải biến đổi thêm một bước nữa vì tính chất của hàm fgets là nó đọc luôn cả ký tự mã 10 (dấu xuống dòng) vào trong xâu kết quả trả về. Vậy nên nếu để nguyên xâu trả về mà không biến đổi thêm (để loại mã 10 ra khỏi xâu) thì sẽ bị sai ngay, hơn nữa khi đến dòng cuối cùng của file thì vì sau dòng này sẽ không có dấu xuống dòng nên hàm fgets sẽ đọc đúng chiều dài của xâu, vì vậy ta phải loại trừ thêm trường hợp này nữa. Như vậy tóm lại là mình phải đi đường vòng khá mệt
=> tui nghĩ nếu đúng như bạn nói thì chỉ cần thêm :
len=strlen(s); if (s[len-1] == '\n') { s[len-1] = 0; }


tuy vậy nhưng mình vẫn thử fgets rồi nhưng không thể chạy được (chẳng hiểu vì sao nữa !?)
=> bạn có thể post cách bạn đã làm được không ?

(có gì sai sót xin các bạn chỉ giúp, cám ơn nhiều)

-thân

litle
03-12-2004, 15:13
Chào bạn!

Mình xin góp 1 ý kiến nhỏ như sau:
1. Nếu file của bạn là file text, thi để đọc 1 dòng text (đọc luôn cả khoảng trắng) bạn nên dùng hàm fgets(...)
2. Bạn nên lưu file dulieu.dat ở dạng nhị phân thì khi đọc bạn đỡ phiền toái hơn.

Chúc bạn thành công nhé.

thanh dat
13-02-2005, 00:33
Xin đóng góp chút ý kiến :
Nên dùng kiểu nhị phân với các mảng , cấu trúc .... và dùng fread , fwrỉte để thao tác
Trước hàm fgets() nên có fflush(stdin) để xoá bộ đệm tránh gây lỗi .
Chúc thành công !