Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 1 TÓM TẮT CHƢƠNG 2 : C++/CLI CĂN BẢN.
1) Tạo và biên dịch một chƣơng trình C++/CLI :
a) Dùng phần mềm Visual Studio :
Mở chương trình VS 2008. Trong màn hình khởi động, chọn File - > New -> Project Trong cửa sổ New Project : Chọn kiểu project là CLR, trong cửa sổ Templates chọn
CLR Console Application.
Nhập tên của project vào ô Name và chọn thư mục chứa project trong ô Location.
Nhấp OK. Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 2
Xuất hiện cửa sổ Project, chúng ta có thể bắt đầu viết chương trình trong vùng soạn thảo. Sau khi hoàn tất chương trình, nhấn vào biểu tượng Debug để chạy chương trình (hoặc
nhấn F5).
Khi Debug, nếu chương trình co lỗi về mặt cú pháp, VS sẽ thông báo các lỗi này trong cửa
sổ Error, nhấp kép chuột vào dòng thông báo lỗi để biết vị trí lỗi. Nếu không thấy cửa sổ Error, trên thanh công cụ chọn View -> Other Windows -> Error
List. (Hoặc nhấn Ctrl+F5).
lập trình hoặc chạy trực tiếp trên Command Prompt bằng cách nhập vào tên của tập tin tại dấu
nhắc (không bao gồm đuôi mở rộng).
Lưu ý : Nếu chương trình có lỗi về mặt cú pháp, quá trình biên dịch sẽ thất bại.
2) Class CONSOLE :
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 5
Class quản lí việc tương tác với màn hình Console. Các phương thức (hàm) cơ bản của lớp:
Write(a) : Hàm một đối số. Xuất ra màn hình Console giá trị của a (a có thể là biến hoặc
hằng số).
VD : Console::Write (10); -> 10
Console::Write(“Hello”); -> Hello
WriteLine(a) : Hàm một đối số. Tương tự như Write() nhưng sau khi xuất giá trị ra màn
hình sẽ xuống dòng.
VD : Console::WriteLine(10); -> 10
Console::WriteLine(“Hello”); -> Hello
Read() : Hàm không có đối số. Kiểu dữ liệu trả về là interger. Nhận một kí tự được nhập từ
bàn phím.
VD : int a = Console::Read ();
5 : a = 5
A : a = 65 (số thập phân tương ứng mã ASCII của kí tự A )
AB : a = 65 (khi nhập vào một chuỗi kí tự thì chỉ nhận kí tự đầu tiên).
ReadLine() : Hàm không có đối số. Kiểu dữ liệu trả về là String. Nhận một chuỗi kí tự
được nhập từ bàn phím.
Các kiểu biến tĩnh : các biến kiểu giá trị như interger, float, decimal, boolean và character.
Một số hạn chế có thể gặp phải khi sử dụng các biến tĩnh:
Cấp phát ô nhớ dư, gây ra lãng phí ô nhớ.
Cấp phát ô nhớ thiếu, chương trình thực thi bị lỗi.
Để tránh những hạn chế trên, ngôn ngữ C++ cung cấp cho ta một loại biến đặc biệt gọi là
biến động với các đặc điểm sau:
Chỉ phát sinh trong quá trình thực hiện chương trình chứ không phát sinh lúc bắt
đầu chương trình.
Khi chạy chương trình, kích thước của biến, vùng nhớ và địa chỉ vùng nhớ được cấp
phát cho biến có thể thay đổi.
Sau khi sử dụng xong có thể giải phóng để tiết kiệm chỗ trong bộ nhớ.
Các kiểu biến động : String, Object, array, interface, delegate …
Tuy nhiên các biến động không có địa chỉ nhất định nên ta không thể truy cập đến chúng
được. Vì thế, ngôn ngữ C lại cung cấp cho ta một loại biến đặc biệt nữa để khắc phục tình trạng
này, đó là biến con trỏ (pointer) với các đặc điểm:
Biến con trỏ không chứa dữ liệu mà chỉ chứa địa chỉ của dữ liệu hay chứa địa chỉ của ô nhớ
chứa dữ liệu.
Kích thước của biến con trỏ không phụ thuộc vào kiểu dữ liệu, luôn có kích thước cố định
là 2 byte.
Tất cả các biến động đều phải khai báo thông qua con trỏ.
b) Pointer : (*)
Muốn truy xuất giá trị của một biến, thì có thể gọi tên biến trong chương trình hoặc truy
xuất trực tiếp đến vùng nhớ thông qua địa chỉ của biến.
Để truy xuất trực tiếp đến vùng nhớ của biến, ta dùng biến con trỏ (pointer). Nói đơn giản,
con trỏ là một biến chứa địa chỉ của biến khác. Kích thước của biến con trỏ không phụ thuộc vào
kiểu dữ liệu, luôn có kích thước cố định là 2 byte.
Cú pháp khai báo : type* name;
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 7
Do con trỏ cũng là một biến nên cũng được lưu trữ trong bộ nhớ, nên ta có thể dùng một
con trỏ khác để chỉ tới địa chỉ này.
VD: int*a = &k1;
int**b = &a;
c) Handle : (^)
Handle cũng có chức năng tương tự như pointer. Chỉ khác là nó không phản ánh được địa
chỉ thật của đối tượng nằm ở đâu trên bộ nhớ mà nó phản ánh được 1 giá trị 32 bit do CLR quản
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 8
lý. Do đó handle còn có thể được xem là một con trỏ ảo cho phép tương tác với bộ nhớ thông qua
CLR.
Do không phản ánh địa chỉ thật của đối tượng trên bộ nhớ nên ta không thể thực hiện các
phép toán công trừ với số nguyên như pointer.
Cơ chế quản lý bộ nhớ của một số ngôn ngữ :
4) String (Kiểu chuỗi kí tự) :
String là kiểu dữ liệu cho phép lưu trữ giá trị dưới dạng một dãy các kí tự. Để dễ hình
dung, ta có xem String như là một vectơ gồm nhiều phần tử liên tiếp nhau, mỗi phần tử là một kí
tự.
Cú pháp khai báo : String^ name; //name là tên biến.
Để gán giá trị cho biến kiểu String, ta đặt chuỗi kí tự trong cặp dấu “”.
VD : String^ a = “Xinchao”;
Do kích thước của kiểu String là không xác định (vì không biết chính xác chiều dài của
chuỗi kí tự). Nên String thuộc kiểu dữ liệu tham chiếu (reference type) và khi khai báo cần có ^
(handle).
Ta có thể truy xuất đến bất kì một phần tử nào trong chuỗi nếu biết vị trí của phần tử đó.
VD : String ^ a = “Welcome”;
String ^ b = a->ToLower(); // b= “welcome”
Remove(int n, int m) : Hàm hai đối số. Kiểu dữ liệu trả về là String. Tạo một chuỗi mới từ
chuỗi ban đầu bằng cách loại đi m các phần tử từ vị trí n .
VD : String^ a = “Hello Viet Nam”;
String^ b = a->Remove(2,5); // b = “Heiet Nam”
Replace(String^ n, String^ m) : Hàm hai đối số. Kiểu dữ liệu trả về là String. Tạo một
chuỗi mới từ chuỗi ban đầu bằng cách thay thế chuỗi n bằng chuỗi m.
VD : String^ a = “Hello Hell”;
String^ b = a->Replace(“ell”, “i”); // b = “Hio Hi”
Insert(int n, String^ m) : Hàm hai đối số. Kiểu dữ liệu trả về là String. Tạo một chuỗi mới
từ chuỗi ban đầu bằng cách chèn thêm vào chuỗi m tại vị trí thứ n .
VD : String^ a = “Hello”;
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 10
String^ b = a->Insert(2, “hi”); // b = “Hehillo”
Trim() : Hàm không đối số. Kiểu dữ liệu trả về là String. Loại bỏ các kí tự khoảng trắng
(spacebar) ở đầu và cuối chuỗi.
VD : String^ a = “ Hello VN ”;
String^ b = a->Trim() ; // b = “Hello VN”
5) Array (Kiểu mảng) :
array là kiểu dữ liệu dạng tập hợp (collection) cho phép lưu trữ giá trị dưới dạng một
mảng các phần tử có cùng kiểu dữ liệu. Để dễ hình dung, ta có xem array như là một ma trận
nhiều chiều gồm nhiều phần tử, kiểu dữ liệu của mỗi phần tử là bất kì.
ở hàng 1 cột 1 là M[0,0]).
Ngoài ra, nếu giá trị tất cả các phần tử của mảng đã biết. Ta có dùng cách gán trực tiếp như
sau :
VD : array<int,2>^ M = { {1,2,3},{2,3,0},{1,2,3} }; //mảng 3x3
Lưu ý : khi dùng cách gán giá trị trực tiếp, ta phải gán ngay khi khai báo và không cần
dùng lệnh gcnew() (phần mềm sẽ tự động cấp phát bộ nhớ).
VD : array<int,2>^ M;
M = { {1,2,3},{2,3,0},{1,2,3} }; // báo lỗi.
Trong C++/CLI, có riêng một Class quản lí kiểu mảng là Class Array. Các biến (variable)
và phương thức (method) cơ bản của Class Array :
Rank : biến có kiểu interger. Trả về số chiều của mảng.
VD : array<int,2>^ M = gcnew array<int,3>(5,3,2);
int x = M->Rank; // x sẽ có giá trị = 3.
GetLength (int i) : hàm 1 đối số. Kiểu dữ liệu trả về là interger. Trả về số phần tử (kích
thước) chiều thứ i của mảng.
VD : array<int,2>^ M = gcnew array<int,2>(5,3);
int x = M->GetLength(0); // x = 5.
int y = M->GetLength(1); // y = 3.
Reverse(array^ x) : Hàm một đối số. Không trả về dữ liệu. Thực hiện chức năng đảo ngược
thứ tự của mảng 1 chiều.
VD : array<int>^ M = { 1,2,3,4,5 };
Array::Reverse(M); // M = {5,4,3,2,1}.
Sort(array^ x) : Hàm một đối số. Không trả về dữ liệu. Thực hiện chức năng sắp xếp thứ
tự của mảng 1 chiều.
VD : int x = 5, y = 3;
int z = x%y; // z = 2 (5 chia 3 dư 2).
int k = x++%y; // k = 2 , x = 6 ( thực hiện x% y trước rồi mới tăng x).
int t = ++z%y; // t = 0 , z = 3 (tăng z rồi mới thực hiện z%y)
b) Toán tử so sánh và logic :
Toán tử so sánh thực hiện so sánh hai biểu thức và trả về một giá trị bool dựa vào kết quả
của việc so sánh. Bao gồm các toán tử sau :
> : So sánh lớn hơn.
< : So sánh nhỏ hơn.
>= : So sánh lớn hơn hoặc bằng.
<= : So sánh nhỏ hơn hoặc bằng.
== : So sánh bằng.
!= : So sánh không bằng.
Toán tử logic thực hiện các phép toán trên số bool. Bao gồm 3 toán tử :
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 13
! : Phép NOT.
&& : Phép AND.
|| : Phép OR.
VD : int x = 5, y = 3;
int z = x%y; // z = 2 (5 chia 3 dư 2).
int k = x++%y; // k = 2 , x = 6 ( thực hiện x% y trước rồi mới tăng x).
int t = ++z%y; // t = 0 , z = 3 (tăng z rồi mới thực hiện z%y)
= : Gán trực tiếp.
+= : Thực hiện công rồi mới gán ( x += a x = x + a).
-= : Thực hiện trừ rồi mới gán ( x -= a x = x - a).
*= : Thực hiện nhân rồi mới gán ( x *= a x = x * a).
/= : Thực hiện chia rồi mới gán ( x /= a x = x / a).
%= : Thực hiện chia lấy dư rồi mới gán ( x %= a x = x % a).
&= : Thực hiện AND rồi mới gán ( x &= a x = x & a).
^= : Thực hiện XOR rồi mới gán ( x ^= a x = x ^ a).
|= : Thực hiện OR rồi mới gán ( x |= a x = x|a).
>>=: Thực hiện dịch phải rồi mới gán ( x >>= a x = x >> a).
<<=: Thực hiện dịch trái rồi mới gán ( x <<= a x = x << a).
f) Toán tử ngoặc đơn (comma) :
Gồm nhiều biểu thức liên tiếp được thực hiện liên tiếp, kết quả là kết quả của biểu thức
cuối cùng.
VD : int x = 5, y = 3;
int z = (y++, x = y++ * x++, x%y); // z = 4.
g) Toán tử địa chỉ, tham chiếu và gián tiếp :
Toán tử địa chỉ (&) : trả về địa chỉ (trong bộ nhớ) của một biến.
VD : int x = 5, *y ;
y = &x; // đặt địa chỉ của biến x vào biến con trỏ y.
Toán tử gián tiếp (*) : toán tử một ngôi trên biến con trỏ, trả về giá trị đang lưu trữ trong ô
nhớ mà biến con trỏ đang chỉ tới.
VD : int x ;
int *y = &x; // y chỉ tới địa chỉ lưu trữ giá trị biến x
Hoặc :
if (conditon) //Nếu điều kiện đúng thì thực hiện đoạn mã lệnh 1.
{
Statement 1;
}
else // Nếu điều kiện sai thì thực hiện đoạn mã lệnh 2.
{
Statement 2;
}
Nếu có nhiều vòng if lồng nhau (nhiều điều kiện) thì có thể dùng cấu trúc sau :
if (conditon 1) //Nếu điều kiện 1 đúng thì thực hiện đoạn mã lệnh 1.
{
Statement 1;
}
else if (condition 2) // Nếu điều kiện 2 đúng thì thực hiện đoạn mã lệnh 2.
{
Statement 2;
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 16
}
else // Nếu tất cả đều sai thì thực hiện đoạn mã lệnh 3.
{
Statement 3;
}
VD : int x = 5, y = 10;
Console::WriteLine(“x chia het cho 3”);
break;
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 17
case 1:
Console::WriteLine(“x la so chan”);
break;
default :
Console::WriteLine(“x la so le”);
}
Kết quả xuất ra màn hình của đoạn mã trên : x la so chan.
Lưu ý :
Lệnh break có tác dụng thoát khỏi điều kiện. Nếu không có lệnh break sau mỗi
đoạn lệnh case, chương trình sẽ thực thi đến đoạn lệnh case tiếp theo (nếu thỏa điều
kiện).
Cấu trúc switch-case có thể được thay thế bởi cấu trúc if , trong đó, condition trong
cấu trúc if sẽ là (expression == constant).
if (expression == constant 1)
{
Statement 1;
}
else if (expression == constant 2)
{
Statement 2;
}
else
Cú pháp :
do
{
Statements; // Thực hiện lại đoạn lệnh khi condition vẫn còn đúng.
} while (condition);
VD : int x = 0;
do
{
Console::Write(“{0}\t”,x++);
} while (x < 3);
Kết quả in ra màn hình : 0 1 2 3
Lưu ý :
Cấu trúc while và do-while là các cấu trúc lặp vô hạn, do đó trong đoạn mã lệnh
phải có đoạn lệnh thoát khỏi vòng lặp.
Cấu trúc “for” :
Cấu trúc “for” thực hiện lặp lại có giới hạn một đoạn mã lệnh .
Cú pháp :
for (initialization ; condition ; increment)
{
Statements; // Thực hiện lại đoạn lệnh khi condition vẫn còn đúng.
}
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 19
initialization : Phát biểu khởi tạo, có thể có nhiều phát biểu, các phát biểu cách nhàu bằng
dấu “,” .
for each(Char x in M)
{
Console::Write(“{0}\t”, x);
}
Kết quả in ra màn hình : A B C D
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 20
8) Hàm (Function) :
Hàm được xem như là trung tâm của các chương trình C++/CLI. Về cơ bản, hàm là một
khối lệnh và có thể được thực thi khi được gọi ra từ bất cứ vị trí nào trong chương trình. Có hai
kiểu hàm cơ bản : hàm trả về kiểu dữ liệu và hàm không trả về kiểu dữ liệu.
a) Hàm trả về kiểu dữ liệu :
Hàm trả về kiểu dữ liệu là hàm sau khi kết thúc sẽ trả về một giá trị, ta có giữ lấy giá trị
này bằng cách gán cho một biến.
Cú pháp :
type function-name (argument 1, argument 2, …)
{
Statements; // Đoạn mã lệnh của hàm.
return x; // Giá trị muốn trả về.
}
Trong đó, type là kiểu dữ liệu của giá trị hàm trả về, function-name là tên của hàm,
argument là tham số của hàm (bao gồm kiểu dữ liệu và tên của tham số). Số lượng tham số của
hàm là không giới hạn. Khi kết thúc đoãn mã lệnh của hàm phải có lệnh return, giá trị được dùng
với lệnh return chính là giá trị trả về của hàm.
Hàm được khai báo bên ngoài hàm main().Trong hàm main(), khi muốn sử dụng hàm, ta
có thể gọi hàm thông qua tên của hàm và các tham số được truyền vào. Sau đây là một ví dụ về
hàm giải phương trình bậc 1.
VD : using namespace Sytem;
void Solve (int a, int b) // Hàm giải pt bậc 1 ax + b = 0.
{
int x = -b/a;
Console::WriteLine (x);
}
void main()
{
int x = 5, y =10;
Solve (x,y); // Gọi hàm và truyền tham số cho hàm .
}
c) Truyền tham số cho hàm :
Có hai cách truyền tham số cho hàm : tham trị (by value) và tham chiếu (by reference).
Điểm khác biệt duy nhất về cú pháp giữa hai cách truyền này là nếu truyền theo tham chiếu thì
trước tham số có thêm toán tử tham chiếu (%) hoặc địa chỉ (&) hoặc khai báo tham số theo kiểu
con trỏ.
VD : void Solve (int a, int b) // Truyền tham trị.
void Solve (int %a, int %b) // Truyền tham chiếu.
void Solve (int &a, int &b) // Truyền tham chiếu theo địa chỉ.
void Solve (int ^a, int ^b) // Truyền tham số kiểu con trỏ.
Về mặt bản chất, khi truyền tham số theo kiểu giá trị cho hàm, tức là ta chỉ truyền giá trị
của biến cho hàm chứ không phải bản thân của biến. Do đó, hàm này không thể thay đổi được giá
trị ban đầu của tham số.
VD : void Binh_phuong (int a) // Hàm tính bình phương của một số.
{
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 22
{
int ^x = 5;
Binh_phuong (x); // Gọi hàm và truyền tham số cho hàm .
Console::WriteLine(x);
}
Kết quả in ra màn hình : 25
VD : void Binh_phuong (int &a) // Hàm tính bình phương của một số.
{
Lập trình ứng dụng trong kỹ thuật Chương 2
Bộ môn Cơ điện tử Trang 23
a = a*a;
}
void main()
{
int x = 5;
Binh_phuong (x); // Gọi hàm và truyền tham số cho hàm .
Console::WriteLine(x);
}
Kết quả in ra màn hình : 25
Như vậy, ta có thể thấy khi truyền tham số theo kiểu tham chiếu, có nghĩa là ta truyền
bản thân của biến cho hàm (can thiệp trực tiếp lên ô nhớ lưu trữ giá trị tham số).
d) Hàm đệ qui và chồng chập hàm :
Hàm đệ qui là hàm gọi lại chính bản thân hàm trong đoạn mã lệnh của hàm.
VD : int Factorial (int a) // Hàm tính giai thừa.
{
if (a > 1) return (a*Factorial(a-1));
else return 1;
}
Quá tải hàm (Overload function) : là các hàm có cùng tên nhưng khác nhau về số lượng
double y = Math::E;
- Các hàm lượng giác và lượng giác ngược :
Cos (double x) : hàm cos.
Sin (double x) : hàm sin.
Tan (double x) : hàm tan.
Acos (double x) : hàm arccos.
Asin (double x) : hàm arcsin.
Atan (double x) : hàm arctan.
- Các hàm đại số :
Abs (x) : hàm lấy giá trị tuyệt đối.
Sign (x) : hàm trả về dấu của x (-1,0,1).
Round (x, y) : hàm làm tròn x đến y số
Log (x) : hàm lnx.
Log (x,y) : log
y
x.
Log10 (x) : log
10
x.
Min (x,y) : lấy giá trị nhỏ nhất của x và y.
Max (x,y) : lấy giá trị lớn nhất của x và y.
Sqrt (x) : căn bậc 2 của x.
Exp (x) : hàm e
x
.
Pow (x,y) : hàm x
y
.
Floor (x) : hàm làm tròn xuống.