Chủ Nhật, 5 tháng 5, 2024

41. Chương trình tào lao với vòng lặp, mảng, hàm...và chuỗi C++ phần 2

Nhắc lại:

Chương trình chưa hoàn hảo thật sự:

  • Mảng sinhVien[] là cho sẵn, chúng ta cần thật sự là một mảng bất kỳ do người sử dụng nhập vào
  • Tổng số phần tử của mảng mặc định là 3, nếu số sinh viên khác thì chương trình sẽ hoạt động sai.

Chúng ta cần biết kích thước của mảng. Tức là ta cần biết số sinh viên. Đơn giản là hỏi người sử dụng số sinh viên và lưu vào một biến. Để bạn quen với cách viết hàm, chúng ta sử dụng hàm cho công việc "dễ ẹc" này

Chúng ta cần một hàm mà giá trị trả về sẽ là một số nguyên int, đai diện cho số sinh viên.
Khai báo hàm sẽ như sau, chúng ta đặt trên main()

    // Khai báo hàm 2
    int soSinhVien();




Định nghĩa hàm, chúng ta sẽ đặt dưới main() . Tạm thời sử dụng return 1.

    // Định nghĩa hàm 2
    int soSinhVien(){

    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    return 1;

    }

Sau khi thêm vào, chương trình sẽ như sau

#include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }        
danhSach(sinhVien); // Lời gọi hàm
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){

    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    return 1;

}



Chúng ta sẽ chạy thử chương trình. Mọi thứ đều ổn

 


 

Bây giờ ta sẽ định nghĩa hàm. 

  • Chúng ta khai báo một biến int tongSo;
  • Sau đó dùng lệnh cin để nhận dữ liệu người dùng nhập vào.
  • Cuối cùng dùng lệnh return tongSo; 

Đến lúc này, chương trình sẽ như sau:

 

#include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }        
danhSach(sinhVien); // Lời gọi hàm
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){
    int tongSo;
    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    cout <<"Hãy nhập tổng số sinh viên:  " << endl;
    cin >> tongSo;
    return tongSo;

    
}


Bấm Run để chạy chương trình, mọi thứ ổn. Tuy nhiên ta cần kiểm tra xem hàm có hoạt động đúng không. Ta cần thêm một lệnh cout và lời gọi hàm.

Chương trình của chúng ta sẽ như thế này:


#include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }        
danhSach(sinhVien); // Lời gọi hàm
soSinhVien(); // loi goi ham 2
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){
    int tongSo;
    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    cout <<"Nhap tong so sinh viên:  " << endl;
    cin >> tongSo;
    cout << "Tong so sinh vien là : " << tongSo << endl;
    return tongSo;
    
}


Bấm Run để chạy chương trình. Mọi thứ rất ổn.

 


 

Vì chương trình của chúng ta có tên là...tào lao, nên ta cứ giữ nguyên mọi thứ, chỉ đắp thêm các nguyên vật liệu khác mà thôi!

Tiếp theo, ta sẽ khai báo một biến số nguyên int size;
Sau đó ta sẽ gán giá trị trả về từ hàm tongSo() cho biến size.
Chúng ta cũng xóa bỏ lời gọi hàm soSinhVien() trong chương trình cũ. Giờ đây chương trình của chúng ta sẽ thế này

#include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }      
int size;
size = soSinhVien();  

danhSach(sinhVien); // Lời gọi hàm
//soSinhVien(); // loi goi ham 2
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){
    int tongSo;
    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    cout <<"Nhap tong so sinh viên:  " << endl;
    cin >> tongSo;
    cout << "Tong so sinh vien là : " << tongSo << endl;
    return tongSo;
    
}



Bấm Run để chạy chương trình

 
 
Ta sẽ khai báo một mảng chuỗi sinhVien2[] với kích thước là size; 
string sinhVien2[size];
 
Lý do chúng ta đặt tên sinhVien2[] vì bản chất chương trình là...tào lao, chúng tôi muốn giữ nguyên mang sinhVien[] khai sẵn giờ đây đã thừa vì không còn sử dụng để bạn hình dung từng bước. Nếu muốn bạn hoàn toàn có thể xóa nó.

 
Chúng ta sử dụng vòng lặp For và lệnh getline() để thêm các phần tử (Tên sinh viên) cho mảng sinhVien2[].
 
Đây là chương trình. 
 
#include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }      
int size;
size = soSinhVien();  
string sinhVien2[size];
for(int i = 0; i < size; i++){
       
        cout <<"Nhap Ho Va Ten Sinh Vien[" << i << "]" << endl;
        getline(cin, sinhVien2[i]);
        cout <<"Xin chao: "<< sinhVien2[i] << endl;
       

}

danhSach(sinhVien); // Lời gọi hàm
//soSinhVien(); // loi goi ham 2
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){
    int tongSo;
    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    cout <<"Nhap tong so sinh viên:  " << endl;
    cin >> tongSo;
    cout << "Tong so sinh vien là : " << tongSo << endl;
    return tongSo;
    
}


Khi chạy thử bạn sẽ thấy bị lỗi.
 


 

Đây gọi là lỗi Trôi Lệnh.
Xử Lý Trôi Lệnh
 
