banner

[Rule] Rules  [Home] Main Forum  [Portal] Portal  
[Members] Member Listing  [Statistics] Statistics  [Search] Search  [Reading Room] Reading Room 
[Register] Register  
[Login] Loginhttp  | https  ]
 
Forum Index Thảo luận hệ điều hành Windows [Thảo luận] Validate input data - C++  XML
  [Programming]   [Thảo luận] Validate input data - C++ 16/11/2007 04:39:14 (+0700) | #1 | 97831
FaL
Moderator

Joined: 14/04/2006 09:31:18
Messages: 1232
Offline
[Profile] [PM]
FaL lập ra topic này để thảo luận về việc kiểm tra dữ liệu nhập vào bởi người dùng trong C++.

Vấn đề đặt ra:
+ Cần nhập vào 1 số nguyên (int), làm sao để kiểm tra dữ liệu nhập vào đã đúng kiểu integer hay chưa?

Ví dụ:
Code:
......
     int x;
     cin>>x;
     .......


+ Điều gì sẽ xảy ra nếu người dùng nhập dữ liệu không đúng: ký tự 'a' chẳng hạn?
+ Làm sao để kiểm tra dữ liệu này?
Hãy giữ một trái tim nóng và một cái đầu lạnh
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 16/11/2007 06:53:59 (+0700) | #2 | 97858
[Avatar]
K4i
Moderator

Joined: 18/04/2006 09:32:13
Messages: 635
Location: Underground
Offline
[Profile] [PM]
các hàm của C++ thì đều trả ra một giá trị nào đó và qua giá trị đó ta có thể xác định được hàm đó thực thi đúng hay không. Ở đây, hàm cin trả ra 2 giá trị true và false
Code:
int x;
if (!(cin >> x)) {
    cout << "Error"; // nếu quá trình đọc bị lỗi thì in ra Error
} else {
    cout << x; // quá trình đọc không lỗi, in ra x;
}


tham khảo thêm ở http://www.arachnoid.com/cpptutor/student1.html.

:d
Sống là để không chết chứ không phải để trở thành anh hùng
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 16/11/2007 15:59:35 (+0700) | #3 | 97941
FaL
Moderator

Joined: 14/04/2006 09:31:18
Messages: 1232
Offline
[Profile] [PM]

K4i wrote:
các hàm của C++ thì đều trả ra một giá trị nào đó và qua giá trị đó ta có thể xác định được hàm đó thực thi đúng hay không. Ở đây, hàm cin trả ra 2 giá trị true và false
Code:
int x;
if (!(cin >> x)) {
    cin >> "Error";// nếu quá trình đọc bị lỗi thì in ra Error
} else {
    cin >> x; // quá trình đọc không lỗi, in ra x;
}


tham khảo thêm ở http://www.arachnoid.com/cpptutor/student1.html.

:d
 


Ối, hình như 2 dòng này ko phải để in ra thì phải smilie
Code:
cin >> "Error";// nếu quá trình đọc bị lỗi thì in ra Error
.....
cin >> x; // quá trình đọc không lỗi, in ra x;


FaL muốn thảo luận thêm về vấn đề:
+ Điều gì xảy ra sau khi nhập sai?
+ Nhập lại sau khi nhập sai thì phải làm thế nào?

smilie Cái link của bạn cho khá hay, nhưng có lẽ giải thích một chút bằng tiếng Việt tốt hơn.

Thân, FaL.
Hãy giữ một trái tim nóng và một cái đầu lạnh
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 17/11/2007 01:06:49 (+0700) | #4 | 97982
[Avatar]
minhquan1712
Member

[Minus]    0    [Plus]
Joined: 07/09/2006 16:17:25
Messages: 240
Offline
[Profile] [PM]
tại sao mình ko thử dùng hàm sizeof để kiểm tra kiểu dữ liệu nhỉ? sau đó mình có thể dùng cin.putback để nhập lại? chỉ là ý tưởng thôi ^^
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 17/11/2007 01:24:36 (+0700) | #5 | 97988
[Avatar]
K4i
Moderator

