Thảo Luận Về Môi Trường Phát Triển và Ưng Dụng C/C++
Các thành phần cơ bản của một chương trình
Các phần tử cơ bản của một ngôn ngữ lập trình
Bảng chữ cái
Mọi ngôn ngữ lập trình đều được xây dựng từ một bộ ký tự nào đó. Các ký tự được nhóm lại theo nhiều cách khác nhau để tạo nên các từ. Các từ lại được liên kết với nhau theo một qui tắc nào đó để tạo nên các câu lệnh. Một chương trình bao gồm nhiều câu lệnh và thể hiện một thuật toán để giải một bài toán nào đó. Ngôn ngữ C được xây dựng trên bộ ký tự sau:
26 chữ cái hoa: A B C .. Z
26 chữ cái thường: a b c .. z
10 chữ số: 0 1 2 .. 9
Các ký hiệu toán học: + - * / = ( )
Ký tự gạch nối: _
Các ký tự khác: . ,: ; [ ] {} ! \ & % # $ ...
Dấu cách (space) dùng để tách các từ. Ví dụ chữ VIET NAM có 8 ký tự, còn VIETNAM chỉ có 7 ký tự.
Chú ý:
Khi viết chương trình, ta không được sử dụng bất kỳ ký tự nào khác ngoài các ký tự trên.
Ví dụ như khi lập chương trình giải phương trình bậc hai ax2 +bx+c=0 , ta cần tính biệt thức Delta Δ= b2 - 4ac, trong ngôn ngữ C không cho phép dùng ký tự Δ, vì vậy ta phải dùng ký hiệu khác để thay thế.
Từ khoá
Từ khoá là những từ được sử dụng để khai báo các kiểu dữ liệu, để viết các toán tử và các câu lệnh. Bảng dưới đây liệt kê các từ khoá của TURBO C:
| asm | break | case | cdecl |
| char | const | continue | default |
| do | double | else | enum |
| extern | far | float | for |
| goto | huge | if | int |
| interrupt | long | near | pascal |
| register | return | short | signed |
| sizeof | static | struct | switch |
| tipedef | union | unsigned | void |
| volatile | while |
Ý nghĩa và cách sử dụng của mỗi từ khoá sẽ được đề cập sau này, ở đây ta cần chú ý:
- Không được dùng các từ khoá để đặt tên cho các hằng, biến, mảng, hàm ...
- Từ khoá phải được viết bằng chữ thường, ví dụ: viết từ khoá khai báo kiểu nguyên là int chứ không phải là INT.
Tên (định danh)
Tên là một khái niệm rất quan trọng, nó dùng để xác định các đại lượng khác nhau trong một chương trình. Chúng ta có tên hằng, tên biến, tên mảng, tên hàm, tên con trỏ, tên tệp, tên cấu trúc, tên nhãn,...
Tên được đặt theo qui tắc sau:
Tên là một dãy các ký tự bao gồm chữ cái, số và gạch nối. Ký tự đầu tiên của tên phải là chữ hoặc gạch nối. Tên không được trùng với khoá. Độ dài cực đại của tên theo mặc định là 32 và có thể được đặt lại là một trong các giá trị từ 1 tới 32 nhờ chức năng: Option-Compiler-Source-Identifier length khi dùng TURBO C.
Ví dụ:
Các tên đúng:
a_1 delta x1 _step GAMA
Các tên sai :
| 3MN | Ký tự đầu tiên là số |
| m#2 | Sử dụng ký tự # |
| f(x) | Sử dụng các dấu ( ) |
| do | Trùng với từ khoá |
| te ta | Sử dụng dấu trắng |
| Y-3 | Sử dụng dấu - |
Chú ý:
Trong TURBO C, tên bằng chữ thường và chữ hoa là khác nhau ví dụ tên AB khác với ab. trong C, ta thường dùng chữ hoa để đặt tên cho các hằng và dùng chữ thường để đặt tên cho hầu hết cho các đại lượng khác như biến, biến mảng, hàm, cấu trúc. Tuy nhiên đây không phải là điều bắt buộc.
Các kiểu dữ liệu cơ bản
Kiểu dữ liệu
Các số liệu lưu trữ trong máy tính gọi là dữ liệu (data). Mỗi đơn vị dữ liệu thuộc một kiểu dữ liệu nào đó.
Kiểu dữ liệu là một tập hợp các giá trị có cùng một tính chất và tập hợp các phép toán thao tác trên các giá trị đó. Người ta chia kiểu dữ liệu ra làm 2 loại: kiểu dữ liệu sơ cấp và kiểu dữ liệu có cấu trúc.
- Kiểu dữ liệu sơ cấp
Kiểu dữ liệu sơ cấp là kiểu dữ liệu mà giá trị của nó là đơn nhất.
Ví dụ: Kiểu int gọi là kiểu sơ cấp vì kiểu này bao gồm các số nguyên từ -32768 đến 32767 và các phép toán +, -, *, /, %…
- Kiểu dữ liệu có cấu trúc
Kiểu dữ liệu có cấu trúc là kiểu dữ liệu mà các giá trị của nó là sự kết hợp của các giá trị khác.
Ví dụ: Kiểu chuỗi ký tự trong ngôn ngữ lập trình C là một kiểu dữ liệu có cấu trúc.
Các ngôn ngữ lập trình đều có những kiểu dữ liệu do ngôn ngữ xây dựng sẵn, mà ta gọi là các kiểu chuẩn. Chẳng hạn như kiểu int, char… trong C; integer, array… trong Pascal. Ngoài ra, hầu hết các ngôn ngữ đều cung cấp cơ chế cho phép người lập trình định nghĩa kiểu của riêng mình để phục vụ cho việc viết chương trình.
Một số kiểu dữ liệu trong ngôn ngữ C
| Kiểu | Phạm vi biểu diễn | Số ký tự | Kích thước |
| Char ( Signed char ) | -128 đến 127 | 256 | 1 byte |
| Unsigned char | 0 đến 255 | 256 | 1 byte |
| int | -32768 đến 32767 | 2 byte | |
| unsigned int | 0 đến 65535 | 2 byte | |
| long | -2147483648 đến 2147483647 | 4 byte | |
| unsigned long | 0 đến 4294967295 | 4 byte | |
| Float | 3.4E-38 đến 3.4E+38 | 7 đến 8 | 4 byte |
| Double | 1.7E-308 đến 1.7E+308 | 15 đến 16 | 8 byte |
| long double | 3.4E-4932 đến 1.1E4932 | 17 đến 18 | 10 byte |
Hằng (Const)
Hằng là một giá trị cố định nào đó ví dụ 3 (hằng nguyên), 'A' (hằng kí tự), 5.0 (hằng thực), "Ha noi" (hằng xâu kí tự). Một giá trị có thể được hiểu dưới nhiều kiểu khác nhau, do vậy khi viết hằng ta cũng cần có dạng viết thích hợp.
- Hằng nguyên
- kiểu short, int: 3, -7, ...
- kiểu unsigned: 3, 123456, ...
- kiểu long, long int: 3L, -7L, 123456L, ... (viết L vào cuối mỗi giá trị)
Các cách viết trên là thể hiện của số nguyên trong hệ thập phân, ngoài ra chúng còn được viết dưới các hệ đếm khác như hệ cơ số 8 hoặc hệ cơ số 16. Một số nguyên trong cơ số 8 luôn luôn được viết với số 0 ở đầu, tương tự với cơ số 16 phải viết với 0x ở đầu. Ví dụ ta biết 65 trong cơ số 8 là 101 và trong cơ số 16 là 41, do đó 3 cách viết 65, 0101, 0x41 là như nhau, cùng biểu diễn giá trị 65.
- Hằng thực
Một số thực có thể được khai báo dưới dạng kiểu float hoặc double và các giá trị của nó có thể được viết dưới một trong hai dạng.
- Dạng dấu phảy tĩnh
Theo cách viết thông thường. Ví dụ: 3.0, -7.0, 3.1416, ...
- Dạng dấu phảy động
Tổng quát, một số thực x có thể được viết dưới dạng: men hoặc mEn, trong đó m được gọi là phần định trị, n gọi là phần bậc (hay mũ). Số men biểu thị giá trị x = m x 10n. Ví dụ số π = 3.1416 có thể được viết:
π = … = 0.031416e2 = 0.31416e1 = 3.1416e0 = 31.416e-1 = 314.16e-2 = …
vì π = 0.031416 x 102 = 0.31416 x 101 = 3.1416 x 100 = …
Như vậy một số x có thể được viết dưới dạng mEn với nhiều giá trị m, n khác nhau, phụ thuộc vào dấu phảy ngăn cách phần nguyên và phần thập phân của số. Do vậy cách viết này được gọi là dạng dấu phảy động.
- Hằng kí tự
- Cách viết hằng
Có 2 cách để viết một hằng kí tự. Đối với các kí tự có mặt chữ thể hiện ta thường sử dụng cách viết thông dụng đó là đặt mặt chữ đó giữa 2 dấu nháy đơn như: 'A', '3', ' ' (dấu cách) ... hoặc sử dụng trực tiếp giá trị số của chúng. Ví dụ các giá trị tương ứng của các kí tự trên là 65, 51 và 32. Với một số kí tự không có mặt chữ ta buộc phải dùng giá trị (số) của chúng, như viết 27 thay cho kí tự được nhấn bởi phím Escape, 13 thay cho kí tự được nhấn bởi phím Enter ...
Để biểu diễn kí tự bằng giá trị số ta có thể viết trực tiếp (không dùng cặp dấu nháy đơn) giá trị đó dưới dạng hệ số 10 (như trên) hoặc đặt chúng vào cặp dấu nháy đơn, trường hợp này chỉ dùng cho giá trị viết dưới dạng hệ 8 hoặc hệ 16 theo mẫu sau:
- '\kkk': không quá 3 chữ số trong hệ 8. Ví dụ '\11' biểu diễn kí tự có mã 9.
- '\xkk': không quá 2 chữ số trong hệ 16. Ví dụ '\x1B' biểu diễn kí tự có mã 27.
Tóm lại, một kí tự có thể có nhiều cách viết, chẳng hạn 'A' có giá trị là 65 (hệ 10) hoặc 101 (hệ 8) hoặc 41 (hệ 16), do đó kí tự 'A' có thể viết bởi một trong các dạng sau:
65, 0101, 0x41 hoặc 'A' , '\101' , '\x41'
Tương tự, dấu kết thúc xâu có giá trị 0 nên có thể viết bởi 0 hoặc '\0' hoặc '\x0', trong các cách này cách viết '\0' được dùng thông dụng nhất.
- Một số hằng thông dụng
Đối với một số hằng kí tự thường dùng nhưng không có mặt chữ tương ứng, hoặc các kí tự được dành riêng với nhiệm vụ khác, khi đó thay vì phải nhớ giá trị của chúng ta có thể viết theo qui ước sau:
'\n' : biểu thị kí tự xuống dòng (cũng tương đương với endl)
'\t' : kí tự tab
'\a' : kí tự chuông (tức thay vì in kí tự, loa sẽ phát ra một tiếng 'bíp')
'\r' : xuống dòng
'\f' : kéo trang
'\\' : dấu \
'\?' : dấu chấm hỏi ?
'\'' : dấu nháy đơn '
'\"' : dấu nháy kép "
'\kkk' : kí tự có mã là kkk trong hệ 8
'\xkk' : kí tự có mã là kk trong hệ 16
Ví dụ:
cout << "Hôm nay trời \t nắng \a \a \a \n" ;
sẽ in ra màn hình dòng chữ "Hôm nay trời" sau đó bỏ một khoảng cách bằng một tab (khoảng 8 dấu cách) rồi in tiếp chữ "nắng", tiếp theo phát ra 3 tiếng chuông và cuối cùng con trỏ trên màn hình sẽ nhảy xuống đầu dòng mới.
Do dấu cách (phím spacebar) không có mặt chữ, nên trong một số trường hợp để tránh nhầm lẫn chúng tôi qui ước sử dụng kí hiệu <> để biểu diễn dấu cách. Ví dụ trong giáo trình này dấu cách (có giá trị là 32) được viết ' ' (dấu nháy đơn bao một dấu cách) hoặc rõ ràng hơn bằng cách viết theo qui ước <>.
- Hằng xâu kí tự
Là dãy kí tự bất kỳ đặt giữa cặp dấu nháy kép. Ví dụ: "Lớp K43*", "12A4", "A", "<>", "" là các hằng xâu kí tự, trong đó "" là xâu không chứa kí tự nào, các xâu "<>", "A" chứa 1 kí tự ... Số các kí tự giữa 2 dấu nháy kép được gọi là độ dài của xâu. Ví dụ xâu "" có độ dài 0, xâu "<>" hoặc "A" có độ dài 1 còn xâu "Lớp K43*" có độ dài 8.
Chú ý phân biệt giữa 2 cách viết 'A' và "A", tuy chúng cùng biểu diễn chữ cái A nhưng chương trình sẽ hiểu 'A' là một kí tự còn "A" là một xâu kí tự (do vậy chúng được bố trí khác nhau trong bộ nhớ cũng như cách sử dụng chúng là khác nhau). Tương tự ta không được viết '' (2 dấu nháy đơn liền nhau) vì không có khái niệm kí tự "rỗng". Để chỉ xâu rỗng (không có kí tự nào) ta phải viết "" (2 dấu nháy kép liền nhau).
Tóm lại một giá trị có thể được viết dưới nhiều kiểu dữ liệu khác nhau và do đó cách sử dụng chúng cũng khác nhau. Ví dụ liên quan đến khái niệm 3 đơn vị có thể có các cách viết sau tuy nhiên chúng hoàn toàn khác nhau:
- 3 : Số nguyên 3 đơn vị
- 3L : Số nguyên dài 3 đơn vị
- 3.0 : Số thực 3 đơn vị
- '3' : Chữ số 3
- "3" : xâu chứa kí tự duy nhất là 3
- Khai báo hằng
Một giá trị cố định (hằng) được sử dụng nhiều lần trong chương trình đôi khi sẽ thuận lợi hơn nếu ta đặt cho nó một tên gọi, thao tác này được gọi là khai báo hằng. Ví dụ một chương trình quản lý sinh viên với giả thiết số sinh viên tối đa là 50. Nếu số sinh viên tối đa không thay đổi trong chương trình ta có thể đặt cho nó một tên gọi như sosv chẳng hạn. Trong suốt chương trình bất kỳ chỗ nào xuất hiện giá trị 50 ta đều có thể thay nó bằng sosv. Tương tự C++ cũng có những tên hằng được đặt sẵn, được gọi là các hằng chuẩn và NSD có thể sử dụng khi cần thiết. Ví dụ hằng π được đặt sẵn trong C++ với tên gọi M_PI. Việc sử dụng tên hằng thay cho hằng có nhiều điểm thuận lợi như sau:
- Chương trình dễ đọc hơn, vì thay cho các con số ít có ý nghĩa, một tên gọi sẽ làm NSD dễ hình dung vai trò, nội dung của nó. Ví dụ, khi gặp tên gọi sosv NSD sẽ hình dung được chẳng hạn, "đây là số sinh viên tối đa trong một lớp", trong khi số 50 có thể là số sinh viên mà cũng có thể là tuổi của một sinh viên nào đó.
- Chương trình dễ sửa chữa hơn, ví dụ bây giờ nếu muốn thay đổi chương trình sao cho bài toán quản lý được thực hiện với số sinh viên tối đa là 60, khi đó ta cần tìm và thay thế hàng trăm vị trí xuất hiện của 50 thành 60. Việc thay thế như vậy dễ gây ra lỗi vì có thể không tìm thấy hết các số 50 trong chương trình hoặc thay nhầm số 50 với ý nghĩa khác như tuổi của một sinh viên nào đó chẳng hạn. Nếu trong chương trình sử dụng hằng sosv, bây giờ việc thay thế trở nên chính xác và dễ dàng hơn bằng thao tác khai báo lại giá trị hằng sosv bằng 60. Lúc đó trong chương trình bất kỳ nơi nào gặp tên hằng sosv đều được chương trình hiểu với giá trị 60.
Để khai báo hằng ta dùng các câu khai báo sau:
#define tên_hằng giá_trị_hằng ;
hoặc:
const tên_hằng = giá_trị_hằng ;
Ví dụ:
#define sosv 50 ;
#define MAX 100 ;
const sosv = 50 ;
Như trên đã chú ý một giá trị hằng chưa nói lên kiểu sử dụng của nó vì vậy ta cần khai báo rõ ràng hơn bằng cách thêm tên kiểu trước tên hằng trong khai báo const, các hằng khai báo như vậy được gọi là hằng có kiểu.
Ví dụ:
const int sosv = 50 ;
const float nhiet_do_soi = 100.0 ;
Biến(Variable)
Biến là một đơn vị dữ liệu của chương trình, biến được xác định bởi định danh biến, hay đơn giản gọi là tên biến. Một tên biến hợp lệ là một chuỗi gồm các chữ cái, chữ số hoặc kí tự gạch dưới. Chiều dài của một tên là không giới hạn.
Kí tự trống, các kí tự đánh dấu đều không thể có mặt trong một tên. Chỉ có chữ cái, chữ số và kí tự gạch dưới là được cho phép. Thêm vào đó, một tên biến luôn phải bắt đầu bằng một chữ cái. Chúng cũng có thể bắt đầu bằng kí tự gạch dưới ( _ ) nhưng kí tự này thường được dành cho các liên kết bên ngoài (external link) hoặc giữa các tên hàm. Không bao giờ chúng bắt đầu bằng một chữ số.
Một luật nữa mà bạn phải quan tâm đến khi tạo ra các tên của riêng mình là chúng không được trùng với bất kì từ khoá nào của ngôn ngữ hay của trình biên dịch, ví dụ các tên sau đây luôn luôn được coi là từ khoá theo chuẩn ANSI-C++ và do vậy chúng không thể được dùng để đặt tên
CODE
asm, car, bool, break, marry, catch, to char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, to register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t
Thêm vào đó, một số biểu diễn khác của các toán tử (operator) cũng không được dùng làm tên vì chúng là những từ được dành riêng trong một số trường hợp.
CODE
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq
Trình dịch của bạn có thể thêm một từ dành riêng đặc trưng khác. Ví dụ, rất nhiều trình dịch 16 bit (như các trình dịch cho DOS) còn có thể các từ khoá far, huge và near.
Chú ý: Ngôn ngữ C/C++ là "case sensitive" có nghĩa là phân biệt chữ hoa chữ thường. Ví dụ một biến có tên RESULT khác với result cũng như Result.
Mỗi biến cần phải được khai báo trước khi đưa vào sử dụng. Việc khai báo biến được thực hiện theo mẫu sau:
“Kiểu dữ liệu của biến” “tên biến”;
Ví dụ:
| int a,b,c; | Khai báo ba biến int là a,b,c |
| long dai,mn; | Khai báo hai biến long là dai và mn |
| char kt1,kt2; | Khai báo hai biến ký tự là kt1 và kt2 |
| float x,y | Khai báo hai biến float là x và y |
| double canh1, canh2; | Khai báo hai biến double là canh1 và canh2 |
Biến kiểu int chỉ nhận được các giá trị kiểu int. Các biến khác cũng có ý nghĩa tương tự. Các biến kiểu char chỉ chứa được một ký tự. Để lưu trữ được một xâu ký tự cần sử dụng một mảng kiểu char.
Vị trí của khai báo biến
Để có thể sử dụng một biến trong C/C++, đầu tiên chúng ta phải khai báo nó, ghi rõ nó là kiểu dữ liệu nào. Chúng ta chỉ cần viết tên kiểu (như int, short, float...) tiếp theo sau đó là một tên biến hợp lệ.
Ví dụ:
CODE
int a; //khai báo biến kiểu số nguyên integer
float mynumber; //khai báo biến kiểu số thực dấu phẩy động
Dòng đầu tiên khai báo một biến kiểu int với tên là a. Dòng thứ hai khai báo một biến kiểu float với tên mynumber. Sau khi được khai báo, các biến trên có thể được dùng trong phạm vi (scope) của chúng trong chương trình. Nếu bạn muốn khai báo một vài biến có cùng một kiểu và bạn muốn tiết kiệm công sức viết bạn có thể khai báo chúng trên một dòng, ngăn cách các tên bằng dấu phẩy.
Ví dụ:
CODE
int a, b, c;
khai báo ba biến kiểu int (a, b và c) và hoàn toàn tương đương với:
CODE
int a;
int b;
int c;
Các kiểu số nguyên (char, short, long và int) có thể là số có dấu hay không dấu tuỳ theo miền giá trị mà chúng ta cần biểu diễn. Vì vậy khi xác định một kiểu số nguyên chúng ta đặt từ khoá signed (hoặc không cần) hoặc unsigned trước tên kiểu dữ liệu.
Ví dụ:
CODE
unsigned short nNumberOfSons;
signed int nMyAccountBalance;
Nếu ta không chỉ rõ signed hoặc unsigned nó sẽ được coi là có dấu, vì vậy trong khai báo thứ hai chúng ta có thể viết:
CODE
int nMyAccountBalance;
cũng hoàn toàn tương đương với dòng khai báo ở trên. Trong thực tế, rất ít khi người ta dùng đến từ khoá signed. Ngoại lệ duy nhất của luật này kiểu char. Trong chuẩn ANSI-C++ nó là kiểu dữ liệu khác với signed char và unsigned char.
Để có thể thấy rõ hơn việc khai báo trong chương trình, chúng ta sẽ xem xét một đoạn mã C++
Ví dụ như sau:
CODE
// thao tác tính toán với các biến
#include <iostream>
int main ()
{
//khai báo biến kiểu số nguyên integer
int a, b;
int result;
//khởi gán và tính toán
a = 5;
b = 2;
a = a + 1;
result = a - b;
//in kết quả
cout << result;
//thoát chương trình
return 0;
}
[code]
Kết quả sau khi thực hiện chương trình là:
[code]
4
Đừng lo lắng nếu như việc khai báo có vẻ hơi lạ lùng với bạn. Bạn sẽ thấy phần chi tiết còn lại trong phần tiếp theo
Khởi tạo các biến (Initial)
Khi khai báo một biến, giá trị của nó mặc nhiên là không xác định. Nhưng có thể bạn sẽ muốn nó mang một giá trị xác định khi được khai báo. Để làm điều đó, bạn chỉ cần viết dấu bằng và giá trị bạn muốn biến đó sẽ mang:
kiểu tên_biến = giá_trị_khởi_tạo_ban_đầu;
Ví dụ, nếu chúng ta muốn khai báo một biến int là a chứa giá trị 0 ngay từ khi khởi tạo, chúng ta sẽ viết:
CODE
int a = 0;
Bổ xung vào cách khởi tạo kiểu C này, C++ còn có thêm một cách mới để khởi tạo biến bằng cách bọc một cặp ngoặc đơn sau giá trị khởi tạo.
Ví dụ:
CODE
int a (0);
Cả hai cách đều hợp lệ trong C++.
Lưu ý: một biến khi được khởi tạo ta vẫn có thể gán cho nó 1 giá trị khác trong quá trình chương trình thực thi và giá trị đó sẽ hợp lệ trong phạm vi hoạt động của biến đó (xem phần sau)
Phạm vi hoạt động của biến (Scope)
Tất cả các biến mà chúng ta sẽ sử dụng đều phải được khai báo trước. Một điểm khác biết giữa C và C++ là trong C++ chúng ta có thể khai báo biến ở bất kì nơi nào trong chương trình, thậm chí là ngay ở giữa các lệnh thực hiện chứ không chỉ là ở đầu khối lệnh như ở trong C.
Mặc dù vậy chúng ta vẫn nên theo cách của ngôn ngữ C khi khai báo các biến bởi vì nó sẽ rất hữu dụng khi cần sửa chữa một chương trình có tất cả các phần khai báo được gộp lại với nhau. Bởi vậy, cách thông dụng nhất để khai báo biến là đặt nó trong phần bắt đầu của mỗi hàm (biến cục bộ - local) hay trực tiếp trong thân chương trình, ngoài tất cả các hàm (biến toàn cục - global).
Global variables (biến toàn cục) có thể được sử dụng ở bất kì đâu trong chương trình, ngay sau khi nó được khai báo và bắt buộc phải đặt ở trên cùng ngoài tất cả các hàm hoặc đặt ở file header .h
Local variables (biến cục bộ) có tầm hoạt động bị giới hạn trong phần mã mà nó được khai báo - thường là trong dấu { và } gần nhất. Nếu chúng được khai báo ở đầu một hàm (như hàm main), tầm hoạt động sẽ là toàn bộ hàm main. Điều đó có nghĩa là trong ví dụ trên, các biến được khai báo trong hàm main() chỉ có thể được dùng trong hàm đó, không được dùng ở bất kì đâu khác, tức là 1 biến được khai báo trong hàm A thì ko thể sử dụng nó trong hàm B nằm ngoài hàm A.
Bên cạnh các biến toàn cục và cục bộ, còn có các biến ngoài (external). Các biến này không những được dùng trong một file mã nguồn mà còn trong tất cả các file được liên kết trong chương trình.
Trong C++ tầm hoạt động của một biến chính là khối lệnh mà nó được khai báo (một khối lệnh là một tập hợp các lệnh được gộp lại trong một bằng các ngoặc nhọn { } ). Nếu nó được khai báo trong một hàm tầm hoạt động sẽ là hàm đó, còn nếu được khai báo trong vòng lặp thì tầm hoạt động sẽ chỉ là vòng lặp đó....
Hãy xem ví dụ sau và tìm hiểu cách hoạt động của các biến:
CODE
int nGlobal; //biến toàn cục có thể đựơc sử dụng trong cả hàm A và B
void A()
{
int a; //biến cục bộ của hàm A
nGlobal = 5; //câu lệnh gán cho biến toàn cục hợp lệ
b = 1; //trình biên dịch sẽ báo lỗi vì biến này chưa được khai báo trong
//hàm A
}
void B()
{
int b; //biến cục bộ của hàm B
for(int i=0; i<10; i++)
{
int c = 5; //khai báo và khởi tạo biến c local trong vòng for
}
c = 1; //không hợp lệ vì biến c chỉ có phạm vi hoạt động trong vòng lặp
//for }
Các khai báo cần phải được đặt ngay sau dấu { đầu tiên của thân hàm và cần đứng trước mọi câu lệnh khác. Sau đây là một ví dụ về khai báo biến sai:
( Khái niệm về hàm và cấu trúc chương trình sẽ nghiên cứu sau này)
main()
{
int a,b,c;
a=2;
int d; /* Vị trí của khai báo sai */
.....
}
Khởi đầu cho biến:
Nếu trong khai báongay sau tên biến ta đặt dấu = và một giá trị nào đó thì đây chính là cách vừa khai báo vừa khởi đầu cho biến.
Ví dụ:
int a,b=20,c,d=40;
float e=-55.2,x=27.23,y,z,t=18.98;
Việc khởi đầu và việc khai báo biến rồi gán giá trị cho nó sau này là hoàn toàn tương đương.
Lấy địa chỉ của biến:
Mỗi biến được cấp phát một vùng nhớ gồm một số byte liên tiếp. Số hiệu của byte đầu chính là địa chỉ của biến. Địa chỉ của biến sẽ được sử dụng trong một số hàm ta sẽ nghiên cứu sau này ( ví dụ như hàm scanf ).
Để lấy địa chỉ của một biến ta sử dụng phép toán: & tên biến
Các phép toán
Các phép toán số học
Các phép toán hai ngôi số học là
| Phép toán | Ý nghiã | Ví dụ |
| + | Phép cộng | a+b |
| - | Phép trừ | a-b |
| * | Phép nhân | a*b |
| / | Phép chia | a/b ( Chia số nguyên sẽ chặt phần thập phân ) |
| % | Phép lấy phần dư | a%b( Cho phần dư của phép chia a cho b ) |
Có phép toán một ngôi - ví du -(a+b) sẽ đảo giá trị của phép cộng (a+b).
Ví dụ:
11/3=3
11%3=2
-(2+6)=-8
Các phép toán + và - có cùng thứ tự ưu tiên, có thứ tự ưu tiên nhỏ hơn các phép * , / , % và cả ba phép này lại có thứ tự ưu tiên nhỏ hơn phép trừ một ngôi.
Các phép toán số học được thực hiện từ trái sang phải. Số ưu tiên và khả năng kết hợp của phép toán được chỉ ra trong một mục sau này
Các phép toán quan hệ và logic
Phép toán quan hệ và logic cho ta giá trị đúng (1) hoặc giá trị sai (0). Nói cách khác, khi các điều kiện nêu ra là đúng thì ta nhận được giá trị 1, trái lại ta nhận giá trị 0.
Các phép toán quan hệ là:
| Phép toán | Ý nghiã | Ví dụ |
| > | So sánh lớn hơn | a>b 4>5 có giá trị 0 |
| >= | So sánh lớn hơn hoặc bằng | a>=b 6>=2 có giá trị 1 |
| < | So sánh nhỏ hơn | a<b 6<=7 có giá trị 1 |
| <= | So sánh nhỏ hơn hoặc bằng | a<=b8<=5 có giá trị 0 |
| == | So sánh bằng nhau | a==b6==6 có giá trị 1 |
| != | So sánh khác nhau | a!=b9!=9 có giá trị 0 |
Bốn phép toán đầu có cùng số ưu tiên, hai phép sau có cùng số thứ tự ưu tiên nhưng thấp hơn số thứ tự của bốn phép đầu.
Các phép toán quan hệ có số thứ tự ưu tiên thấp hơn so với các phép toán số học, cho nên biểu thức
i<n-1
được hiểu là i<(n-1).
Các phép toán logic:
Trong C sử dụng ba phép toán logic:
Phép phủ định một ngôi !
| a | !a |
| khác 0 | 0 |
| bằng 0 | 1 |
Phép và (AND) &&
Phép hoặc ( OR ) ||
| a | b | a&&b | a||b |
| khác 0 | khác 0 | 1 | 1 |
| khác 0 | bằng 0 | 0 | 1 |
| bằng 0 | khác 0 | 0 | 1 |
| bằng 0 | bằng 0 | 0 | 0 |
Các phép quan hệ có số ưu tiên nhỏ hơn so với ! nhưng lớn hơn so với && và ||, vì vậy biểu thức như:
(a<b)&&(c>d)
có thể viết lại thành:
a<b&&c>d
Chú ý:
Cả a và b có thể là nguyên hoặc thực.
Phép toán tăng giảm
C đưa ra hai phép toán một ngôi để tăng và giảm các biến ( nguyên và thực ). Toán tử tăng là ++ sẽ cộng 1 vào toán hạng của nó, toán tử giảm -- thì sẽ trừ toán hạng đi 1.
Ví dụ:
n=5
++n Cho ta n=6
--n Cho ta n=4
Ta có thể viết phép toán ++ và -- trước hoặc sau toán hạng như sau: ++n, n++, --n, n--.
Sự khác nhau của ++n và n++ ở chỗ: trong phép n++ thì tăng sau khi giá trị của nó đã được sử dụng, còn trong phép ++n thì n được tăng trước khi sử dụng. Sự khác nhau giữa n-- và --n cũng như vậy.
Ví dụ:
n=5
x=++n Cho ta x=6 và n=6
x=n++ Cho ta x=5 và n=6
Thứ tự ưu tiên các phép toán
Các phép toán có độ ưu tiên khác nhau, điều này có ý nghĩa trong cùng một biểu thức sẽ có một số phép toán này được thực hiện trước một số phép toán khác.
Thứ tự ưu tiên của các phép toán được trình bày trong bảng sau:
| TT | Phép toán | Trình tự kết hợp |
| 1 | () [] -> | Trái qua phải |
| 2 | ! ~ & * - ++ -- (type ) sizeof | Phải qua trái |
| 3 | * ( phép nhân ) / % | Trái qua phải |
| 4 | + - | Trái qua phải |
| 5 | << >> | Trái qua phải |
| 6 | < <= > >= | Trái qua phải |
| 7 | == != | Trái qua phải |
| 8 | & | Trái qua phải |
| 9 | ^ | Trái qua phải |
| 10 | | | Trái qua phải |
| 11 | && | Trái qua phải |
| 12 | || | Trái qua phải |
| 13 | ?: | Phải qua trái |
| 14 | = += -= *= /= %= <<= >>= &= ^= |= | Phải qua trái |
| 15 | , | Trái qua phải |
Chú thích:
Các phép toán tên một dòng có cùng thứ tự ưu tiên, các phép toán ở hàng trên có số ưu tiên cao hơn các số ở hàng dưới.
Đối với các phép toán cùng mức ưu tiên thì trình tự tính toán có thể từ trái qua phải hay ngược lại được chỉ ra trong cột trình tự kết hợp.
Ví dụ:
*--px=*(--px) ( Phải qua trái )
8/4*6=(8/4)*6 ( Trái qua phải )
Nên dùng các dấu ngoặc tròn để viết biểu thức một cách chính xác.
Các phép toán lạ:
Dòng 1
[ ] Dùng để biểu diễn phần tử mảng, ví dụ: a[i][j]
“.” Dùng để biểu diễn thành phần cấu trúc, ví dụ: ht.ten
-> Dùng để biểu diễn thành phần cấu trúc thông qua con trỏ
Dòng 2
* Dùng để khai báo con trỏ, ví dụ: int *a
& Phép toán lấy địa chỉ, ví dụ: &x
( type) là phép chuyển đổi kiểu, ví dụ: (float)(x+y)
Dòng 15
Toán tử , thường dùng để viết một dãy biểu thức trong toán tử for.
Chuyển đổi kiểu giá trị
Việc chuyển đổi kiểu giá trị thường diễn ra một cách tự động trong hai trường hợp sau:
Khi gán biểu thức gồm các toán hạng khác kiểu.
Khi gán một giá trị kiểu này cho một biến ( hoặc phần tử mảng ) kiểu khác. Điều này xảy ra trong toán tử gán, trong việc truyền giá trị các tham số thực sự cho các đối.
Ngoài ra, ta có thể chuyển từ một kiểu giá trị sang một kiểu bất kỳ mà ta muốn bằng phép chuyển sau:
(type) biểu thức
Ví dụ:
(float) (a+b)
Chuyển đổi kiểu trong biểu thức
Khi hai toán hạng trong một phép toán có kiểu khác nhau thì kiểu thấp hơn sẽ được nâng thành kiểu cao hơn trước khi thực hiện phép toán. Kết quả thu được là một giá trị kiểu cao hơn. Chẳng hạn:
Giữa int và long thì int chuyển thành long.
Giữa int và float thì int chuyển thành float.
Giữa float và double thì float chuyển thành double.
Ví dụ:
1.5*(11/3)=4.5
1.5*11/3=5.5
(11/3)*1.5=4.5
Chuyển đổi kiểu thông qua phép gán:
Giá trị của vế phải được chuyển sang kiểu vế trái đó là kiểu của kết quả. Kiểu int có thể được được chuyển thành float. Kiểu float có thể chuyển thành int do chặt đi phần thập phân. Kiểu double chuyển thành float bằng cách làm tròn. Kiểu long được chuyển thành int bằng cách cắt bỏ một vài chữ số.
Ví dụ:
int n;
n=15.6 giá trị của n là 15
Đổi kiểu dạng (type)biểu thức:
Theo cách này, kiểu của biểu thức được đổi thành kiểu type theo nguyên tắc trên.
Ví dụ:Phép toán: (int)a
Cho một giá trị kiểu int. Nếu a là float thì ở đây có sự chuyển đổi từ float sang int. Chú ý rằng bản thân kiểu của a vẫn không bị thay đổi. Nói cách khác, a vẫn có kiểu float nhưng (int)a có kiểu int.
Đối với hàm toán học của thư viện chuẩn, thì giá trị của đối và giá trị của hàm đều có kiểu double, vì vậy để tính căn bậc hai của một biến nguyên n ta phải dùng phép ép kiểu để chuyển kiểu int sang double như sau:
sqrt((double)n)
Phép ép kiểu có cùng số ưu tiên như các toán tử một ngôi.
Chú ý:Muốn có giá trị chính xác trong phép chia hai số nguyên cần dùng phép ép kiểu:
((float)a)/b
Để đổi giá trị thực r sang nguyên, ta dùng:
(int)(r+0.5)
Chú ý thứ tự ưu tiên:
(int)1.4*10=1*10=10
(int)(1.4*10)=(int)14.0=14
Biểu thức
Biểu thức là một sự kết hợp giữa các phép toán và các toán hạng để diễn đạt một công thức toán học nào đó. Mỗi biểu thức có sẽ có một giá trị. Như vậy hằng, biến, phần tử mảng và hàm cũng được xem là biểu thức.
Trong C, ta có hai khái niệm về biểu thức:
Biểu thức gán.
Biểu thức điều kiện .
Biểu thức được phân loại theo kiểu giá trị: nguyên và thực. Trong các mệnh đề logic, biểu thức được phân thành đúng ( giá trị khác 0 ) và sai ( giá trị bằng 0 ).
Biểu thức thường được dùng trong:
Vế phải của câu lệnh gán.
Làm tham số thực sự của hàm.
Làm chỉ số.
Trong các toán tử của các cấu trúc điều khiển.
Tới đây, ta đã có hai khái niệm chính tạo nên biểu thức đó là toán hạng và phép toán. Toán hạng gồm: hằng, biến, phần tử mảng và hàm trước đây ta đã xét. Dưới đây ta sẽ nói đến các phép toán. Hàm sẽ được đề cập trong chương 6.