Lập trình C++ | Thao tác với input trong C++ (Advance)

mới xu được bên congdongcviet.com về việc nhập sai kiểu dữ liệu:http://forums.congdongcviet.com/showthread.php?t=6380

// that make basic console input easier for new C++ programmers.
//
// basic_input:
//    template<typename charT, typename traits, typename T>
//      inline bool basic_input(std::basic_istream<charT,traits>& is, T& x, charT delim)
//    template<typename charT, typename traits, typename Allocator>
//      inline bool basic_input(std::basic_istream<charT,traits>& is, std::basic_string<charT,traits,Allocator>& x, charT delim)
//    template<typename charT, typename traits>
//      inline bool basic_input(std::basic_istream<charT,traits>& is, charT* x, std::streamsize count, charT delim)
//    template<typename charT, typename traits, typename T>
//      inline bool basic_input(std::basic_istream<charT,traits>& is, T& x)
//
//  Returns:
//    bool – true if the input succeeded, false otherwise.
//
//  Effects:
//    This function attempts to read from the input stream into the passed in
//    variable up to the specified delimiter. If the data in the stream does
//    not match the expected format of the variable type, or if the character
//    following the data read in is not the delimiter, then the input fails.
//
//    On success, the variable x contains the inputted value. On failure, the
//    variable x is cleared (i.e. default-initialized).
//
//    On success or failure, the input stream is left in a good state and all
//    characters up to and including the delimiter are removed from the stream.
//
//    The delimiter defaults to ‘\n’ if not specified.
//
//    If the variable type is char* (or some other character pointer), and the
//    delimiter has not yet been reached prior to count characters being read
//    in, then the input has failed and the array pointed to by the char* will
//    be filled with count characters set to null.
//
//  Sample usage:
//    int i;
//    std::cout << “Enter an int: “;
//    while (!bip::basic_input(std::cin, i))
//        std::cout << “Invalid int! Try again: “;
//
//
// ignore_line:
//    template<typename charT, typename traits>
//    inline std::basic_istream<charT,traits>& ignore_line(std::basic_istream<charT,traits>& is, charT delim)
//    template<typename charT, typename traits>
//    inline std::basic_istream<charT,traits>& ignore_line(std::basic_istream<charT,traits>& is)
//
//  Returns:
//    std::basic_istream<charT,traits>& – the stream passed in.
//
//  Effects:
//    This function reads and discards all characters in the passed in input
//    stream up to and including the first instance of the delimiter. The
//    delimiter defaults to ‘\n’ if not specified.
//
//  Sample usage:
//    std::cout << “Press Enter to Close.\n”;
//    bip::ignore_line(std::cin);
//

#ifndef BASIC_INPUT_H_
#define BASIC_INPUT_H_

#include <istream>
#include <ios>
#include <string>
#include <limits>

namespace bip
{
template<typename charT, typename traits>
inline std::basic_istream<charT,traits>& ignore_line(std::basic_istream<charT,traits>& is, charT delim)
{
return is.ignore(std::numeric_limits<std::streamsize>::max(), delim);
}

template<typename charT, typename traits>
inline std::basic_istream<charT,traits>& ignore_line(std::basic_istream<charT,traits>& is)
{
return ignore_line(is, is.widen(‘\n’));
}

template<typename charT, typename traits, typename T>
inline bool basic_input(std::basic_istream<charT,traits>& is, T& x, charT delim)
{
std::ios::fmtflags old_flags = is.flags();
if ((is >> std::noskipws >> x) && (is.eof() || is.get() == delim))
{
is.flags(old_flags);
return true;
}
is.flags(old_flags);

x = T();
is.clear();
ignore_line(is, delim);
return false;
}

template<typename charT, typename traits, typename Allocator>
inline bool basic_input(std::basic_istream<charT,traits>& is, std::basic_string<charT,traits,Allocator>& x, charT delim)
{
if (std::getline(is, x, delim))
return true;

x.clear();
is.clear();
return false;
}

template<typename charT, typename traits>
inline bool basic_input(std::basic_istream<charT,traits>& is, charT* x, std::streamsize count, charT delim)
{
if (is.getline(x, count, delim))
return true;

if (is.gcount()+1 < count)
memset(x, charT(), count);

is.clear();
ignore_line(is, delim);
return false;
}

template<typename charT, typename traits, typename T>
inline bool basic_input(std::basic_istream<charT,traits>& is, T& x)
{
return basic_input(is, x, is.widen(‘\n’));
}
}
driver example
#endif  // BASIC_INPUT_H_