Joined: 18/04/2006 09:32:13
Messages: 635
Location: Underground
Offline
[Profile] [PM]
uh, gõ nhầm. smilie

Còn về vấn đề phát hiện lỗi thì thực ra rất đơn giản, nó dựa vào chính việc xây dựng các hàm của C++. Theo mình biết thì rất nhiều các hàm của C++ đều có giá trị trả ra thay vì mang giá trị void thuần túy như của C. Nên mình chỉ dựa vào đó để tìm xem hàm cin trả ra giá trị gì mà thôi. Chính vì thế, khi nhập sai hàm cin sẽ trả ra giá trị false và biến x sẽ được gán một giá trị nào đó (phụ thuộc vào compiler).

Còn về việc xử lý việc nhập lại, ở trong link mình đưa ra đã nói rất rõ nhưng ở đây mình sẽ nói lại một chút:
Khi bạn nhập sai, cờ false sẽ được bật lên và khi đó không thể sử dụng lại được câu lệnh cin >> x. Để sửa, dùng hàm
Code:
cin.clear(); // hàm này có tác dụng là xóa lỗi (clear error)


sau đó, chúng ta bắt buộc phải xóa bộ nhớ đệm để chuẩn bị cho lần nhập kế tiếp
Code:
cin.ignore (80, '\n');


còn đây là chương trình chạy thử của mình
Code:
// chương trình này thực hiện đọc một số nguyên và in ra số nguyên đó.
// nếu nhập sai, phải nhập lại
#include <iostream>

using namespace std;

int main() {
	int x;
	while (!(cin >> x)) {
		cin.clear();
		cin.ignore (80, '\n');
		cout << "Error " << endl;
		cout << "Try again: ";
	}
	cout << x;
	return 0;
}


:d
Sống là để không chết chứ không phải để trở thành anh hùng
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 18/11/2007 03:19:32 (+0700) | #6 | 98252
FaL
Moderator

Joined: 14/04/2006 09:31:18
Messages: 1232
Offline
[Profile] [PM]
Cách giải quyết của K4i rất hay, tuy nhiên theo FaL cần làm rõ một số điểm:

1. Như K4i đã nói việc nhập dữ liệu sai sẽ khiến cin không thể tiếp tục làm việc. Tuy nhiên ở đây có 2 dạng nhập sai căn bản:
+ Nhập vào một số nguyên vượt quá giới hạn đã định (int): Trong trường hợp này chỉ cần dọn dẹp stream là có thể nhập lại giá trị cho biến:
Code:
cin.clear(int)


+Nhập vào một vài ký tự: trong trường hợp này cin vẫn trả về giá trị 0 (false) nhưng giá trị trong stream vẫn "hợp lệ", hàm cin.clear() sẽ không có hiệu lực xóa stream, việc nhập lại dữ liệu sẽ không được tiếp tục. K4i đề xuất dùng:
Code:
cin.ignore(80,"\n")

