Không hiểu lỗi sai trong code sau khi chạy debug

Chào mọi người. Mình đang làm cái game nho nhỏ trong tập tài liệu tự học ở trên diễn đàn. Nó như này :


Mình tạo 1 file text danh sách từ bí mật và chọn random. Nói chung code chạy ok. Sau đó mình tạo thêm 1 file text khác chứa những gợi ý tương ứng cho các từ bí mật và rút gọn code, tạo thêm các function con để cải tiến game, lúc này thì code chạy sai. Mình chạy debug thì nó sai từ đoạn này :

FILE *taptin = NULL;
    FILE *goi_y = NULL;
    goi_y = fopen("GoiY_Nguoitreoco.txt","r+");
    taptin = fopen("Nguoitreoco.txt","r+");
    int dem_Tu = 0,so_batky = 0;
    dem_Tu = dem_tu_bitmat(taptin);
    srand(time(NULL));
    so_batky = (rand() % (dem_Tu - min +1)) + min;
    char *Chu_bimat = NULL;
    char *an_chu_bimat = NULL;
    char *Goiy_tubimat = NULL;
    long dodai = 0;
    if(taptin != NULL)
    {
        Chu_bimat = chon_tu_bimat(taptin,so_batky);
        printf("%s\n",Chu_bimat);
        dodai = strlen(Chu_bimat);
        Goiy_tubimat = goiy_tubimat(goi_y,so_batky);
    }
    // Sau khi tao duoc chu bi mat. Ẩn chữ đó bằng các dấu *
    an_chu_bimat = anChu_bimat(dodai);

Các function con như này :

char nhap_kytu()
{
    char kytu = 0;
    do
    {
        kytu = toupper(getchar());
    }
    while(getchar() != '\n');
    return kytu;
}
int dem_chu(char taptin1[], char chu_cai)
{
    int i = 0, dem = 0;
    do
    {
        if(chu_cai == taptin1[i])
            dem++;
        i++;
    }
    while(taptin1[i] != '\0');
    return dem;
}
int dem_tu_bitmat(FILE *taptin2)
{
    int dem_tu = 0, c = 0;
    do
    {
        c = fgetc(taptin2);
        if(c == '\n')
            dem_tu++;
    }
    while(c != EOF);
    return dem_tu;
}
char *chon_tu_bimat(FILE *taptin3, int so_batky1)
{
    char *pointer = NULL;
    char chu_bimat[SO_KYTUMAX] = "";
    rewind(taptin3);
    for(int k = 1; k <= so_batky1; k++)
        fgets(chu_bimat,SO_KYTUMAX,taptin3);
    pointer = &chu_bimat[0];
    return pointer;
}
char *goiy_tubimat(FILE *taptin4, int so_batky2)
{
    char *pointer1 = NULL;
    char goiy[SO_KYTUMAX] = "";
    rewind(taptin4);
    for(int h = 1; h <= so_batky2; h++)
        fgets(goiy,SO_KYTUMAX,taptin4);
    pointer1 = &goiy[0];
    return pointer1;
}
char *anChu_bimat(int dodai1)
{
     char *pointer2 = NULL;
     char *anChu_Bimat = NULL;
     anChu_Bimat = malloc(dodai1*sizeof(int));
     int i = 0;
     for (i = 0; i < dodai1 - 1; i++)
        anChu_Bimat[i] = '*';
     anChu_Bimat[i] = 0;
     pointer2 = &anChu_Bimat[0];
     return pointer2;

+) Bước tạo từ bí mật vẫn ok :


+) Tới bước lấy ra câu gợi ý thì nó bị như này :

+) Và tới bước ẩn thì bị như này :

Không hiểu sao tất cả lại ghi đè lên nhau như vậy. Mọi người chỉ giúp. Mình cảm ơn!
P/S : Mình có nên up cả 2 cái file text và full code lên không nhỉ? Liệu có cần thiết ko?

Đây là mảng local :smiley: tức là đều bị tiêu hủy khi rời khỏi hàm.

1 Like

Mình biết, nên mình đã để hàm return về 1 pointer mà bạn :smiley: Hàm này vẫn hoạt động bình thường nếu để nó đứng 1 mình, lỗi xảy ra sau khi mình thêm cái hàm chọn gợi ý vào sau hàm này, bạn chạy debug thì thấy ngay mà.

Cả hai khai báo:

char chu_bimat[SO_KYTUMAX] = "";
// của chon_tu_bịmất()

Và:

char goiy[SO_KYTUMAX] = "";
// của goiy_tubịmất()

Đều “vô tình” trỏ vào một (mảng) ô nhớ. Và cả 2 đều trả về cùng 1 giá trị con trỏ đó :smiling_imp:
Có lẽ do khai báo giống nhau quá (trừ tên) nên máy nó bảo:

Nên khai báo toàn cục, tránh bị dùng chung đồ bỏ (thực sự vẫn dùng).

Không phải :slight_smile: đó là duy ý chí thôi. Trước khi callee rút ra thì phải trả lại số mem ấy đã.

Cũng như không :smiley:

Ơ hơ, bác Phát diễn đạt dân dã quá. Còn bác rogp10 ơi, trước đó mình vẫn dùng hàm đó để đưa ra từ, và chương trình vẫn chạy ok mà. Mình hiểu ý cậu nói nó là biến local, khi hàm kết thúc nó sẽ xóa chuỗi đó và return lại pointer chỉ vào 1 vùng mem trống đúng ko? Nhưng vậy tại sao trong bảng watches kia thì lúc đầu nó vẫn gọi ra được từ mình cần? Và trước đó khi chưa thêm phần gợi ý, code đã chạy ok như yêu cầu rồi, và mình cũng dùng hàm đó

C/C++ mà căn cứ vào tiêu chí “chạy được là đúng” thì có ngày tiêu mà không hiểu vì sao. Còn giải thích trên là gượng ép, không phù hợp quy luật khách quan. Đồng ý bạn thêm phần gợi ý thì mới thấy nhưng lỗi đã có sẵn từ đầu, nó chưa phát tác thôi. Nên lấy một số địa chỉ trong hàm lấy gợi ý thì sẽ thấy rõ.

Cái này phải xuống thấp hơn 1 nấc là assembly. Một hàm chạy sẽ đón nhận tham số từ thanh ghi, sau đó tự lấy số mem nó cần cho các biến nội (bao gồm mấy con trỏ), bằng cách cộng thêm vào thanh ghi stack. Cuối cùng nó trừ hết số byte đó để trả lại trạng thái ban đầu.

1 Like

Vậy để mình nghiên cứu thêm lời bác :slight_smile: trong trường hợp này phải dùng biến global ah. Có cách nào sửa lại hàm con ko nhỉ?

Chép sang ô nhớ khác. Tính độ dài của mảng kí tự (chuỗi) đó rồi tạo mảng mới dựa vào độ dài rồi chép qua.

Thêm tham số chuỗi vào hàm là được.

2 Likes

thank 2 bác. Để mình ngồi coi lại. Bác rogp10 lần nào hỏi cũng trả lời nhiệt tình, thank bác nha.

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?