Trong bài viết này, chúng ta sẽ tìm hiểu về hàm gets() trong ngôn ngữ lập trình C++. Đây là một hàm được sử dụng để đọc các ký tự từ thư viện chuẩn vào chuỗi.
I. Hàm Gets() trong C++ là gì?
Hàm gets() thuộc thư viện cstdio trong C++, vì vậy trước khi sử dụng hàm này, chúng ta cần khai báo thư viện cstdio như sau: #include
.
Hàm char *gets(char *str)
trong thư viện C chuẩn được sử dụng để đọc một dòng từ nguồn dữ liệu chuẩn và lưu trữ nó bên trong một chuỗi được trỏ bởi str
. Hàm này sẽ dừng lại khi gặp ký tự kết thúc dòng hoặc ký tự newline (dòng mới).
Hàm gets() có một khác biệt so với hàm scanf() là nó cho phép chấp nhận chuỗi có chứa khoảng trống.
II. Cú pháp hàm Gets() trong C++
Hàm gets() được sử dụng để đọc các ký tự từ nguồn dữ liệu chuẩn và lưu trữ chúng cho đến khi gặp ký tự kết thúc dòng. Hàm gets() không cung cấp hỗ trợ để ngăn chặn tràn bộ đệm nếu chuỗi đầu vào quá lớn.
Cú pháp:
char* gets(char* str);
Trong đó:
str
: Con trỏ đến một mảng ký tự để lưu trữ các ký tự đầu vào từ nguồn dữ liệu chuẩn.
Hàm trả về:
- Khi thành công, hàm gets() trả về con trỏ đến chuỗi
str
. - Khi thất bại, hàm gets() trả về giá trị
NULL
.
Ví dụ: Khi chúng ta muốn yêu cầu người dùng nhập vào họ và tên, chúng ta có thể sử dụng hàm gets() kết hợp với câu lệnh cout
.
char str[100];
cout "Nhập vào họ tên của bạn: ";
gets(str);
Như vậy, khi chạy chương trình, người dùng sẽ được yêu cầu nhập từ bàn phím.
III. Ví dụ hàm Gets() trong C++
Chương trình minh họa dưới đây sử dụng hàm gets() trong C để nhập và xuất chuỗi. Bạn sẽ thấy rằng hàm gets() chấp nhận chuỗi có chứa khoảng trống, không giống như hàm scanf().
#include
int main() {
char str[50];
printf("Nhập một chuỗi: ");
gets(str);
printf("Bạn vừa nhập chuỗi: %s", str);
return 0;
}
IV. Hướng dẫn xử lý lỗi khi sử dụng hàm Gets() và Cin.Getline() trong C & C++
Ví dụ với thư viện stdio.h
#include
struct sinhvien {
char hoten[50];
char ngaysinh[20];
float cannang;
};
void Xuat1SV(sinhvien x) {
printf("Tên Sinh Viên: %s\n", x.hoten);
printf("Ngày sinh: %s\n", x.ngaysinh);
}
void Nhap1SV(sinhvien &x) {
float cn;
printf("Tên Sinh Viên: ");
gets(x.hoten);
printf("Ngày sinh: ");
gets(x.ngaysinh);
printf("Cân nặng: ");
scanf("%f", &cn);
x.cannang = cn;
}
int main() {
sinhvien dssv[3];
int i = 0;
// Nhập SV
for (i = 0; i 3; i++) {
printf("Nhập sinh viên thứ %d\n\n", i + 1);
Nhap1SV(dssv[i]);
printf("\n");
}
return 0;
}
Ví dụ với thư viện iostream.h
#include
struct sinhvien {
char hoten[50];
char ngaysinh[20];
float cannang;
};
void Xuat1SV(sinhvien x) {
cout "Tên Sinh Viên: " x.hoten endl;
cout "Ngày sinh: " x.ngaysinh endl;
}
void Nhap1SV(sinhvien &x) {
float cn;
cout "Tên Sinh Viên: ";
cin.getline(x.hoten, 50);
cout "Ngày sinh: ";
cin.getline(x.ngaysinh, 20);
cout "Cân nặng: ";
cin >> cn;
x.cannang = cn;
cin.ignore();
}
int main() {
sinhvien dssv[3];
int i = 0;
// Nhập SV
for (i = 0; i 3; i++) {
cout "Nhập sinh viên thứ " i + 1 endl "-" endl;
Nhap1SV(dssv[i]);
cout endl;
}
return 0;
}
Khi chạy các ví dụ trên, bạn sẽ thấy rằng sau khi nhập sinh viên đầu tiên, chương trình bỏ qua bước nhập tên sinh viên thứ 2 và chuyển sang nhập ngày sinh luôn.
Điều này có thể được giải thích như sau:
Khi bạn nhập một ký tự từ bàn phím, ký tự đó sẽ được chuyển vào một trong hai nơi: bộ đệm bàn phím hoặc tệp dữ liệu chuẩn (stdin). Nhưng làm sao để biết ký tự bạn nhập sẽ được gửi vào đâu? Câu trả lời là nếu bạn nhập ký tự trong khi máy tính đang chờ trước những hàm scanf, gets, getchar, thì máy tính sẽ gửi ký tự đó vào tệp dữ liệu chuẩn (stdin). Nếu không phải là ba hàm này, ký tự sẽ được gửi vào bộ đệm bàn phím. Tệp dữ liệu chuẩn (stdin) có những đặc điểm sau:
- Nếu trên stdin còn dư dữ liệu (tức là bạn bấm nhiều phím bất kỳ), các hàm trên sẽ chỉ nhận một phần dữ liệu mà chúng yêu cầu. Các ký tự còn lại vẫn nằm trên stdin.
- Khi tệp stdin chưa đủ dữ liệu, máy tính sẽ chờ cho đến khi người dùng nhập đủ dữ liệu.
Khi bạn nhập ví dụ như sau: 45
và nhấn Enter cho hàm cin, ký tự 45
sẽ được gán cho thuộc tính cân nặng. Nhưng ký tự Enter vẫn còn lưu lại trên tệp stdin hoặc bộ đệm, và hàm cin.getline (gets) sẽ nhận nó và làm trôi câu lệnh cin.getline (gets) đi. Vì vậy, dù bạn muốn nhập gì đó cho chuỗi họ tên, bạn không thể làm được.
Cách giải quyết chính là làm sạch tệp stdin và bộ đệm buffer.
Đối với thư viện stdio.h bị lỗi với hàm gets(), chúng ta có thể chèn
fflush(stdin);
sau hàm nhập số liền kề với gets().
Đối với thư viện iostream.h bị lỗi với cin.getline(), chúng ta có thể chèn
cin.ignore();
sau hàm nhập số trước cin.getline() liền kề sau nó để xóa bộ đệm.
Kết quả sau khi chèn cin.ignore():
#include
struct sinhvien {
char hoten[50];
char ngaysinh[20];
float cannang;
};
void Xuat1SV(sinhvien x) {
cout "Tên Sinh Viên: " x.hoten endl;
cout "Ngày sinh: " x.ngaysinh endl;
}
void Nhap1SV(sinhvien &x) {
float cn;
cout "Tên Sinh Viên: ";
cin.getline(x.hoten, 50);
cout "Ngày sinh: ";
cin.getline(x.ngaysinh, 20);
cout "Cân nặng: ";
cin >> cn;
x.cannang = cn;
cin.ignore();
}
int main() {
sinhvien dssv[3];
int i = 0;
// Nhập SV
for (i = 0; i 3; i++) {
cout "Nhập sinh viên thứ " i + 1 endl "-" endl;
Nhap1SV(dssv[i]);
cout endl;
}
return 0;
}
Kết quả sau khi chèn fflush(stdin)
:
#include
struct sinhvien {
char hoten[50];
char ngaysinh[20];
float cannang;
};
void Xuat1SV(sinhvien x) {
printf("Tên Sinh Viên: %s\n", x.hoten);
printf("Ngày sinh: %s\n", x.ngaysinh);
}
void Nhap1SV(sinhvien &x) {
float cn;
printf("Tên Sinh Viên: ");
gets(x.hoten);
printf("Ngày sinh: ");
gets(x.ngaysinh);
printf("Cân nặng: ");
scanf("%f", &cn);
x.cannang = cn;
fflush(stdin);
}
int main() {
sinhvien dssv[3];
int i = 0;
// Nhập SV
for (i = 0; i 3; i++) {
printf("Nhập sinh viên thứ %d\n\n", i + 1);
Nhap1SV(dssv[i]);
printf("\n");
}
return 0;
}
V. Bài tập về hàm Gets() trong C++
Ví dụ:
Chương trình C dưới đây minh họa cách sử dụng hàm gets() trong C. Bạn sẽ thấy rằng hàm gets() chấp nhận chuỗi có chứa khoảng trống, không giống như hàm scanf().
#include
int main() {
char str[50];
printf("Nhập một chuỗi: ");
gets(str);
printf("Bạn vừa nhập chuỗi: %s", str);
return 0;
}