có tác dụng xóa 80 byte khỏi stream hoặc khi gặp ký tự "\n". Trường hợp này điều gì sẽ xảy ra nếu người dùng nhập 1 string dài hơn 80? Lúc này sẽ xuất hiện vài dòng "Try again .." tương ứng với việc vòng lặp phải lặp lại vài lần để xóa hết stream. Phải chọn số bao nhiêu cho cin.ignore(int,"\n"smilie để có thể xóa hết? Cách này có vẻ vẫn chưa tối ưu?

2. Vậy làm sao để validate một cách chính xác?

Trong tầm hiểu biết của mình, FaL đề xuất 1 cách giải quyết. Đó là việc đọc dữ liệu nhập vào bằng string - string sẽ không giới hạn kích thước của chuỗi nhập vào:
Code:
class StringClass {
  char *p;
  int len;
public:
  StringClass(char *ptr)
  {
    len = strlen(ptr);
    p = (char *) malloc(len+1);
    if(!p) {
      cout << "Allocation error\n";
      exit(1);
    }
    strcpy(p, ptr);
  }
  ~StringClass() { 
    cout << "Freeing p\n"; free(p); 
  }

  void show() 
  {
    cout << p << " - length: " << len;
    cout << endl;
  }
};


string sẽ "chấp nhận" tất cả các ký tự nhập vào từ bàn phím, từ đó ta sẽ dùng 1 hàm atoi() để kiểm tra xem string nhập vào có phải số hay ko.

Lưu ý:
Code:
atoi(char*)

bởi vậy nếu muốn convert string sang integer dùng:
Code:
atoi(sting.c_std)


Không biết cách giải quyết trên đã trọn vẹn chưa, có gì sai sót mong mọi người góp ý!

FaL
Hãy giữ một trái tim nóng và một cái đầu lạnh
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 18/11/2007 13:30:54 (+0700) | #7 | 98362
[Avatar]
K4i
Moderator

Joined: 18/04/2006 09:32:13
Messages: 635
Location: Underground
Offline
[Profile] [PM]
Thực ra, chuyển tất cả đầu vào (input) thành xâu và sau đó convert sang các kiểu cần thiết là điều mình đã biết. Tuy nhiên mình thấy làm như thế thì với những C/C++ developer phải code rất nhiều thứ và chương trình cồng kềnh hơn. Nhưng đó chính là cách an toàn nhất. smilie

Với câu hỏi này của FaL thì mình muốn thử tìm một cách khác để xử lý lỗi đầu vào bằng cách lợi dụng tính chất của C/C++. smilie. Về việc xóa bộ đệm, mình nghĩ có thể dùng cách khác để thay thế cho cin.ignore :d.

Còn về code của FaL, mình nghĩ nếu đã dùng thì nên dùng C++ (vì trong code của FaL có rất nhiều code C đặc biệt là những hàm như strcpy - là một trong những hàm rất không an toàn) vì C++ hỗ trợ nhiều thư viện là C và mình sẽ viết ít code hơn.

:d
Sống là để không chết chứ không phải để trở thành anh hùng
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 18/11/2007 13:54:46 (+0700) | #8 | 98369
FaL
Moderator

Joined: 14/04/2006 09:31:18
Messages: 1232
Offline
[Profile] [PM]
@K4i đó là định nghĩa class string của C++, FaL chỉ copy lại thôi, trong constructor viết như vậy là an toàn, khi đã kiểm tra bộ nhớ trước khi dùng strcpy. Theo ý kiến riêng của FaL, sử dụng an toàn hay ko phần lớn là do người dùng.

Thân.
Hãy giữ một trái tim nóng và một cái đầu lạnh
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 19/11/2007 14:44:45 (+0700) | #9 | 98590
[Avatar]
K4i
Moderator

Joined: 18/04/2006 09:32:13
Messages: 635
Location: Underground
Offline
[Profile] [PM]

FaL wrote:
@K4i đó là định nghĩa class string của C++, FaL chỉ copy lại thôi, trong constructor viết như vậy là an toàn, khi đã kiểm tra bộ nhớ trước khi dùng strcpy. Theo ý kiến riêng của FaL, sử dụng an toàn hay ko phần lớn là do người dùng.

Thân. 


hi, FaL. Hôm nay ngồi rỗi, xử lý lại cái lỗi của code lần trước. Thấy cũng ổn. FaL cho thêm ý kiến nhé:
Code:
#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
	int x;
	while (!(cin >> x)) {
		cout << "Error: " << endl;
		cout << "Try again: ";
		cin.clear(); // xóa cờ lỗi của cin
		fflush (stdin); // xóa toàn bộ bộ nhớ đệm, chuẩn bị cho lần nhập kế tiếp
	}
	cout << x;
    return 0;
}


==> cái này là sự pha trộn giữa C và C++.

:d
Sống là để không chết chứ không phải để trở thành anh hùng
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 19/11/2007 16:46:21 (+0700) | #10 | 98599
FaL
Moderator