ví dụ:

#include <iostream>
#include <string>
#include “basic_input.h”

int main()
{
const std::streamsize cslen = 5;
char cstyle[cslen];
std::cout << “Enter a line of text: “;
if (bip::basic_input(std::cin, cstyle, cslen, ‘\n’))
std::cout << “The line of text read in was: ” << cstyle << std::endl;
else
std::cout << “Sorry, invalid: ” << cstyle << std::endl;

std::string s;
std::cout << “Enter a line of text: “;
bip::basic_input(std::cin, s);
std::cout << “The line of text read in was: ” << s << std::endl;

int i;
std::cout << “Enter an int: “;
if (bip::basic_input(std::cin, i))
std::cout << “The number read in was: ” << i << std::endl;
else
std::cout << “Sorry, invalid int!” << std::endl;

double d;
std::cout << “Enter a double: “;
while (!bip::basic_input(std::cin, d))
{
std::cout << “Invalid double! Try again: “;
}
std::cout << “The double read in was: ” << d << std::endl;

std::wstring ws;
std::wcout << L”Enter a line of text: “;
bip::basic_input(std::wcin, ws);
std::wcout << L”The line of text read in was: ” << ws << std::endl;

int wi;
std::wcout << L”Enter an int: “;
if (bip::basic_input(std::wcin, wi))
std::wcout << L”The number read in was: ” << wi << std::endl;
else
std::wcout << L”Sorry, invalid int!” << std::endl;

double wd;
std::wcout << L”Enter a double: “;
while (!bip::basic_input(std::wcin, wd))
{
std::wcout << L”Invalid double! Try again: “;
}
std::wcout << L”The double read in was: ” << wd << std::endl;

std::cout << “Press Enter to Close.\n”;
bip::ignore_line(std::cin);
}

Advertisements

Tip: Nạp chồng toán tử ++ hay — tiền tố hoặc hậu tố ntn?

class Point
{
public:
Point& operator++();       // khai báo nạp chồng toán tử ++ tiền tố
Point operator++(int);     // khai báo nạp chồng toán tử ++ hậu tố

Point& operator--();       // tiền tố
Point operator--(int);     // hậu tố

// default constructor
Point() { _x = _y = 0; }

// accessor functions
int x() { return _x; }
int y() { return _y; }
private:
int _x, _y;
};

// Phần hiện thực
Point& Point::operator++()
{
_x++;
_y++;
return *this;
}

Point Point::operator++(int)
{
Point temp = *this;
++*this;
return temp;
}

Point& Point::operator--()
{
_x--;
_y--;
return *this;
}

Point Point::operator--(int)
{
Point temp = *this;
--*this;
return temp;
}

int main()
{
}

Ngoài ra chúng ta có thể dùng hàm friend để hiện thực các toán tử ++/– như sau:

friend Point& operator++( Point& )      // tiền tố
friend Point& operator++( Point&, int ) // hậu tố
friend Point& operator--( Point& )      // tiền tố
friend Point& operator--( Point&, int ) // hậu tố

Các điểm cần lưu ý:
– Toán tử ++/– dạng tiền tố trả về một tham chiếu đến đối tượng thuộc lớp Point
– Toán tử ++/– dạng hậu tố trả về một đối tượng thuộc lớp Point
– Đối số “int” trong dạng hậu số là bắt buộc, dùng để phân biệt với dạng tiền tố, thường thì nó mang trị mặc định là 0. Trong hầu hết các trường hợp chúng ta không quan tâm đến nó. Tuy nhiên nó vẫn có thể được sử dụng như dưới đây:

