30/09/2018, 16:12

Dùng C đọc dữ liệu từ file lên bị lỗi?

Em có một bài tập, đề bài như sau ạ:

Lập trình thực hiện các nhiệm vụ sau

  • Định nghĩa một kiểu cấu trúc Sinhvien gồm
  • dtb (điểm trung bình theo thang 4.0 - kiểu float)
  • masv, hoten là kiểu xâu kí tự
typedef struct
{
    char masv[7];
    char hoten[32];
    float dtb;
} Sinhvien;
  • Định nghĩa một kiểu cấu trúc Lop gồm có:
  • dssv là một mảng con trỏ cấu trúc Sinhvien*
  • siso là số sinh viên trong danh sách
const int MAX = 80;
typedef struct
{
    Sinhvien dssv[MAX];
    char tenlop[8];
    int n;
} Lop;
  • Đầu vào của chương trình là tệp SV.inp có định dạng như sau

Dòng 1: tên lớp
Dòng 2: sĩ số

  • Các dòng tiếp theo: Mã số SV, họ tên, điểm trung bình

56PM
65
484756
Nguyen Van Hung
3.3


Lập chương trình bao gồm các hàm sau

a. Hàm nhập thông tin từ tệp tin vào một biến cấu trúc Lop gồm: tên lớp, sĩ số n, và thông tin của n sinh viên vào trong danh sách sinh viên . Với mỗi sinh viên cần nhập đầy đủ thông tin như: mã số, họ tên, điểm trung bình

void nhap_dssv (Lop* lop);
// tham số lop là đại diện cho địa chỉ của 1 biến cấu trúc sẽ lưu thông tin

b. Hàm sắp xếp danh sách sinh viên theo thứ tự điểm trung bình giảm dần

void sapxep_dssv(Sinhvien ds[], int n);

c. Hàm in danh sách sinh viên theo quy cách sau:

Ma so SV | Ho ten | Diem trung binh
374754 Nguyen Van Tuan 3.5

void in_dssv(Sinhvien ds[], int n);

d. Hàm tìm kiếm trong lớp và cho kết quả là một danh sách sinh viên có điểm trung bình lớn hơn d (0 <= d <= 4.0)

void tim_diemtb(Lop* lop, float d, Sinhvien ketqua[])

e. Viết hàm main thực thi việc
i. Nhập thông tin và danh sách sinh viên của lớp
ii. Sắp xếp danh sách sinh viên trong lớp và in ra màn hình
iii. Tìm kiếm sinh viên có điểm trung bình > 2.0 và in ra tệp SV.out theo định dạng trong câu c.

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

#define MAX 80

struct SinhVien
{
    char maSV[8];
    char hoTen[50];
    float dtb;
};

struct LopHoc
{
    int siso;
    SinhVien sv[MAX];
    char tenLop[8];
};