Joined: 14/04/2006 09:31:18
Messages: 1232
Offline
[Profile] [PM]
Một ý tưởng hay!!! Nhưng mà fflush(FILE* stream) là một trong những "Things to avoid in C/C++".

FaL.
Hãy giữ một trái tim nóng và một cái đầu lạnh
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 20/11/2007 11:57:38 (+0700) | #11 | 98806
[Avatar]
Huyxvn
Member

[Minus]    0    [Plus]
Joined: 30/08/2007 21:42:56
Messages: 21
Location: Fotech
Offline
[Profile] [PM] [WWW] [Yahoo!]

K4i wrote:
uh, gõ nhầm. smilie

Còn về vấn đề phát hiện lỗi thì thực ra rất đơn giản, nó dựa vào chính việc xây dựng các hàm của C++. Theo mình biết thì rất nhiều các hàm của C++ đều có giá trị trả ra thay vì mang giá trị void thuần túy như của C. Nên mình chỉ dựa vào đó để tìm xem hàm cin trả ra giá trị gì mà thôi. Chính vì thế, khi nhập sai hàm cin sẽ trả ra giá trị false và biến x sẽ được gán một giá trị nào đó (phụ thuộc vào compiler).

Còn về việc xử lý việc nhập lại, ở trong link mình đưa ra đã nói rất rõ nhưng ở đây mình sẽ nói lại một chút:
Khi bạn nhập sai, cờ false sẽ được bật lên và khi đó không thể sử dụng lại được câu lệnh cin >> x. Để sửa, dùng hàm
Code:
cin.clear(); // hàm này có tác dụng là xóa lỗi (clear error)


sau đó, chúng ta bắt buộc phải xóa bộ nhớ đệm để chuẩn bị cho lần nhập kế tiếp
Code:
cin.ignore (80, '\n');


còn đây là chương trình chạy thử của mình
Code:
// chương trình này thực hiện đọc một số nguyên và in ra số nguyên đó.
// nếu nhập sai, phải nhập lại
#include <iostream>

using namespace std;

int main() {
	int x;
	while (!(cin >> x)) {
		cin.clear();
		cin.ignore (80, '\n');
		cout << "Error " << endl;
		cout << "Try again: ";
	}
	cout << x;
	return 0;
}


:d 


Cảm ơn bác Dương, em cũng đang mắc chỗ này, nhất là trong bài sắp xếp sinh viên yêu cầu nhập số nguyên (là số sinh viên cần nhập) để cấp phát động cho cấu trúc sinh viên. Khi nhập ko phải là số nguyên thì chương trình nhảy loạn cả lên.

Ko hổ danh thành viên đội tuyển phần mềm nguồn mở Coltech thì Tin học SV toàn quốc 2007
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 21/11/2007 09:24:41 (+0700) | #12 | 99003
pearltran
Member

[Minus]    0    [Plus]
Joined: 15/08/2007 13:10:08
Messages: 33
Offline
[Profile] [PM]
Em mới học nên cũng không biết nhiều nếu có sai thì anh Fal và anh K4i bỏ qua nhé.Chương trình của em yêu cầu người dùng nhập tên






Code:
#include <stdio.h>
#include<string.h>
void  kiemtra(char *s)
{
int n=0;
sscanf(s,"%*[a-zA-z]%n",&n);
if(n==strlen(s))
printf("ok");
else
printf("du lieu nhap vao khong dung");
}
main()
{
char a[20];
printf("nhapten:");
gets(a);
kiemtra(&a);
}

Không biết cách này liệu đã ổn chưa anh Fal?
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 21/11/2007 10:18:41 (+0700) | #13 | 99010
TQN
Elite Member