class Int
{
public:
Int &operator++( int n );
private:
int _i;
};

Int& Int::operator++( int n )
{
if( n != 0 )    // Trường hợp có sử dụng đối số trong toán tử ++/-- hậu tố
_i += n;
else
_i++;       // Trường hợp thông thường
return *this;
}

int main()
{

}

from:http://www.codeprovn.com/forums/viewtopic.php?f=18&t=23&p=23

Điều đầu tiên khi lập trình viên nghĩ đến từ khóa const là những gì không thể thay đổi được (hằng số). Bạn không thể thay đổi giá trị của một hằng số. Bạn có thể dùng từ khóa const để chỉ ra rằng một giá trị nào đó sẽ không thể thay đổi được trong suốt chương trình của bạn. Một câu hỏi dành cho bạn:

Bạn có thể đặt từ khóa “const” ở những nơi nào trong chương trình của mình?

Để trả lời câu hỏi trên khi làm việc với ngôn ngữ lập trình (ở đây là C++), bạn cần phải trả lời được câu hỏi: “Tôi cần giá trị nào trở thành không thay đổi được?”.

Ở đây, trong bài viết này, xin liệt kê ra một số nơi bạn có thể đặt từ const.

1. Khi khai báo một biến, nếu bạn đặt thêm từ const thì giá trị của biến đó sẽ không thể thay đổi được trong suốt phạm vi tồn tại của biến đó.
Ví dụ các khai báo sau:

const int x = 8;
int const y = 10;

Hai dạng khai báo trên là tương đương. Giá trị của hai biến x và y sẽ không thể tha đổi được.

2. Đối với biến con trỏ, bạn cần lưu ý đến hai điều: vùng nhớ con trỏ trỏ đến và giá trị của vùng nhớ đó.

Với các khai báo:

int x = 10, y = 20;
const int *px = &x;

Khi này, giá trị của vùng nhớ mà px đang trỏ đến là không thể thay đổi được thông qua thay đổi (*px). Do đó, ta có các câu lệnh sau:

*px = 15; // incorrect
px = &y; // correct
x = 15; // correct (Để ý rằng giá trị của x vẫn có thể được thay đổi, ta chỉ không thể thay đổi giá trị này thông qua px)

Nhưng với các khai báo sau:

int x = 10, y = 20;
int* const px = &x;

Khi này, giá trị của vùng nhớ mà px trỏ đến có thể được thay đổi thông qua việc thay đổi (*px) nhưng điều đặc biệt là ta không thể làm cho px trỏ đến một vùng nhớ khác. Ta có các câu lệnh sau:

*px = 15; // correct
px = &y; // incorrect

Với khai báo sau:

int x = 10;
const int* const px = &x;

Bạn không thể thay đổi nơi px đang trỏ đến và thông qua (*px) cũng không thể thay đổi giá trị vùng nhớ đó.

============

Tiếp theo bài viết kỳ trước, bài này xin trình bày tác dụng của const khi hoạt động với hàm trong C++.

Giả sử ta có cấu trúc sau:

class A
{
private:
int m_a;
public:

};

Và ta có một hàm nhận tham số đầu vào là một đối tượng kiểu A và trả về một đối tượng kiểu A.

A functionName(A object); // object là một đối tượng kiểu A

Khi gọi hàm này với x là một đối tượng kiểu A:

functionName(x);

Một đối tượng object sẽ được tạo và máy sẽ copy toàn bộ giá trị của x vào object rồi xử lý, sau đó sẽ trả về một đối tượng kiểu A. Vấn đề phát sinh là khi ta có một class với kích thước lớn thì việc chép giá trị vào tham số hình thức ở hàm sẽ làm cho chương trình trở nên chậm đi và đặc biệt là sẽ hao phí bộ nhớ. Do đó, ta có giải pháp là hai khai báo cho hàm đó như sau:

