Viết chương trình tính tần số của mỗi tiếng

Chào mọi người, em có làm cái code như này mà không hiểu sao chỉ có 3/10 test case đúng, khi test bằng CodeBlocks nó còn ra kết quả kèm mấy char rác kì lắm ạ :frowning:
Mọi người giúp giải thích giúp em tại sao nó lại có char rác với làm sao khắc phục với ạ! ><

Note: Em không được dùng các hàm có sẵn của cstring ạ!

(Ngôn ngữ C++)
Hình ảnh test

Code

#include <iostream>
using namespace std;
#define MAX 300
  
void DemTieng(char s1[]);
int myStrcmp(char s1[], char s2[]);


int main()
{
 char s[MAX];
 fgets(s,MAX,stdin);
 if (myStrcmp(s, "") == 0)
     cout << "Chuoi rong." << endl;
 else
     DemTieng(s);
 return 0;
}

int myStrcmp(char s1[], char s2[])
{
    if (s1[0] == '\n')
        return 0;

    for (int i = 0; s1[i] != 0; i++)
    {
        if (s1[i] != s2[i] && s1[i] > s2[i])
            return 1;
        else if (s1[i] != s2[i] && s1[i] < s2[i])
            return -1;
    }

    return 0;
}

void DemTieng(char s1[])
{
    char tieng[MAX][10];
    int soTieng = 0;
    int k = 0;

    //luu tru tung tieng trong cau
    for (int i = 0; s1[i] != 0; i++)
    {
        if (s1[i] != ' ')
        {
            if (s1[i] == '\n')
                break;

            tieng[soTieng][k] = s1[i];
            k = k + ((s1[i+1] == ' ' || s1[i+1] == '\n') ? 0 : 1);
        }
        else
       {
            soTieng++;
            k = 0;
        }
    }

    int dem;
    char *temp = new char [soTieng]; //mang danh dau cac vi tri trung lap, vi tri trung danh dau '1', khong trung la NULL

    //kiem tra tan so tung tieng
    for (int i = 0; i <= soTieng; i++)
   {
        dem = 0;

        //neu tieng nay da xet qua roi thi bo qua
        if (temp[i] != '1')
        {
            for (int m = i; m <= soTieng; m++)
            {
                //neu tieng nay chua tung xet qua va trung lap voi tieng dang xet thi tang bien dem
                if (temp[m] != '1' && myStrcmp(tieng[i], tieng[m]) == 0)
                {
                    dem++;
                    temp[m] = '1';  //neu day la tieng lan dau tien xet qua thi danh dau vi tri cua no de lan sau khong xet nua
                }
            }

            cout << tieng[i] << ": " << dem << endl;
        }
    }
}
  1. Bạn chưa xét trường hợp str2[i] == 0 trong myStrcmp.
  2. Chuỗi C quy ước kết thúc bằng '\0' và mỗi tieng[i] cũng vậy. (chỗ lấy danh sách tiếng)
5 Likes

Cảm ơn cậu đã giúp đỡ, nhưng cho mình thắc mắc tại sao lại phải xét str2[i] == 0 trong myStrcmp vậy cậu? Cậu có thể giải thích giúp mình không?

Vì nếu xâu 2 ngắn hơn xâu 1, cậu nên ngừng việc so sánh ở thời điểm đó. So sánh str2[i] == 0 là để phát hiện xem xâu 2 đã kết thúc chưa đó cậu :smile:

Hope it helps!

4 Likes

Awww thank youu :smiling_face_with_three_hearts: :smiling_face_with_three_hearts:
Nhưng mà khi mình chạy vài test case mới 2 chuỗi không bằng nhau thì nó vẫn cho ra kết quả giống với strcmp gốc á :<
Không biết là nếu thiếu trường hợp đó thì có ảnh hưởng gì nhiều không nhỉ cậu? :cold_sweat:

Nếu test của cậu là str1 dài hơn str2, thì code của cậu chạy được.
Nếu test của cậu là str2 dài hơn str1, cậu có khả năng sẽ truy cập vào 1 vùng nhớ không phải của str2 (vì cậu duyệt lần lượt các phần tử của str1 mà) => khả năng cậu sẽ bị segmentation fault.
Đó là ảnh hưởng nếu cậu không xét TH đó :smile:

4 Likes

Ồ ra là vậy :crazy_face: Mình hiểu rồi cảm ơn bạn đã giải thích nha :stuck_out_tongue:

1 Like

hình như chữ “là” với chữ “làm” của bạn đang được so sánh là bằng nhau thì phải.

2 Likes

Đúng rồi bạn, mình cũng không hiểu tại sao lại bị vậy nhưng sau khi mình khai báo chuỗi char tieng[MAX][10] = {0} và sửa lại hàm myStrcmp của mình thì hết bị lỗi này rồi đấy bạn. Mình nghĩ lỗi do hàm đó hehe :3

Anyway, lí do mình chỉ có 3/10 test case ngoài 3 lý do các bạn tìm ra ở trên thì còn 1 cái nữa là mình phải xóa mấy khoảng trống thừa ở đầu, cuối và bỏ qua mấy khoảng trống thừa ở giữa, nếu không thì compiler nó sẽ ra sai kết quả ấy, vì nó sẽ lưu các khoảng trống đó thành 1 tiếng và đếm luôn các “tiếng” đó á XD

Hàm myStrcmp mới của mình nếu các bạn muốn tham khảo

int myStrcmp(char s1[], char s2[])
{
    //chuoi rong
    if (s1[0] == '\n' || s1[0] == 0)
        return 0;

    if (myStrlen(s1, 0) > myStrlen(s2, 0))
        return 1;
    else if (myStrlen(s1, 0) < myStrlen(s2, 0))
        return -1;

    for (int i = 0; s1[i] != '\0'; i++)
    {
        if (s1[i] > s2[i])
            return 1;
        else if (s1[i] < s2[i])
            return -1;
    }
    return 0;
}

Bạn đăng hàm myStrcmp khiến mình tò mò về hàm myStrlen hơn, tại sao lúc nào tham số thứ 2 cũng truyền vào 0. Bạn có thể đăng cả hàm đó đc ko? :))))

Hàm myStrlen của mình cũng giống bình thường thôi cậu ơi :crazy_face: , 0 là vị trí bắt đầu đếm thôi á cậu, do template bên trường mình bắt phải có cái vị trí í mà :crazy_face:
Đây là hàm myStrlen của mình này, như cậu thấy thì tham số k chính là vị trí bắt đầu đếm á

int myStrlen(char s[], int k)
{
    int dem = 0;
    for (int i = k; s[i] != '\0'; i++)
        dem++;
    return dem;
}
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?