[Minus]    0    [Plus]
Joined: 29/06/2006 22:28:01
Messages: 888
Location: Biết làm chi ?
Offline
[Profile] [PM] [WWW] [Yahoo!]
Hồi tui mới học C/C++, tui có code hàm ReadInt này để đọc int từ console, cậu Fal xem thử có dùng được không, bảo đãm nhanh và rock hơn các hàm trên:
Code:
BOOL ReadInt(int *pIn)
{
    int c, sign;

    // Skip white space
    while (isspace(c = getchar()) && c != '\n')
        c = getchar();

    if (!isdigit(c) && c != '+' && c != '-')
        return FALSE;

    sign = (c == '-') ? -1 : 1;

    if (c == '+' || c == '-') {
        c = getchar();
        if (!isdigit(c))
            return FALSE;
    }

    for (*pIn = 0; isdigit(c); c = getchar())
        *pIn = 10 * *pIn + (c - '0');

    *pIn *= sign;

    return TRUE;
}
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 22/11/2007 11:24:33 (+0700) | #14 | 99251
FaL
Moderator

Joined: 14/04/2006 09:31:18
Messages: 1232
Offline
[Profile] [PM]

pearltran wrote:
Em mới học nên cũng không biết nhiều nếu có sai thì anh Fal và anh K4i bỏ qua nhé.Chương trình của em yêu cầu người dùng nhập tên
Code:
#include <stdio.h>
#include<string.h>
void  kiemtra(char *s)
{
int n=0;
sscanf(s,"%*[a-zA-z]%n",&n);
if(n==strlen(s))
printf("ok");
else
printf("du lieu nhap vao khong dung");
}
main()
{
char a[20];
printf("nhapten:");
gets(a);
kiemtra(&a);
}

Không biết cách này liệu đã ổn chưa anh Fal?
 


- Tớ nghĩ nếu chỉ là đọc tên thì ko có vấn đề gì. Nhưng mà include cả string.h, sử dung strlen(),.. thì thà viết 1 hàm như hàm strlen() còn hơn smilie

Anh Thangcuem wrote:

BOOL ReadInt(int *pIn)
{
int c, sign;

// Skip white space
while (isspace(c = getchar()) && c != '\n')
c = getchar();

if (!isdigit(c) && c != '+' && c != '-')
return FALSE;

sign = (c == '-') ? -1 : 1;

if (c == '+' || c == '-') {
c = getchar();
if (!isdigit(c))
return FALSE;
}

for (*pIn = 0; isdigit(c); c = getchar())
*pIn = 10 * *pIn + (c - '0');

*pIn *= sign;

return TRUE;

smilie Em đọc đoạn code mấy bữa nay rồi, nhưng muốn thấm rõ hơn nên chưa reply, đúng là ngắn gọn và Rock lắm anh. Thanks anh! Mong anh Thangcuem đóng góp cho box lập trình sôi nổi hơn nữa.

Hãy giữ một trái tim nóng và một cái đầu lạnh
[Up] [Print Copy]
  [Question]   Re: [Thảo luận] Validate input data - C++ 23/11/2007 01:43:14 (+0700) | #15 | 99389
pearltran
Member

[Minus]    0    [Plus]
Joined: 15/08/2007 13:10:08
Messages: 33
Offline
[Profile] [PM]
Hi anh Fal,điều em muốn nói đến trong đoạn code của em là việc sử dụng hàm sscanf. Sử dụng hàm này thì anh không những có thể bắt người dùng chỉ được nhập tên,anh có thê bắt họ chỉ được nhập số hoặc nhập một ký tự duy nhất,v.vv
[Up] [Print Copy]
  [Programming]   Validate input data - C++ 29/06/2009 13:31:35 (+0700) | #16 | 184919
pitatima
Member

[Minus]    0    [Plus]
Joined: 07/05/2009 20:36:47
Messages: 3
Offline
[Profile] [PM]
Video C# về đổi àu tự động rất đẹp
link Down
[code]http://www.mediafire.com/download.php?qntzjtzwmdm[/cde]
[Up] [Print Copy]
[digg] [delicious] [google] [yahoo] [technorati] [reddit] [stumbleupon]
Go to: 
 Users currently in here 
1 Anonymous

Powered by JForum - Extended by HVAOnline
 hvaonline.net  |  hvaforum.net  |  hvazone.net  |  hvanews.net  |  vnhacker.org
1999 - 2013 © v2012|0504|218|