Nguyên nhân :

Hàm getline() khi bạn nhập chuỗi sẽ dừng nhập cho tới khi nó gặp được ký tự xuống dòng (enter), những ký tự nó đọc được từ luồng vào cin cho tới kí tự enter đó sẽ được gán cho chuỗi.

Khi bạn nhập cin >> n sau đó ấn enter, thì giá trị mà bạn vừa nhập sẽ được gán cho n tuy nhiên ký tự enter ở cuối bạn nhập sẽ nằm trong luồng vào cin, khi hàm getline() đọc từ luồng cin thì sẽ gặp ký tự enter này do cin ở câu lệnh trên để lại.

Do getline() sẽ dừng nhập khi gặp enter nên nó sẽ dừng ngay tại lúc đó mà chưa hề nhập được ký tự nào và dẫn đến chuỗi của chúng ta là một chuỗi rỗng

Vậy nếu trước hàm getline() mà trong luồng cin có thừa kí tự enter(thông thường do cin ở câu lệnh trước đó để lại) thì sẽ xảy ra trôi lệnh.

Lưu ý rằng nếu bạn dùng câu lệnh getline() sau một câu lệnh getline() thì bạn sẽ không bị trôi lệnh vì hàm getline() sẽ xử lý ký tự enter ở cuối dòng chứ không để lại trong luồng vào như câu lệnh cin.

Cách khắc phục :

Khi bạn biết nguyên nhân getline() bị trôi lệnh là do đọc phải ký tự enter thừa trong luồng vào từ bàn phím nên để xử lý việc này bạn chỉ cần loại bỏ được ký tự enter này trước khi dùng getline().

Bạn có thể dùng hàm cin.ignore(1) hoặc cin.ingore() để loại bỏ đi 1 ký tự trong luồng cin, khi đó ký tự enter sẽ bị loại bỏ và hàm getline() sẽ đợi bạn nhập nội dung sau đó ấn enter.

Ngoài ra, giống như trong C, bạn cũng có thể sử dụng hàm scanf("\n"); hoặc getchar() vì hàm này sẽ đọc 1 ký tự trong luồng cin và đọc được ký tự enter thừa.
 
Chúng ta sẽ sử dụng scanf("\n") trong chương trình của chúng ta. Bạn thêm lệnh hàm scanf("\n"); vào trước getline(). Đây là chương trình
 
#include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }      
int size;
size = soSinhVien();  
string sinhVien2[size];
for(int i = 0; i < size; i++){
       
        cout <<"Nhap Ho Va Ten Sinh Vien[" << i << "]" << endl;
        scanf("\n");
        getline(cin, sinhVien2[i]);
        cout <<"Xin chao: "<< sinhVien2[i] << endl;
       

}
danhSach(sinhVien); // Lời gọi hàm
//soSinhVien(); // loi goi ham 2
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){
    int tongSo;
    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    cout <<"Nhap tong so sinh viên:  " << endl;
    cin >> tongSo;
    cout << "Tong so sinh vien là : " << tongSo << endl;
    return tongSo;
    
}

 
Chạy thử chương trình, bây giờ mọi thứ đã ổn. 
 
 

 
 
Để in danh sách, chúng ta truyền giá trị mảng sinhVien2[] cho hàm danhSach()



Đây là chương trình:
 
 #include <iostream>
#include <string>

using namespace std;
// Khai báo hàm
void danhSach(string sinhVien[]);
 // Khai báo hàm 2
 int soSinhVien();


int main(){
string arr[3] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};   
string sinhVien[20] = {"Nguyen Van A",
                     "Tran Van B", "Le Thi C"};                     
 for (int i = 0; i < 3; i++)
  {
    cout << "Ten: " << arr[i]<< endl;
  }      
int size;
size = soSinhVien();  
string sinhVien2[size];
for(int i = 0; i < size; i++){
       
        cout <<"Nhap Ho Va Ten Sinh Vien[" << i << "]" << endl;
        scanf("\n");
        getline(cin, sinhVien2[i]);
        cout <<"Xin chao: "<< sinhVien2[i] << endl;
       
}
danhSach(sinhVien2); // Lời gọi hàm
//soSinhVien(); // loi goi ham 2
  return 0;
    
}

// Định nghĩa hàm
void danhSach(string sinhVien[]) {

    cout << "Xin chào Dat Viet Lap Trinh! Danh sach Sinh Vien: " << endl;
    for (int i = 0; i < 3; i++)
    {
       cout << "Tên sinh viên: " << sinhVien[i] << endl;
    }
}

 // Định nghĩa hàm 2
int soSinhVien(){
    int tongSo;
    cout << "Xin chào Dat Viet Lap Trinh! Day la tong so Sinh Vien" << endl;
    cout <<"Nhap tong so sinh viên:  " << endl;
    cin >> tongSo;
    cout << "Tong so sinh vien là : " << tongSo << endl;
    return tongSo;
    
}


Chạy chương trình:



Như bạn thấy, chỉ một ý tưởng về chương trình rất đơn giản, nhưng chúng ta cũng phải "vật vã" qua 2 phần mới tạm hoàn tất.
 
 
 

 

 

Không có nhận xét nào:

Đăng nhận xét