A functionName(A& object);
A functionName(A* object);

Hàm trên sử dụng tham số hình thức là một biến tham chiếu (reference variable) và hàm dưới dùng một biến con trỏ (pointer variable). Hai cách khai báo này sẽ cho kết quả tương tự nhau. (Sự khác nhau giữa biến tham chiếu và biến con trỏ sẽ được trình bày trong một bài gần đây). Khi này, với lời gọi hàm như trên thì địa chỉ của x sẽ được truyền vào, do đó sẽ tránh được việc phải chép cả cấu trúc với kích thước lớn.

Nhưng với khai báo như thế thì giá trị của biến truyền vào có thể bị thay đổi thông qua biến object (vì là biến con trỏ hoặc tham chiếu), trong khi với cách khai báo như cũ thì ta không hề muốn giá trị này bị sửa đổi chút nào. Do đó, từ khóa const được sử dụng:

A functionName(const A& object);
A functionName(const A* object);

Như bài trước, nếu ta muốn con trỏ object luôn trỏ đến một vị trí cố định:

A functionName(const A* const object);

Nếu hàm trả về một con trỏ trỏ đến một đối tượng kiểu A:

A* functionName( const A* const object);

Theo nhu cầu, có thể bạn mong muốn hàm sẽ trả về con trỏ mà giá trị trỏ đến là không thay đổi được thông qua con trỏ, bạn sẽ khai báo hàm như sau:

const A* functionName(const A* const object);

Nếu bạn muốn con trỏ trả về cũng không thể thay đổi được vị trí trỏ đến của nó:

const A* const functionName(const A* const object);

Tiếp theo, nếu class A của chúng ta có thêm một phương thức là long A::m_square() ; chẳng hạn. Phương thức này sẽ tính bình phương của biến A::m_a và trả về giá trị đó. Thực sự, đây chỉ là một hàm tính toán một giá trị từ giá trị của những thuộc tính trong class. Yêu cầu đặt ra là hàm này không được làm thay đổi giá trị của các thuộc tính của class. Do đó ta sẽ sử dụng một phương thức hằng bằng cách đặt từ const vào cuối hàm:

long A::m_square() const;

Bây giờ, nếu bạn lại muốn phương thức hằng của mình vẫn có thể thay đổi được giá trị của một số thuộc tính của class thì sao? Điều này vẫn có thể đạt được bằng cách sử dụng từ khóa mutable vào trước khai báo của thuộc tính nào bạn cần thay đổi giá trị bởi phương thức hằng. Chú ý là mutable không được dùng cho các biến staticcons.

Trở lại với hàm functionName(…) của ta. Khi hàm này là một phương thức của class A và bạn muốn nó trở thành một phương thức hằng thì ta có một khai báo khủng hoảng về từ khóa const:

const A* const functionName(const A* const object) const; // 5 từ const

Việc sử dụng những từ khoá const và vị trí của chúng trong chương trình là tùy theo mục đích và yêu cầu của ngữ cảnh hiện tại. Do đó, bạn hãy lưu ý khi làm việc với chúng.

from:http://tek3d.org/tu-khoa-const-trong-c-2

(phongtran88)

Cấp phát bộ nhớ động cho chuỗi

int main()
{
_STRING *string = new _STRING;
_STRING *stringbak = string;
int iCounter = 0;
while(1)
{
char tmp = getchar();
if(tmp == 13)
break;
printf(“%c”,tmp);
string->data = tmp;
string->pNext = new _STRING;
if(!string->pNext)
break;
string = string->pNext;
iCounter++;
};
string = stringbak;
char *chuoi = new char[iCounter+1];
chuoi[iCounter] = ”;
string->data=string->data+string->pNext->data;

printf(“\n%s\n”,string->data);
return 0;