void in_dssv(SinhVien ds[], int n)
{
    printf("%-8s%-25s%-4s"," MSSV"," Ho ten"," Diem trung binh
");
    for(int i=0; i<n; i++)
        printf("%-8s%-25s%-3.2f
",ds[i].maSV,ds[i].hoTen,ds[i].dtb);
}

void nhap_dssv(LopHoc* lop)
{
    FILE *f=fopen("SV.inp","r");
    if(f==NULL)
    {
        perror("Loi mo tep SV.inp");
        exit(1);
    }
    fflush(f);
    fgets(lop->tenLop,10,f);
    fscanf(f,"%d",&lop->siso);
    for(int i=0; i<lop->siso; i++)
    {
        fgets(lop->sv[i].maSV,10,f);
        fgets(lop->sv[i].hoTen,50,f);
        fscanf(f,"%f",&lop->sv[i].dtb);
    }
    fclose(f);
}

void sapxep_dssv(SinhVien ds[], int n)
{
    for(int i=0; i<n-1; i++)
        for(int j=i+1; j<n; j++)
            if(ds[i].dtb<ds[j].dtb)
            {
                struct SinhVien tg=ds[i];
                ds[i]=ds[j];
                ds[j]=tg;
            }
    printf("
Danh sach sau khi sap xep:
");
    in_dssv(ds,n);
}

void tim_diemtb (LopHoc* lop, float d, SinhVien ketqua[])
{
    int m=0;
    for(int i=0; i<lop->siso; i++)
        if(lop->sv[i].dtb>d)
        {
            ketqua[m]=lop->sv[i];
            m++;
        }
    FILE *f=fopen("SV.out","w");
    if(f==NULL)
    {
        perror("Loi mo tep SV.out");
        exit(1);
    }
    if(m>0)
    {
        fprintf(f,"%-8s%-25s%-4s"," MSSV"," Ho ten"," Diem trung binh
");
        for(int i=0; i<m; i++)
            fprintf(f,"%-8s%-25s%-3.2f
",ketqua[i].maSV,ketqua[i].hoTen,ketqua[i].dtb);
        fclose(f);
    }
    else fprintf(f,"Khong co sinh vien nao co dtb>%3.1f
",d);
}

int main()
{
    LopHoc* lop=(LopHoc*) malloc(sizeof(LopHoc));
    SinhVien kq[MAX];
    nhap_dssv(lop);
    sapxep_dssv(lop->sv,lop->siso);
    tim_diemtb(lop,2.0,kq);
    free(lop);
    getch();
    return 0;
}

Trên đây là chương trình e viết, chạy không lỗi nhưng kết quả cứ sai tùm lum hết. T.T
anh chị nào có kinh nghiệm làm việc với file thì giúp e chỉnh sửa với đc ko ạ.
Em cảm ơn ạ.

Nguyễn Minh Dũng viết 18:14 ngày 30/09/2018

I moved a post to a new topic: Ghép nội dung của 2 files sinh ra ký tự lạ ở file thứ 2?

Nguyễn Minh Dũng viết 18:12 ngày 30/09/2018

kết quả cứ sai tùm lum hết

Em chỉ ra sai cụ thể chỗ nào, anh sẽ xem cho. Giống như bài này, em đặt câu hỏi rất cụ thể. Là có ký tự lạ ở cuối file đích. Anh đọc hiểu ngay.

Sáng Béo viết 18:17 ngày 30/09/2018

A thử copy code trên rồi chạy ví dụ với file SV.inp như sau ạ:

58PM1
2
1554558
Sang Coi
3.2
1554258
Day Nhau Hoc
2.8

chứ e ko biết miêu tả lỗi như nào cả. T.T

Nguyễn Minh Dũng viết 18:28 ngày 30/09/2018

Tối hoặc mai nhé, đang bận tí việc…

Sáng Béo viết 18:17 ngày 30/09/2018

vâng ạ.
e cũng đang học môn khác.
gần cuối kì rồi thi với kiểm tra dồn dập quá ạ. T.T

Sáng Béo viết 18:22 ngày 30/09/2018

Tối hoặc mai nhé, đang bận tí việc…

a ơi, xem giúp e với. T.T

Nguyễn Minh Dũng viết 18:19 ngày 30/09/2018

Cụ thể hợp đi @htwap, anh bận quá, anh có chạy thử rồi, thấy in ra lung tung mà không có thời gian kiểm tra xem em viết cái gì

Sáng Béo viết 18:22 ngày 30/09/2018

Cụ thể hợp đi @htwap, anh bận quá, anh có chạy thử rồi, thấy in ra lung tung mà không có thời gian kiểm tra xem em viết cái g

e cũng ko biết bị lỗi gì nữa a ạ, nêu nhập từ bàn phím thì ngon lành, e nghĩ chắc là sai chỗ lấy dữ liệu từ file ạ

Nguyễn Minh Dũng viết 18:14 ngày 30/09/2018

Em không hiểu lỗi gì mà bắt anh sửa, , nếu anh có thời gian thì anh sẽ tra dùm em. Nhưng anh bận quá, em chỉ ra lỗi cụ thể anh sửa trong 30s thì được

Sáng Béo viết 18:20 ngày 30/09/2018

bị sai chỗ lấy dữ liệu từ file a ạ, tại sai chỗ đấy nên các bước sau sai hết.
e ko biết lấy sao cho đúng. T.T

Nguyễn Minh Dũng viết 18:24 ngày 30/09/2018

bị sai chỗ lấy dữ liệu từ file a ạ,

Sai như thế nào em.

Input như thế nào? Em muốn lấy như thế nào và nó trả ra như thế nào?

Sáng Béo viết 18:26 ngày 30/09/2018

e input gồm:
+dòng đầu là số n chỉ số sinh viên
+các dòng tiếp theo cho 3 thông tin của mỗi sinh viên là mã số sinh viên, họ tên, điểm trung bình.
ví dụ:

2
14434
Sáng Còi
3.5
14443
Dạy Nhau Học
3.6

là 2 sinh viên Sáng Còi và Dạy Nhau Học.

e muốn lấy thông tin cho vào biến cấu trúc Lop gồm 2 sinh viên đó và mỗi sinh viên lại là cấu trúc gồm Mã sinh viên, họ tên và điểm.

Yêu cầu in ra:

MSSV    Họ Tên         Điểm TB
14434   Sáng Còi       3.5
14443   Dạy Nhau Học   3.6
Sáng Béo viết 18:20 ngày 30/09/2018

úp úp.

e sửa mấy ngày rồi ko đc ạ.

Nguyễn Minh Dũng viết 18:25 ngày 30/09/2018

Vẫn code cũ luôn hả @htwap?


1.Lỗi sai kích thước

fgets(lop->tenLop,10,fp); // tên lớp 8 mà em nhập vào 10

Giải pháp: #define vài cái macro để xài

#define MAX 80
#define TEN_LOP 8
#define MA_SV 8
#define HO_TEN 8

struct SinhVien
{
    char ma_sv[MA_SV];
    char ho_ten[HO_TEN];
    float trung_binh;
};

struct LopHoc
{
    int siso;
    struct SinhVien sv[MAX];
    char ten_lop[TEN_LOP];
};

Sau đó đọc vào như sau

fgets(lop->ten_lop,TEN_LOP,fp);

2.Sai cấu trúc nhập vào

Em nhập vào sai rôi, em bảo cấu trúc là

  • dòng đầu là số n chỉ số sinh viên
  • các dòng tiếp theo cho 3 thông tin của mỗi sinh viên là mã số sinh viên, họ tên, điểm trung bình.

2
14434
Sáng Còi
3.5
14443
Dạy Nhau Học
3.6

Mà vô một phát em đọc tên lớp, đâu có tên lớp đâu mà đọc?

void nhap_dssv(struct LopHoc* lop)
{
    FILE *fp=fopen("SV.in","r");
    if(!fp)
    {
        perror("Loi mo tep SV.in");
        exit(1);
    }
    fflush(fp);
    fgets(lop->ten_lop,TEN_LOP,fp);
    fscanf(fp,"%d",&lop->siso);
    for(int i = 0; i < lop->siso; i++)
    {
        fgets(lop->sv[i].maSV,10,fp);
        fgets(lop->sv[i].hoTen,50,fp);
        fscanf(fp,"%f",&lop->sv[i].trungBinh);
    }
    fclose(fp);
}

3.Struct em đâu thể gán như số int mà em phải viết hàm swap như sau

void hoan_vi(struct SinhVien* sv_a, struct SinhVien* sv_b)
{
    struct SinhVien sv_t;
    strncpy(sv_t.ho_ten, sv_a->ho_ten, HO_TEN);
    strncpy(sv_t.ma_sv, sv_a->ma_sv, MA_SV);
    sv_t.trung_binh = sv_a->trung_binh;
    
    strncpy(sv_b->ho_ten, sv_a->ho_ten, HO_TEN);
    strncpy(sv_b->ma_sv, sv_a->ma_sv, MA_SV);
    sv_b->trung_binh = sv_a->trung_binh;
    
    strncpy(sv_a->ho_ten, sv_t.ho_ten, HO_TEN);
    strncpy(sv_a->ma_sv, sv_t.ma_sv, MA_SV);
    sv_a->trung_binh = sv_t.trung_binh;
}

4.Không thể dùng fgets để đọc từng dòng, em phải viết hàm đọc từng dòng.

Anh đã viết ở đây, em phải đọc cho hiểu mới được xài.

int eof_or_line_break(char c) // kiem tra neu EOF hoac xuong hang
{
    return (c == '\n' || c == EOF);
}

int readline(char * line, int max_len, FILE *fp)
{
    char c;
    int i = 0;
    while( !eof_or_line_break(c = fgetc(fp)) && i < max_len - 1)
        line[i++] = c;
    line[i] = 0;

    if (i == max_len - 1) // neu line dai hon max_len
        while( (c = fgetc(fp)) != '\n') // bo het doan phia sau
            ;

    return i;
}

void nhap_dssv(struct LopHoc* lop)
{
    FILE *fp=fopen("SV.in","r");
    if(!fp)
    {
        perror("Loi mo tep SV.in");
        exit(1);
    }
    fflush(fp);
    readline(lop->ten_lop, TEN_LOP, fp);
    printf("ten_lop %s\n", lop->ten_lop);
    char tmp[10];
    readline(tmp, 10, fp);
    lop->siso = atoi(tmp);
    printf("siso %d\n", lop->siso);

    for(int i = 0; i < lop->siso; i++)
    {
        readline(lop->sv[i].ma_sv, MA_SV, fp);
        printf("ma_sv %s\n", lop->sv[i].ma_sv);
        readline(lop->sv[i].ho_ten, HO_TEN, fp);
        printf("ho_ten %s\n", lop->sv[i].ho_ten);
        readline(tmp, 10, fp);
        lop->sv[i].trung_binh = atof(tmp);
        printf("trung_binh %f\n", lop->sv[i].trung_binh);
    }
    fclose(fp);
}

Em xem lại code anh sửa tới hàm nhập, hàm sắp xếp em tự kiểm tra lại

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

#define MAX 80
#define TEN_LOP 8
#define MA_SV 8
#define HO_TEN 8

struct SinhVien
{
    char ma_sv[MA_SV];
    char ho_ten[HO_TEN];
    float trung_binh;
};

struct LopHoc
{
    int siso;
    struct SinhVien sv[MAX];
    char ten_lop[TEN_LOP];
};

int eof_or_line_break(char c) // kiem tra neu EOF hoac xuong hang
{
    return (c == '\n' || c == EOF);
}

int readline(char * line, int max_len, FILE *fp)
{
    char c;
    int i = 0;
    while( !eof_or_line_break(c = fgetc(fp)) && i < max_len - 1)
        line[i++] = c;
    line[i] = 0;

    if (i == max_len - 1) // neu line dai hon max_len
        while( (c = fgetc(fp)) != '\n') // bo het doan phia sau
            ;

    return i;
}

void nhap_dssv(struct LopHoc* lop)
{
    FILE *fp=fopen("SV.in","r");
    if(!fp)
    {
        perror("Loi mo tep SV.in");
        exit(1);
    }
    fflush(fp);
    readline(lop->ten_lop, TEN_LOP, fp);
    printf("ten_lop %s\n", lop->ten_lop);
    char tmp[10];
    readline(tmp, 10, fp);
    lop->siso = atoi(tmp);
    printf("siso %d\n", lop->siso);

    for(int i = 0; i < lop->siso; i++)
    {
        readline(lop->sv[i].ma_sv, MA_SV, fp);
        printf("ma_sv %s\n", lop->sv[i].ma_sv);
        readline(lop->sv[i].ho_ten, HO_TEN, fp);
        printf("ho_ten %s\n", lop->sv[i].ho_ten);
        readline(tmp, 10, fp);
        lop->sv[i].trung_binh = atof(tmp);
        printf("trung_binh %f\n", lop->sv[i].trung_binh);
    }
    fclose(fp);
}

void hoan_vi(struct SinhVien* sv_a, struct SinhVien* sv_b)
{
    struct SinhVien sv_t;
    strncpy(sv_t.ho_ten, sv_a->ho_ten, HO_TEN);
    strncpy(sv_t.ma_sv, sv_a->ma_sv, MA_SV);
    sv_t.trung_binh = sv_a->trung_binh;

    strncpy(sv_b->ho_ten, sv_a->ho_ten, HO_TEN);
    strncpy(sv_b->ma_sv, sv_a->ma_sv, MA_SV);
    sv_b->trung_binh = sv_a->trung_binh;

    strncpy(sv_a->ho_ten, sv_t.ho_ten, HO_TEN);
    strncpy(sv_a->ma_sv, sv_t.ma_sv, MA_SV);
    sv_a->trung_binh = sv_t.trung_binh;
}

void in_dssv(const struct SinhVien ds[], int n)
{
    printf("%-8s%-25s%-4s"," MSSV"," Ho ten"," Diem trung binh\n");
    for(int i = 0; i < n; i++)
        printf("%-8s%-25s%-3.2f\n",ds[i].ma_sv,ds[i].ho_ten,ds[i].trung_binh);
}

void sapxep_dssv(struct SinhVien dssv[], int n)
{
    printf("\nDanh sach truoc khi sap xep:\n");
    in_dssv(dssv,n);

    for(int i=0; i<n-1; i++)
        for(int j=i+1; j<n; j++)
            if(dssv[i].trung_binh < dssv[j].trung_binh)
                hoan_vi(&dssv[i], &dssv[i]);

    printf("\nDanh sach sau khi sap xep:\n");
    in_dssv(dssv,n);
}

void tim_diemtb (struct LopHoc* lop, float d, struct SinhVien ketqua[])
{
    int m=0;
    for(int i=0; i<lop->siso; i++)
        if(lop->sv[i].trung_binh>d)
        {
            ketqua[m]=lop->sv[i];
            m++;
        }
    FILE *f=fopen("SV.out","w");
    if(f==NULL)
    {
        perror("Loi mo tep SV.out");
        exit(1);
    }
    if(m>0)
    {
        fprintf(f,"%-8s%-25s%-4s"," MSSV"," Ho ten"," Diem trung binh\n");
        for(int i=0; i<m; i++)
            fprintf(f,"%-8s%-25s%-3.2f\n",ketqua[i].ma_sv,ketqua[i].ho_ten,ketqua[i].trung_binh);
        fclose(f);
    }
    else fprintf(f,"Khong co sinh vien nao co dtb>%3.1f\n",d);
}

int main()
{
    struct LopHoc lophoc;
    struct SinhVien kq[MAX];
    nhap_dssv(&lophoc);
    sapxep_dssv(lophoc.sv,lophoc.siso);
    tim_diemtb(&lophoc,2.0,kq);
    getchar();
    return 0;
}
Sáng Béo viết 18:24 ngày 30/09/2018

3.Struct em đâu thể gán như số int mà em phải viết hàm swap như sau

sao struct e vẫn gán thẳng dc mà a @@

Nguyễn Minh Dũng viết 18:17 ngày 30/09/2018

Yeah, vì em may mắn là struct của em đơn giản, không có con trỏ. Có mảng, nhưng là mảng tĩnh. Nên việc copy tương tự như copy memory. Nhưng nếu em sử dụng con trỏ char * ho_ten; thì việc gán như vậy không đảm bảo.

Sáng Béo viết 18:20 ngày 30/09/2018

Yeah, vì em may mắn là struct của em đơn giản, không có con trỏ. Có mảng, nhưng là mảng tĩnh. Nên việc copy tương tự như copy memory. Nhưng nếu em sử dụng con trỏ char * ho_ten; thì việc gán như vậy không đảm bảo.

vâng, e sẽ lưu ý ạ.
thank a nha

Nguyễn Minh Dũng viết 18:23 ngày 30/09/2018

I moved 2 posts to a new topic: Dùng hàm gì để đổi ký tự trong C++?

Bài liên quan
0