Tải bản đầy đủ (.pdf) (136 trang)

The c programming language bản dịch

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.03 MB, 136 trang )

MỞ ĐẦU
Ngôn ngữ lập trình C do Dennis Ritchie phát triển lần đầu tiên vào năm 1972 tại
phòng thí nghiệm Bell thuộc hãng AT&T (Mỹ) và có nguồn gốc từ ngôn ngữ BCPL (do
Martin Richards đƣa ra năm 1967) và ngôn ngữ B (do Ken Thompson phát triển từ ngôn
ngữ BCPL vào năm 1969). Ngôn ngữ C chính thức ra đời từ năm 1978 khi cuốn "Ngôn ngữ
lập trình C”do các tác giả Dennis Ritchie và Brian Kernighan đƣợc xuất bản.
Ngôn ngữ lập trình C đƣợc đánh giá cao do nhiều nguyên nhân, đó là:
 Ngôn ngữ C thể hiện các đặc trƣng của ngôn ngữ lập trình bậc cao nhƣng có những
khả năng của các ngôn ngữ lập trình bậc thấp.
 Ngôn ngữ C súc tích và cô đọng. Chƣơng trình viết bằng C thƣờng ngắn gọn, có cấu
trúc rõ ràng. Thƣ viện các hàm mẫu của C là rất phong phú.
Hiện nay ngôn ngữ C thƣờng đƣợc sử dụng rộng rãi để giải quyết các bài toán khoa
học kỹ thuật, các bài toán xử lý tín hiệu số, đồ họa, âm thanh,...Tuy nhiên ngôn ngữ C có
những khía cạnh độc đáo mà sinh viên không dễ gì nắm vững nếu không nghiên cứu nó một
cách nghiêm túc. Chính vì vậy, cuốn sách này đƣợc biên soạn với mục đích cung cấp một
cách hệ thống và đầy đủ những vấn đề cốt yếu của ngôn ngữ lập trình C và có thể dùng làm
tài liệu học tập cho các sinh viên thuộc các chuyên ngành Tin học, Toán Tin học và các
chuyên ngành khoa học kỹ thuật khác. Nội dung cuốn sách này bao gồm 7 chƣơng:
 Chƣơng 1 đề cập đến những yếu tố cơ bản trong ngôn ngữ C, bao gồm bộ ký tự, các
từ khoá, các kiểu dữ liệu, các hằng, biến, biểu thức, các toán tử.
 Chƣơng 2 trình bày việc xuất nhập dữ liệu và các lệnh có cấu trúc, bao gồm lệnh
cấu trúc rẽ nhánh (if), cấu trúc lựa chọn (switch), cấu trúc lặp (for, while,
do...while).
 Chƣơng 3 nói về hàm, quy tắc xây dựng một hàm, cách sử dụng hàm thƣ viện và
hàm tự tạo.
 Chƣơng 4,5 trình bày về mảng, con trỏ và chuỗi trong C.
 Chƣơng 6 đề cập đến các kiểu dữ liệu có cấu trúc (struct và union).
 Chƣơng 7 trình bày các thao tác xuất nhập, truy xuất tập tin trong C.
Trong mỗi chƣơng đều có nhiều ví dụ minh họa, cuối chƣơng là phần câu hỏi và bài
tập để các bạn có thể luyện tập thêm. Hiện nay, ngôn ngữ lập trình C đã đƣợc mở rộng
thành ngôn ngữ lập trình C++ hỗ trợ cho lập trình hƣớng đối tƣợng, vì vậy trong mỗi


chƣơng, một số phần mở rộng của C++ cũng đƣợc đƣa vào.
Mặc dầu tác giả đã cố gắng để cuốn sách đƣợc hoàn chỉnh, song chắc chắn sẽ không
tránh khỏi những thiếu sót, vì vậy rất mong nhận đƣợc những góp ý của độc giả.

7


Chƣơng 1
CÁC THÀNH PHẦN CƠ BẢN
CỦA NGÔN NGỮ C
Trƣớc khi tìm hiểu các thành phần cơ bản của ngôn ngữ lập trình C, chúng ta sẽ xem
một chƣơng trình C đơn giản sau đây:
#include
<stdio.h>
void main()
{
printf("\n Chào mừng bạn đến với NNLT C! ");
}

Giải thích sơ bộ ý nghĩa từng câu lệnh:
#include <stdio.h>
Đây là dòng lệnh tiền xử lý, dùng để mở một tập tin thƣ viện là stdio.h, trong đó có cài đặt
các hàm nhập xuất chuẩn (ở đây là hàm printf).
void main()
Dòng này tƣơng ứng với phần bắt đầu khai báo hàm main. Hàm main là điểm mà tất cả các
chƣơng trình C bắt đầu thực hiện. Không phụ thuộc vào vị trí của hàm main, nội dung của
hàm này luôn đƣợc thực hiện đầu tiên khi chƣơng trình bắt đầu. Mọi chƣơng trình C đều
phải tồn tại một hàm main.
Theo sau main là một cặp dấu ngoặc đơn (). Nội dung của hàm main tiếp ngay sau phần
khai báo đƣợc đặt trong các dấu ngoặc nhọn { }.

printf("Chào mừng bạn đến với NNLT C!\n");
Dòng lệnh này nhằm mục đích in ra màn hình dòng chữ Chào mừng bạn đến với NNLT
C!. Hàm printf dùng để in dữ liệu nằm trong cặp dấu ngoặc đơn ra thiết bị xuất chuẩn (ở đây
là màn hình). Chú ý dòng lệnh này kết thúc bằng dấu chấm phẩy (;). Ký tự này đƣợc dùng
để kết thúc một lệnh và bắt buộc phải có sau mỗi lệnh trong chƣơng trình C.

1.1 BỘ KÝ TỰ VÀ TỪ KHOÁ
1.1.1 BỘ ký tự
Ngôn ngữ lập trình C đƣợc xây dựng trên bộ ký tự sau:
 Các chữ cái: a, b, ..., z, A, B, C,..., Z.
 Các chữ số: bao gồm 10 chữ số 0, 1, 2,..., 9.
 Các ký hiệu: bao gồm các ký hiệu hiện có trên bàn phím nhƣ:
. , ;: [ ] { } ? ! \ _ % & ^ | () + - * / < > ...
1.1.2 Từ khóa
Từ khoá là những từ dùng riêng trong ngôn ngữ C và có một ý nghĩa hoàn toàn xác định.
Từ khóa đƣợc viết bằng chữ thƣờng. Sau đây là các từ khoá thông dụng của C:
auto
break
Case
char
typedef
const
continue
Default
do
union
double
Else
Extern
float

unsigned
for
goto
If
int
Void
long
register
Return
short
While
sizeof
static
Struct
switch
8


1.1.3 Tên
Tên là một dãy các ký tự bắt đầu bằng chữ cái hoặc ký tự gạch dƣới (_), theo sau là
chữ cái, chữ số hoặc ký tự gạch dƣới.
Chú ý:
 Trong khi lập trình, nên đặt các tên mang đầy đủ ý nghĩa hoặc mang tính gợi nhớ đến
mục đích mà bạn dùng.
 Đối với các tên dài nên dùng thêm các dấu gạch nối để dễ đọc.
 Các tên trong C có sự phân biệt chữ hoa và thƣờng. Chẳng hạn, các tên aBc, abc
hay ABC là khác nhau.

1.2 LỜI CHÚ THÍCH
Các chú thích trong C là những lời giải thích để làm cho chƣơng trình đƣợc dễ hiểu và

sáng sủa. Lời chú thích đặt giữa cặp ký tự /* và */. Dòng chú thích có thể trên nhiều dòng.
Ví dụ:
/* Bắt đầu lặp */
/* Đây là đoạn
Chƣơng trình nhập dữ liệu */
Trong C++ lời chú thích có thể đặt sau hai dấu gạch chéo //, để tạo chú thích trên từng
dòng.
Ví dụ: // Bắt đầu lặp
Khi gặp các chú thích chƣơng trình dịch sẽ bỏ qua chúng mà không dịch các dòng này.

1.3 CÁC KIỂU DỮ LIỆU CƠ BẢN
Khi lập trình, chúng ta lƣu trữ các biến trong bộ nhớ của máy tính nhƣng máy tính
phải biết ta muốn lƣu trữ gì trong chúng vì các kiểu dữ liệu khác nhau sẽ cần lƣợng bộ nhớ
khác nhau.
Bộ nhớ của máy tính đƣợc tổ chức thành các byte. Một byte có thể dùng để lƣu trữ một
loại dữ liệu nhỏ nhƣ là kiểu số nguyên từ 0 đến 255 hay một ký tự. Nhƣng máy tính có thể
xử lý các kiểu dữ liệu phức tạp hơn bằng cách gộp nhiều byte lại với nhau, nhƣ số nguyên
dài hay số thập phân.
1.3.1 Kiểu char
Kiểu char có kích thƣớc 1 byte và biểu diễn đƣợc 1 ký tự trong bảng mã ASCII. Kiểu
char thực chất là kiểu số nguyên. Có hai kiểu char là signed char (char có dấu) và unsigned
char (char không dấu). Kiểu signed char (mặc định) biểu diễn một số nguyên từ -128 đến
127 và unsigned char biểu diễn số nguyên từ 0 đến 255.
1.3.2 Kiểu số nguyên
C có nhiều kiểu số nguyên và đƣợc cho bởi bảng sau:
Tên kiểu
Kích cỡ (byte)
Phạm vi biểu diễn
int
short

long
unsigned int
unsigned long

2
2
4
2
4

-32768  32767
-32768  32767
-2147483648  -2147483647
0  65535
0  4294967295

9


Chú ý: Đối với hầu hết các ngôn ngữ lập trình dữ liệu kiểu số và kiểu ký tự luôn luôn phân
biệt nhau, chẳng hạn 5 là một số và A là một ký tự. Trong C việc phân biệt ký tự và số chỉ là
một cách tƣơng đối. Thực ra khi C xem xét ký tự là xem xét đến mã ASCII của nó. Từ khoá
char dùng để khai báo kiểu số nguyên một byte và đƣợc dùng để lƣu trữ vừa ký tự vừa số
nguyên. Chẳng hạn, sau khi ta khai báo: char c; thì ta có thể thực hiện các phép gán:
c = 'A';
c = 127;
1.3.3 Kiểu số thực
Các kiểu số thực của C đƣợc cho bởi bảng:
Tên kiểu
float

double
long double

Kích cỡ (byte)
4
8
10

Phạm vi biểu diễn
3.4E-38  3.4E+38
1.7E-308  1.7E+308
3.4E-4932  1.1E+4932

Kiểu float có độ chính xác đơn (7 chữ số sau dấu chấm thập phân) và kiểu double có độ
chính xác kép (15 chữ số sau dấu chấm thập phân)
Chú ý: Ta có thể dùng từ khóa typedef để đặt lại tên cho một kiểu dữ liệu đã có. Tên kiểu
mới này có thể đƣợc dùng để khai báo dữ liệu sau này. Cú pháp nhƣ sau:
typedef
<Kiểu dữ liệu>
<Tên kiểu định nghĩa>;
trong đó, <Kiểu dữ liệu> là từ khoá chỉ các kiểu dữ liệu cần định nghĩa, nghĩa> là một tên đƣợc đặt bởi ngƣời lập trình.
Ví dụ: typedef
int
SN;

1.4 BIẾN
Biến là một đại lƣợng có giá trị thay đổi trong quá trình thực hiện chƣơng trình. Mỗi
biến trong chƣơng trình có một tên gọi là tên biến và giá trị của nó đƣợc lƣu trữ tại một vị trí
trong bộ nhớ.

Mỗi biến khi sử dụng trong chƣơng trình đều phải đƣợc đặt tên theo quy định nhƣ quy
tắc đặt tên đã đề cập ở trên. Tên biến không đƣợc đặt trùng tên với các từ khoá của C.
Mọi biến đều phải đƣợc khai báo trƣớc khi sử dụng. Việc khai báo biến thực hiện theo
cú pháp sau đây:
Kiểu dữ liệu
Danh sách các biến;
trong đó:
Kiểu dữ liệu
là tên kiểu dữ liệu của một hay nhiều biến cần khai báo.
Danh sách các biến là một danh sách các tên biến đƣợc ngăn cách bởi dấu phẩy.
Ví dụ:
int j;
/* khai báo biến j có kiểu nguyên */
float x, y;
/* khai báo hai biến x, y có kiểu thực*/
Chú ý: 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 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
10


nhau. 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ộ) 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).
Phạm vi hoạt động của biến sẽ phụ thuộc vào vị trí mà nó đƣợc khai báo. Ta có các
cách khai báo vị trí của biến nhƣ sau:
 Vị trí của các khai báo biến đặt bên ngoài tất cả các hàm, lúc đó các biến này sẽ tác
động đến toàn bộ chƣơng trình.

Ví dụ:
int a, b;
/* a,b tác động đến toàn bộ chương trình */
void main()
{
. . .
a = a + b;
. . .
}
 Các khai báo biến đặt bên trong thân hàm, lúc đó các biến chỉ tác động bên trong hàm
đó.
Ví dụ:
void main()
{
int a, b; /* a,b chỉ tác động trong main */
a = 1;
}
 Có thể đặt các khai báo biến trong một khối lệnh ({ ... }). Lúc đó các biến chỉ hoạt
động trong khối đó mà thôi.
Ví dụ:
void main()
{
int a, b; /* a,b chỉ tác động trong main */
a = b = 5;
{
int c, d;
c = 1;
d = 2;
}
}

Trong khi khai báo các biến, ta cũng có thể đồng thời gán cho các biến những giá trị
nào đó. Các giá trị này đƣợc gọi là các giá trị khởi gán. Cú pháp để khởi gán giá trị cho một
hay nhiều biến là:
Kiểu dữ liệu
Danh sách các phép gán;
trong đó <Danh sách các phép gán> chứa các phép gán giá trị cho các biến đƣợc khai báo.
Chúng có dạng Tên biến = Giá trị khởi gán và đƣợc ngăn cách nhau bởi dấu phẩy. trị khởi gán> là các hằng hoặc biểu thức hằng. C không chấp nhận hàm và biến làm giá trị
khởi gán.
Ví dụ:
char c = 65;
/* khởi gán c là 65 */
int a = 6, b = 7;
/* khởi gán cho a là 6 và b là 7 */
float x = y = 6.5;
/* khởi gán cho x và y là 6.5 */
11


Chú ý: Mỗi biến khi đƣợc khai báo sẽ đƣợc trình biên dịch cấp phát một vùng nhớ gồm một
số byte liên tiếp có kích thƣớc là kích thƣớc của kiểu. Để lấy địa chỉ của biến (tức là địa chỉ
vùng nhớ chứa giá trị của biến) ta dùng toán tử &, cú pháp nhƣ sau: &tên biến

1.5 HẰNG
Hằng là một đại lƣợng mà giá trị của nó không thay đổi trong khi thực hiện chƣơng trình.
1.5.1. Định nghĩa hằng
Có thể định nghĩa hằng với tên nào đó để có thể sử dụng thƣờng xuyên bằng cách sử
dụng chỉ thị #define nhƣ sau:
#define Tên hằng giá trị
Ví dụ:

#define
NEWLINE
'\n'
#define
N 100
Trong thực tế việc duy nhất mà trình biên dịch làm khi nó tìm thấy một chỉ thị #define
là thay thế các tên hằng tại bất kỳ chỗ nào chúng xuất hiện bằng giá trị mà chúng đƣợc định
nghĩa. Vì vậy các hằng định nghĩa bởi #define đƣợc xem là các hằng macro.
Chỉ thị #define không phải là một lệnh thực thi, nó là chỉ thị tiền xử lý (preprocessor),
đó là lý do trình biên dịch xem cả dòng là một chỉ thị và dòng đó không cần kết thúc bằng
dấu chấm phẩy. Nếu bạn thêm dấu chấm phẩy vào cuối dòng, nó sẽ đƣợc xem là một phần
của giá trị định nghĩa hằng.
1.5.2 Khai báo hằng
Cú pháp khai báo hằng:
const
Kiểu dữ liệu
giá trị có thể là hằng hoặc biểu thức hằng.
Ví dụ: const
float R = 10.5;

Tên hằng

=

giá trị;

1.5.3 Các loại hằng
1. Hằng nguyên: Là một số nguyên có giá trị trong khoảng từ -32768 đến 32767. Ta phân
biệt các loại hằng nguyên sau đây:
 Hằng nguyên hệ 10: là một dãy ký tự số không bắt đầu bằng số 0.

 Hằng nguyên hệ 8: là một dãy ký tự số từ 0 đến 7 và bắt đầu bằng số 0.
Ví dụ:
const int i = 010; /* i = 8 */
 Hằng nguyên hệ 16: là một dãy ký tự số từ 0 đến 9, các chữ cái từ A đến F và bắt đầu
bằng 0x (hoặc 0X)
Ví dụ:
const int i = 0x10; /* i = 16 */
const int j = 0xFF; /* j = 255 */
 Hằng nguyên có định trƣớc kiểu: Là các hằng số đƣợc viết bằng cách thêm một ký tự
vào cuối dãy số: L cho kiểu long, U cho kiểu unsigned int, UL cho kiểu unsigned long.
Ví dụ:
123456789L là hằng số nguyên kiểu long
2. Hằng thực: Đƣợc viết theo hai cách:
 Dạng dấu chấm tĩnh: Số bao gồm phần nguyên, dấu chấm thập phân và phần lẻ.
Ví dụ: 23.45, -12.34
 Dạng khoa học: Số gồm hai phần:
- Phần định trị: là số nguyên hoặc thực hệ 10,
- Phần bậc: là một số nguyên.
12


- Hai phần này cách nhau bởi ký tự e hoặc E, là lũy thừa của 10.
Ví dụ:
12e+3 (số 12000)
và 12e-2 (số 0.12)
3. Hằng ký tự: Là một ký tự đƣợc viết trong hai dấu nháy đơn ‟ ‟. Chẳng hạn, ‟a‟ là một
hằng ký tự.
Hằng ký tự cũng đƣợc xem là những trị nguyên vì mỗi ký tự đƣợc gán bằng một giá trị
nguyên tƣơng ứng với mã của nó trong bảng mã ASCII. Vì vậy hằng ký tự có thể tham gia
vào các biểu thức nhƣ mọi số nguyên khác. Chẳng hạn ‟a‟ - ‟A‟ cho kết quả là 32.

Hằng ký tự còn có cách viết khác nhƣ sau: ‟\x1x2x3‟ trong đó x1x2x3 là số hệ 8 mà giá
trị của nó bằng mã ASCII của ký tự biểu diễn.
Ví dụ: Hằng ký tự ‟a‟ có mã ASCII là 97, đổi sang số hệ 8 là 0141, vậy hằng ký tự ‟a‟ có
thể viết cách khác là ‟\141‟.
Chú ý: Có những ký tự mang tính chất riêng biệt đƣợc gọi là các mã điều khiển. Sau đây là
một số mã điều khiển:
\n
\r
\t
\v
\b
\f
\a
\'
\"
\?
\\

Xuống dòng
Lùi về đầu dòng
Ký tự tab
Căn thẳng theo chiều dọc
Backspace
Sang trang
Tiếng kêu bíp
Dấu nháy đơn
Dấu nháy kép
Dấu hỏi
Ký tự xổ ngƣợc


4. Hằng chuỗi: Là một dãy các ký tự bất kỳ đặt trong hai dấu nháy kép “". Chẳng hạn,
"Trung tâm” hay "“(chuỗi rỗng) là các hằng chuỗi.
Chuỗi ký tự đƣợc lƣu trữ trong máy dƣới dạng một mảng có các phần tử là các ký tự
riêng biệt. Trình biên dịch tự động thêm ký tự null (‟\0‟) vào cuối mỗi chuỗi (ký tự ‟\0‟
đƣợc xem là dấu hiệu kết thúc chuỗi).
Chú ý: Cần phân biệt 'a' và "a", 'a' là hằng ký tự lƣu trữ trong một byte còn "a”là một hằng
chuỗi lƣu trữ trong một mảng một chiều gồm 2 phần tử: phần tử thứ nhất chứa 'a' và phần tử
thứ hai là ‟\0‟.

1.6 KIỂU enum
Kiểu enum có kích thƣớc 2 byte và có thể viết theo hai dạng sau đây:
Dạng 1: enum <tên kiểu> {<các giá trị liệt kê>} <tb1>,<tb2 >,...<tbk >;
Dạng 2: enum {<các giá trị liệt kê>} <tb1>,<tb2>,...<tbk >;
trong đó:
<tên kiểu> là tên kiểu liệt kê đƣợc đặt theo quy tắc của tên.
<tb1>,<tb2>,..., <tbk > là tên các tên biến kiểu enum.
<các giá trị liệt kê> là một danh sách các tên hằng đƣợc đặt đúng quy tắc về tên. Các
tên này dùng để đại diện cho các giá trị của kiểu và đƣợc viết cách nhau dấu phẩy (,) và phải
là duy nhất không trùng tên. Chúng hoạt động nhƣ các giá trị của kiểu enum.
13


Câu lệnh ở dạng 1 định nghĩa kiểu enum có tên là <tên kiểu>. Sau này có thể dùng
cụm từ enum <tên kiểu> để khai báo các biến enum.
Câu lệnh ở dạng 2 khai báo các biến enum có tên là <tb1>, <tb2>,...<tbk>. Các biến này
có thể nhận các giá trị từ <các giá trị liệt kê>.
Kích thƣớc của kiểu enum mặc định là số nguyên 2 byte có dấu (int). Các biến kiểu
enum thực ra là các biến kiểu int, do đó chúng vẫn có thể nhận các giá trị nguyên khác.
Ví dụ: Câu lệnh sau tạo ra kiểu liệt kê có tên là ngay mang các giá trị hai, ba, tu, nam, sau,
bay, chunhat. d1, d2 là 2 biến thuộc kiểu liệt kê ngay.

enum ngay {hai,ba,tu,nam,sau,bay,chunhat} d1,d2;
Câu lệnh này tƣơng đƣơng các lệnh sau:
enum ngay {hai,ba,tu,nam,sau,bay,chunhat};
enum ngay d1,d2;
Chú ý: Các giá trị của các tên đƣợc liệt kê trong kiểu liệt kê sẽ đƣợc C tự động gán theo thứ
tự bắt đầu từ 0, 1, 2, ... Tuy nhiên có thể thay đổi các giá trị này bằng cách gán cho chúng
giá trị mới. Lúc đó các tên không đƣợc gán giá trị sau sẽ nhận các giá trị tiếp theo giá trị mà
tên trƣớc đã nhận.
Ví dụ: Nếu có một khai báo nhƣ sau:
enum xe_may {honda, suzuki= 4, yamaha= -4, vmep };
thì các giá trị của các hằng lần lƣợt là: honda là 0, suzuki là 4, yamaha là
-4, và vmep là -3.

1.7 BIỂU THỨC VÀ CÁC TOÁN TỬ
Biểu thức là một dãy các toán hạng đƣợc nối với nhau bằng các toán tử và cho kết quả
là một giá trị gọi là giá trị của biểu thức. Có thể sử dụng cặp dấu ngoặc đơn () trong biểu
thức.
 Toán hạng có thể gồm các biến, các hằng, lời gọi hàm.
 Toán tử có thể là các toán tử số học, logic, quan hệ, ...
Ví dụ: Các dãy biểu diễn dƣới đây là các biểu thức:
5 + j
5*j + 6
f()/(4*x)
1.7.1 Toán tử số học
 Các toán tử hai ngôi:
Toán tử

Ý nghĩa

+


Cộng

-

Trừ

*

Nhân

/

Chia

%

Lấy phần dƣ

 Toán tử một ngôi: Toán tử - đứng trƣớc một toán hạng, chỉ giá trị trái dấu với toán
hạng, chẳng hạn -5.

14


1.7.2 Toán tử quan hệ
Toán tử

Ý nghĩa


>

Lớn hơn

>=

Lớn hơn
bằng

<

Bé hơn

<=

Bé hơn hay bằng

==

Bằng nhau

!=

Khác nhau

hay

Chú ý:
 Kết quả của toán tử quan hệ luôn luôn là một số nguyên: 1 nếu đúng và 0 nếu sai.
 Các toán tử >, >=, <, <= là cùng thứ tự ƣu tiên, hai toán tử = =, != cùng thứ tự ƣu tiên

nhƣng thấp hơn thứ tự ƣu tiên của bốn toán tử đầu.
1.7.3 Toán tử logic
Toán tử
!
&&
||

Ý nghĩa
Phủ định
Phép giao
Phép hoặc

Kết quả của toán tử logic trả về một trong hai giá trị: 1 nếu đúng và 0 nếu sai. Ý nghĩa
của các toán tử đƣợc cho bởi các bảng sau:
a

!a

A

b

a && b

a || b

bằng 0

1


khác 0

Khác 0

1

1

khác 0

0

khác 0

Bằng 0

0

1

bằng 0

Khác 0

0

1

bằng 0


Bằng 0

0

0

1.7.4 Toán tử xử lý bit

C cung cấp các toán tử xử lý bit nhƣ sau:
Toán tử

Ý nghĩa

~

Lấy phần bù theo bit

&

Phép hội theo bit

|

Phép tuyển theo bit

^

Phép tuyển loại theo
bit


<<

Dịch trái

>>

Dịch phải

Các toán tử này chỉ thực hiện trên các toán hạng có kiểu dữ liệu là số nguyên nhƣ:
char, int, long (kể cả signed hoặc unsigned).
15


Bảng sau đây cho kết quả của các toán tử:
a

b

~a

a&b

a|b

a^b

0

0


1

0

0

0

0

1

1

0

1

1

1

0

0

0

1


1

1

1

0

1

1

0

1.7.5 Toán tử gán
C có hai kiểu gán giá trị nhƣ sau:
1. Toán tử gán =
Cú pháp: biến = biểu thức;
Dùng để gán giá trị của biểu thức ở vế phải toán tử = cho biến ở vế trái. Vế trái bắt
buộc là một biến, chẳng hạn: a = b; sẽ gán giá trị của biến a bằng giá trị đang chứa trong
biến b. Chú ý rằng ta chỉ gán giá trị của biến b cho biến a và sự thay đổi của biến b sau đó
sẽ không ảnh hƣởng đến giá trị của biến a.
Trong C++ cho phép vế phải toán tử = có thể chứa các phép gán khác. Ví dụ:
a = 2 + (b = 5);
tƣơng đƣơng với:
b = 5;
a = 2 + b;
Biểu thức sau cũng hợp lệ trong C++:
a = b = c = 5;
sẽ gán giá trị 5 cho cả ba biến a, b và c.

Chú ý: Đối với toán tử gán = thì giá trị của toán hạng bên phải đƣợc gán nguyên vẹn cho
biến bên trái nếu chúng cùng kiểu. Nếu chúng khác kiểu thì C sẽ thực hiện việc chuyển kiểu
tự động (xem 1.7).
2. Các toán tử gán phức hợp: +=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=
Các toán tử gán phức hợp cho phép chỉnh sửa giá trị của một biến, ví dụ:
Ví dụ:
a += b;
tƣơng đƣơng a = a + b;
a -= b;
tƣơng đƣơng a = a - b;
a *= b;
tƣơng đƣơng a = a * b;
a /= b;
tƣơng đƣơng a = a / b;
a %= b;
tƣơng đƣơng a = a % b;
và tƣơng tự cho các toán tử khác.
1.7.6 Toán tử tăng giảm
Trong ngôn ngữ C có hai toán tử một ngôi dùng để tăng giảm giá trị của các biến
(nguyên, thực và con trỏ) gọi là toán tử tăng (+ +) và toán tử giảm (--).
Các toán tử ++ hay -- có thể đặt trƣớc hay sau biến và có tác dụng tăng hoặc giảm biến
đó một đơn vị.
- Nếu đặt trƣớc (++n hay --n) thì giá trị của n sẽ đƣợc tăng (hoặc giảm) trƣớc khi
tham gia vào biểu thức.

16


- Nếu đặt sau (n++ hay n--) thì giá trị của n sẽ đƣợc tăng (hoặc giảm) sau khi tham
gia vào biểu thức.

Ví dụ 1: Nếu n = 5 thì câu lệnh: x = ++n; sẽ cho ra giá trị của x là x = 6 còn x = n++; sẽ
cho ra giá trị của x là x = 5. Sau khi thực hiện hai câu lệnh này thì n đều có giá trị là 6.
n  n  1;
 j  n;

Ví dụ 2: Câu lệnh j = ++n; tƣơng đƣơng 
Câu lệnh j = n++;

 j  n;
n  n  1;

tƣơng đƣơng 

Chú ý: Để tránh lỗi phát sinh do việc sử dụng các toán tử tăng/giảm không hợp lý ta không
nên sử dụng các toán tử tăng/giảm cho các biến có mặt nhiều lần trong cùng một biểu thức.
Ví dụ: Không nên viết: k = a++ * ++a;
1.7.7 Toán tử dấu phẩy (,)
Toán tử dấu phẩy có thể dùng để phân cách dãy các biểu thức và tạo thành một biểu
thức phẩy. Ví dụ:
a = 1, b = 2, c = a+b
là một biểu thức phẩy. Việc tính toán trên biểu thức phẩy đƣợc thực hiện từ trái sang phải.
Kết quả của biểu thức phẩy là giá trị của biểu thức cuối cùng của biểu thức phẩy, kiểu dữ
liệu của biểu thức cuối cùng này là kiểu dữ liệu của biểu thức phẩy.
Ví dụ: Câu lệnh
a = (b = 2, b*5+4);
cho kết quả là b = 2 và a = 14.
Chú ý: Biểu thức phẩy thƣờng đƣợc dùng trong vòng lặp for.
1.7.8 Toán tử điều kiện 3 ngôi ?:
Cú pháp: biểu thức 1 ? biểu thức 2: biểu thức 3
Tác dụng: Nếu biểu thức 1 có giá trị khác 0 (đúng) thì kết quả của toán tử là giá trị của

biểu thức 2, ngƣợc lại kết quả của toán tử là giá trị của biểu thức 3.
Kiểu của toán tử ?: là kiểu lớn nhất trong các kiểu của
biểu thức 2 và biểu thức 3.
Toán tử này thực chất là cách viết tắt của cấu trúc if ... else mà ta sẽ xét trong chƣơng
tiếp theo. Câu lệnh:
z = (biểu thức 1 ? biểu thức 2: biểu thức 3);
có thể viết lại:
if(biểu thức 1)
z = biểu thức 2;
else
z = biểu thức 3;
Ví dụ: Câu lệnh z = ((x < y) ? x: y); sẽ gán giá trị nhỏ nhất của x và y cho biến z.

1.8 CHUYỂN ĐỔI KIỂU
Trong một biểu thức các toán hạng có thể có các kiểu dữ liệu khác nhau. Vì vậy để
việc tính toán đƣợc chính xác đôi lúc chúng ta cần phải chuyển đổi kiểu dữ liệu cho phù
hợp. C có hai cách chuyển đổi kiểu dữ liệu:
1. Chuyển kiểu tự động: Thực hiện theo quy tắc sau:
17


 Khi hai toán hạng tham gia vào một toán tử có kiểu khác nhau thì kiểu của toán hạng
có độ ƣu tiên thấp hơn sẽ tự động chuyển thành kiểu lớn hơn của toán hạng kia trƣớc
khi thực hiện toán tử. Chiều cấp bậc tăng dần đƣợc xếp nhƣ sau:
int  long  float  double  long double
 Đối với lệnh gán thì sự chuyển kiểu căn cứ vào kiểu dữ liệu của biến ở vế trái.
Ví dụ: 1.2*(10/3) cho kết quả là 3.6
Giả sử n là biến nguyên thì sau lệnh gán n = 2.5; sẽ cho kết quả là n = 2.
2. Chuyển kiểu bắt buộc:
Thực hiện theo cú pháp sau : (Kiểu dữ liệu) Biểu thức

Kiểu của biểu thức sẽ đƣợc chuyển thành kiểu dữ liệu đƣợc cho ở Kiểu dữ liệu.
Ví dụ:
int i; float f = 3.14;
i = (int) f;
Đoạn mã trên chuyển số thập phân 3.14 sang một số nguyên 3.
Chú ý:
 Trong C++ việc chuyển kiểu bắt buộc có thể viết theo cú pháp:
Kiểu dữ liệu (Biểu thức)
 Đối với các hàm toán học của thƣ viện chuẩn thì giá trị của tham số và giá trị của
hàm đều có kiểu double, vì vậy để tính toán đƣợc chính xác ta cần phải chuyển đổi
kiểu cho tham số.
Ví dụ: Để tính căn bậc hai của một biến nguyên n, ta nên viết:
sqrt((double)n);
 Phép chuyển đổi kiểu có cùng độ ƣu tiên nhƣ các toán tử một ngôi.

1.9 ĐỘ ƢU TIÊN CỦA CÁC TOÁN TỬ
Bảng sau đây liệt kê độ ƣu tiên của tất cả các toán tử:
Độ ƣu tiên

Toán tử

Ƣu tiên nhóm
Trái

() [ ] -> . sizeof
++ -~
!

Phải


&*
(type)
+*/%

Trái

+-

Trái

<< >>

Trái

< <= > >=

Trái

== !=

Trái

&^|

Trái
18


&& ||


Trái

?:

Phải

= += -= *= /= %=
>>= <<= &= ^= |=

Phải

,

Trái

Ƣu tiên nhóm định nghĩa trong trƣờng hợp có một vài toán tử có cùng thứ tự ƣu tiên thì
toán tử nào sẽ đƣợc thực hiện trƣớc: toán tử ở phía xa nhất bên phải hay là xa nhất bên trái.
Nếu bạn muốn viết một biểu thức phức tạp mà lại không chắc lắm về thứ tự ƣu tiên của các
toán tử thì nên sử dụng các ngoặc đơn.

1.10 CÂU LỆNH
Trong C, các câu lệnh cách nhau bằng dấu chấm phẩy. Câu lệnh đƣợc chia thành 2
loại: lệnh đơn và khối lệnh.
Lệnh đơn là những lệnh không chứa lệnh khác, chẳng hạn phép gán là một lệnh đơn.
Khối lệnh là những lệnh đặt trong hai dấu móc nhọn { }.
1.11 LỆNH TIỀN XỬ LÝ #include
Lệnh tiền xử lý #include báo cho trình biên dịch đọc các dòng mã từ một tập tin văn
bản khác ngay khi tập tin hiện thời đang biên dịch. Lệnh #include có hai dạng:
Dạng 1:
#include <tên_tập tin>

Dạng 2:
#include “tên tập tin”
Các tập tin sau #include gọi là các tập tin dẫn hƣớng (header file), phần mở rộng của
các tập tin này là h. Mục đích dùng lệnh #include là để C biết các hàm sử dụng trong
chƣơng trình thuộc vào nhóm nào. Chẳng hạn các hàm printf và scanf thuộc vào nhóm
đƣợc dẫn bởi tập tin có tên là stdio.h
Cần phân biệt giữa hai dạng trên của #include. Với dạng 1, C hiểu đó là các tập tin thƣ
viện của C và nó sẽ tìm trong thƣ viện riêng của C. Với dạng 2, C hiểu đó là tập tin thƣ viện
của ngƣời sử dụng, C sẽ tìm chúng trong thƣ mục chứa tập tin nguồn, nếu không có thì mới
tìm trong thƣ mục riêng của nó.

19


Chƣơng 2

XUẤT NHẬP DỮ LIỆU
VÀ CÁC CÂU LỆNH CÓ CẤU TRÚC

2.1 XUẤT NHẬP DỮ LIỆU
2.1.1 Xuất dữ liệu với hàm printf
Để xuất dữ liệu ra màn hình ta dùng hàm printf sau đây:
int printf(<khung chỉnh dạng>,[<danh sách tham số>]);
trong đó:
 <danh sách tham số> có thể là hằng, biến, biểu thức, hàm, phần tử mảng mà giá trị
của nó cần hiển thị lên màn hình. Các tham số đƣợc ngăn cách nhau bởi dấu phẩy.
 <khung chỉnh dạng> đƣợc đặt trong hai dấu nháy kép, bao gồm ba loại thông tin sau:
- Những ký tự bình thƣờng ghi thế nào sẽ đƣợc hiện lên màn hình thế ấy.
- Các ký tự điều khiển: sẽ cho thi hành chức năng của nó.
- Các mã định dạng dùng để xác định số các tham số và cách biểu thị các tham số này

lên màn hình. Mỗi mã định dạng phải bắt đầu bởi ký tự %. Số mã định dạng bằng số
tham số.
Dạng tổng quát của mã định dạng nhƣ sau:
%[flags][width][.prec]<mã định dạng>
Giải thích:
 flags:
- Nếu flags không có: dữ liệu đƣợc in ra canh phải.
- Nếu flags là : dữ liệu đƣợc in ra canh trái.
- Nếu flags là +
: dữ liệu đƣợc in ra có dấu âm hoặc dƣơng.
- Nếu flags là khoảng trống: dữ liệu đƣợc in ra có dấu âm, nếu là dƣơng thì dấu +
đƣợc thay bằng khoảng trắng.
 width: chỉ độ rộng tối thiểu để hiển thị dữ liệu.
Với width là n: nếu số chữ số của dữ liệu bé hơn n thì các khoảng thừa đƣợc lắp đầy bởi các
khoảng trống,
Với width là 0n: tƣơng tự nhƣ trên nhƣng thay vì khoảng trống bây giờ là số 0
 prec: số con số có ý nghĩa sau dấu chấm thập phân.
 <mã định dạng> đƣợc liệt kê bởi bảng sau:

d
u
ld
lu
f
e hoặc E
g hoặc G
c
s
p


Tham số
số nguyên
số nguyên
số nguyên
số nguyên
số thực
số thực
số thực
ký tự
chuỗi ký tự
con trỏ

Dạng xuất
số nguyên int
số nguyên không dấu
long
unsigned long
số thực float, double (dấu chấm tĩnh)
số thực float, double (biểu diễn khoa học) (e)
biểu diễn khoa học hoặc thập phân tuỳ theo dạng nào ngắn nhất
char
chuỗi ký tự
địa chỉ
20


Hàm printf trả về số ký tự đã hiển thị ra màn hình. Nếu gặp lỗi hàm sẽ trả về -1 (EOF).
Ví dụ: Với các lệnh:
printf("Turbo C \n");
printf("là một ngôn ngữ lập trình cấp cao");

thì màn hình xuất hiện dòng:
Turbo C
là một ngôn ngữ lập trình bậc cao
Hai câu lệnh trên có thể viết lại nhƣ sau:
printf("Turbo C \nlà một ngôn ngữ lập trình bậc cao");
Ví dụ: Giả sử ta khai báo:
int
a =10, b=20 ;
thì lệnh:
printf("Tổng của %d và %d là %d ",a,b,a+b);
sẽ hiển thị ra màn hình nhƣ sau:
Tổng của 10 và 20 là 30
2.1.2 Nhập dữ liệu với hàm scanf
Để nhập dữ liệu từ bàn phím ta dùng hàm scanf sau đây:
int scanf(<Khung chỉnh dạng>,<danh sách tham số>);
trong đó:
 <khung chỉnh dạng> đƣợc đặt trong hai dấu nháy kép và gồm các mã định dạng nhƣ
hàm printf.
Dạng tổng quát của khung chỉnh dạng dạng:
%[width]<mã định dạng>
 <danh sách tham số> là một dãy địa chỉ các biến tƣơng ứng với mã định dạng và chúng
ngăn cách nhau bởi dấu phẩy. Có bao nhiêu tham số thì có bấy nhiêu mã định dạng. Ta
dùng toán tử & để lấy địa chỉ của một biến, chẳng hạn với x là một biến thì &x là địa chỉ
của biến x.
Ví dụ: Nhập dữ liệu cho hai biến x và y.
int x; float y;
scanf("%d%f",&x,&y);
Chú ý: Khi sử dụng các hàm printf và scanf cần khai báo câu lệnh tiền xử lý #include
<stdio.h> ở đầu chƣơng trình.
2.1.3 Nhập chuỗi với hàm gets

Cú pháp: char *gets(char *s);
trong đó tham số s là con trỏ (kiểu char) trỏ đến vùng nhớ chứa chuỗi ký tự nhận đƣợc.
Hàm gets nhận một chuỗi ký tự từ thiết bị vào chuẩn là bàn phím cho đến khi gặp „\n‟
(nhấn ENTER). Ký tự „\n‟ không đƣợc đặt vào chuỗi, thay vào đó là ký tự kết thúc „\0‟ và
đặt vào vùng nhớ do s trỏ đến. Hàm trả về địa chỉ chuỗi nhận đƣợc.
Ví dụ 1: Chƣơng trình sau đây thực hiện việc nhập một chuỗi ký tự từ bàn phím vào biến
hoten và hiển thị ra màn hình chuỗi ký tự đó.
#include <stdio.h>
void main()
21


{
char hoten[30];
printf(“\nHọ và tên: ”);
gets(hoten);
printf("\nHọ và tên là %s ", hoten);
}
Chú ý: Nếu sử dụng hàm scanf để nhập chuỗi ký tự thì chuỗi ký tự gõ vào không nên có
khoảng trống (?)
2.1.4 Xuất chuỗi ra màn hình với hàm puts
Cú pháp:
int puts(const char *s) ;
Hàm puts hiển thị chuỗi ký tự s ra màn hình. Ký tự xuống dòng đƣợc thêm vào cuối chuỗi.
Hàm trả về một giá trị không âm nếu việc hiển thị chuỗi thành công, ngƣợc lại hàm trả về
EOF.
Ví dụ 2: Sau khi thực hiện chƣơng trình:
#include <stdio.h>
void main()
{

char st[50];
gets(st);
//giả sử nhập vào dòng TURBO C
puts(st);
// hiển thị chuỗi st ra màn hình
scanf("%s",st);
// nhập vào dòng TURBO C
puts(st);
canf("%s",st);
/* không dừng lại để nhập */
puts(st);
}
Kết quả đƣợc cho trên màn hình là:
TURBO C
TURBO C
TURBO C
TURBO
C
2.1.5 Nhập ký tự với hàm getchar và getch
1. Cú pháp hàm getchar nhƣ sau:
int getchar(void);
Hàm getchar nhận một ký tự từ bàn phím và trả về màn hình ký tự nhận đƣợc.
Ví dụ: Chƣơng trình sau đây thực hiện việc nhập một ký tự từ bàn phím vào biến ch và hiển
thị ra màn hình ký tự đó.
#include <stdio.h>
void main()
{
char
ch;
printf("\nNhập một ký tự: ");ch = getchar();

printf("\nKý tự đó là %c : ", ch);
22


}
Chú ý:
 Khi sử dụng hàm gets, puts, getchar, ta phải khai báo lệnh tiền xử lý #include <stdio.h>
ở đầu chƣơng trình.
 Để tránh làm việc sai sót với gets và getchar ta nên làm sạch bộ đệm bàn phím bằng
cách dùng hàm fflush nhƣ sau:
fflush(stdin);
Ví dụ: Đoạn chƣơng trình sau đây có sử dụng hàm fflush để xoá bộ đệm trƣớc khi nhập vào
chuỗi ký tự.
#include <stdio.h>
void main()
{
char ht[30];
int tuoi;
printf("\nNhập tuổi: ");
scanf("%d”,&tuoi);
printf("\nNhập họ tên: ");
fflush(stdin);
gets(ht);
}
2. Cú pháp hàm getch nhƣ sau:
int getch(void);
Hàm getch hoạt động hoàn toàn giống nhƣ getchar chỉ khác ở hai điểm: thứ nhất, ký tự sẽ
đƣợc nhận ngay không chờ nhấn ENTER. Thứ hai, ký tự nhập vào sẽ không đƣợc in ra màn
hình. Khi sử dụng hàm getch, ta phải khai báo lệnh tiền xử lý #include <conio.h> ở đầu
chƣơng trình.

2.1.6 Một số ví dụ
Ví dụ 1: Nhập vào từ bàn phím một số nguyên hệ 10 và chuyển thành số hệ 8 và số hệ 16
#include <stdio.h>
#include <conio.h>
void main()
{
int i;
clrscr();
printf("\nNhập số nguyên hệ 10 ");
scanf("%d",&i);
printf("\n Chuyển sang hệ 8 là %o",i);
printf("\n Chuyển sang hệ 16 là %X",i);
getch();
}
Ví dụ 2: Tìm số lớn nhất và nhỏ nhất của 3 số thực đƣợc nhập vào từ bàn phím.
#include <stdio.h>
#include <conio.h>
23


void main()
{
float x,y,z,max,min;
clrscr();
printf("\nNhập vào 3 số: ");
scanf("%f%f%f",&x,&y,&z);
max=(x>y)?x:y;
max=(max>z)?max:z;
min=(x>y)?y:x;
min=(min>z)?z:min;

printf("\nSố lớn nhất là %f",max);
printf("\nSố nhỏ nhất là %f",min);
printf("\nĐây là 5 tiếng chuông!\a\a\a\a\a");
getch();
}
Ví dụ 3: Nhập vào một số nguyên không âm, dịch trái n bit, in kết quả lên màn hình theo hệ
10, 16, 8.
#include <stdio.h>
#include <conio.h>
void main()
{ unsigned int i,j,n;
clrscr();
printf("\nNhập vào một số nguyên: ");
scanf("%d",&i);
printf("\nCần dịch trái mấy bit: ");
scanf("%d",&n);
j = i << n;
printf("\nSố %d dịch trái %d bit có giá trị ở hệ 10 là %d",i,n,j);
printf("\nSố %d dịch trái %d bit có giá trị ở hệ 16 là %x",i,n,j);
printf("\nSố %d dịch trái %d bit có giá trị ở hệ

8 là %o",i,n,j);

getch();
}

2.1.7 Xuất nhập dữ liệu trong C++
Để xuất dữ liệu ra màn hình và nhập dữ liệu từ bàn phím, trong C++ vẫn có thể dùng
hàm printf và scanf, ngoài ra trong C++ ta có thể dùng dòng xuất/nhập chuẩn để xuất/nhập
dữ liệu thông qua hai biến đối tƣợng là cout và cin.

2.1.6.1 Xuất dữ liệu
Cú pháp:
cout << biểu thức 1<<. . .<< biểu thức N;
Trong đó cout đƣợc định nghĩa trƣớc nhƣ một đối tƣợng biểu diễn cho thiết bị xuất chuẩn
của C++ là màn hình, cout đƣợc sử dụng kết hợp với toán tử chèn << để hiển thị giá trị các
biểu thức 1, 2,..., N ra màn hình.
Ví dụ:
cout<<5<<7;
//57
int a=10, b=20;
24


cout<<"\na= "<Không đƣợc viết:
cout<2.1.6.2 Nhập dữ liệu
Cú pháp:
cin >>biến 1>>. . . >>biến N;
Trong đó cin đƣợc định nghĩa trƣớc nhƣ một đối tƣợng biểu diễn cho thiết bị vào chuẩn của
C++ là bàn phím, cin đƣợc sử dụng kết hợp với toán tử trích >> để nhập dữ liệu từ bàn phím
cho các biến 1, 2, ..., N.
Ví dụ:
int a; float b;
cout<<"\na = "; cin >> a;
cout<<"\nb = "; cin >> b;
Không đƣợc viết: cin >>a, b;
Chú ý:
 Toán tử nhập cin>> sẽ để lại ký tự chuyển dòng ‟\n‟ trong bộ đệm bàn phím. Ta có thể
dùng phƣơng thức cin.ignore(1) để bỏ qua ký tự chuyển dòng.

 Để sử dụng cout, cin và phƣơng thức nói trên cần khai báo tập tin iostream.h:
#include <iostream.h>
2.1.6.3 Định dạng khi in ra màn hình
 Để quy định số thực đƣợc hiển thị ra màn hình với k chữ số sau dấu chấm thập phân, ta
sử dụng đồng thời các hàm sau:
setiosflags(ios::showpoint);
// Bật cờ hiệu
setprecision(k);
Các hàm này cần đặt trong toán tử xuất cout nhƣ sau:
cout<Câu lệnh trên sẽ có hiệu lực đối với tất cả các toán tử xuất tiếp theo cho đến khi gặp
một câu lệnh định dạng mới.
Ví dụ: int a=10, b=3;
cout<cout<//3.333
 Để quy định độ rộng tối thiểu để hiển thị là k vị trí cho giá trị (nguyên, thực, chuỗi) ta
dùng hàm setw(k)
Hàm này cần đặt trong toán tử xuất và nó chỉ có hiệu lực cho một giá trị đƣợc hiển thị
gần nhất. Các giá trị hiển thị tiếp theo sẽ có độ rộng tối thiểu mặc định là 0, nhƣ vậy câu
lệnh:
cout<sẽ in ra chuỗi “ KhoaCNTT”.
để dùng hàm setw(k) cần khai báo tập tin thƣ viện iomanip.h:
#include
<iomanip.h>

2.2.CÁC CÂU LỆNH CÓ CẤU TRÚC
Mọi biểu thức của C đều có một giá trị nào đó. Tuy nhiên trong các câu lệnh có cấu
trúc của C, giá trị cụ thể của biểu thức đƣợc dùng để xét điều kiện thƣờng không đƣợc quan

tâm mà chỉ cần xác định biểu thức đó có giá trị bằng 0 hay khác 0. Nếu biểu thức trong các

25


lệnh có cấu trúc có giá trị khác 0 thì có nghĩa là điều kiện kiểm tra đƣợc đánh giá đúng.
Trong trƣờng hợp ngƣợc lại - điều kiện là sai thì biểu thức có giá trị bằng 0.
2.2.1 Cấu trúc điều khiển if, switch
2.2.1.1 Cấu trúc if
1. Dạng 1:
Cú pháp:
if(<biểu thức>)
<Câu lệnh 1>
[ else
<Câu lệnh 2> ]
Các câu lệnh sau if hoặc else có thể là lệnh đơn hoặc khối lệnh. Nếu các câu lệnh if
lồng nhau thì else sẽ đi với if gần nhất.
Câu lệnh if - else ở dạng 1 thực hiện theo trình tự sau:
- Tính giá trị của biểu thức sau if,
- Nếu <biểu thức> có giá trị khác 0 thì thực hiện <câu lệnh 1>, nếu bằng 0 thì thực
hiện <câu lệnh 2> (nếu có).
- Chuyển điều khiển chƣơng trình đến câu lệnh viết ngay sau cấu trúc if-else.
Chú ý: Biểu thức điều kiện của if, cũng nhƣ trong các cấu trúc sau này, đều phải đặt trong
cặp dấu ngoặc đơn ().
Ví dụ: Chƣơng trình sau đây nhập vào một ký tự và xem xét ký tự đó có phải là một chữ cái
không?
#include <stdio.h>
#include <ctype.h>
/* để dùng hàm isalpha() */
void main()

{
char ch;
printf("Nhập một ký tự: ");
scanf("%c", &ch);
if(isalpha(ch))
printf("%c", ch);
else
printf("%c không phải là chữ cái\n",ch);
}
2. Dạng 2:
Cú pháp:
if(<biểu thức 1>)
<Câu lệnh 1>
else if(<biểu thức 2>)
<Câu lệnh 2>
. . .
else if(<biểu thức n-1>)
<Câu lệnh n-1>
else
26


<Câu lệnh n>
Dạng này của lệnh if thƣờng dùng khi muốn lựa chọn để thực hiện một trong nhiều
điều kiện.
Trong cấu trúc này, việc xét các điều kiện đƣợc thực hiện tuần tự từ trên xuống. Nếu
<biểu thức i> là biểu thức đầu tiên khác 0 (i = 1,...,n-1) thì
<Câu lệnh i> đƣợc thực hiện, còn nếu cả n -1 biểu thức đều có giá trị bằng 0 thì n> sẽ đƣợc thực hiện.
Ví dụ: Chƣơng trình sau đây thực hiện việc giải phƣơng trình bậc hai:

ax2 + bx + c = 0
(a  0)
#include <stdio.h>
#include <math.h>
# include <conio.h>
void main()
{ float a,b,c,delta,x1,x2;
printf("\nNhập các hệ số a,b,c:

(a khác 0) ");

scanf("%f%f%f",&a,&b,&c);
delta = b*b - 4*a*c;
if(delta < 0)
printf("\nPhương trình vô nghiệm");
else

if(delta == 0)

printf("\nPhương trình có nghiệm kép %.2f", -b/(2*a));
else
{x1 = (-b - sqrt(delta))/(2*a);
x2 = (-b + sqrt(delta))/(2*a);
printf("\nP. trình có 2 nghiệm phân biệt %8.2f %8.2f",x1,x2);
}
getch();
}

2.2.1.2 Cấu trúc switch
Cú pháp:

switch (<biểu thức>) {
case <giá trị 1>: [ câu lệnh 1 ];[break];
case <giá trị 2>: [ câu lệnh 2 ];[break];
.
.
case <giá trị n>: [ câu lệnh n ];[break];
[default: [ câu lệnh n+1 ]]
}
trong đó <biểu thức> phải có kết quả là một trị nguyên, <giá trị 1>, ...,
<giá trị n> phải khác nhau và thuộc kiểu nguyên.
Từ khoá default để chỉ các giá trị không liệt kê ra trong câu lệnh switch, và default là thành
phần không bắt buộc.
Sự hoạt động của cấu trúc switch đƣợc mô tả nhƣ sau:
27


- Tính giá trị của <biểu thức>,
- Nếu <biểu thức> có giá trị bằng với một <giá trị k> nào đó (k{1,2,...,n}) thì C sẽ
chuyển điều khiển đến case <giá trị k> và thực hiện từ <câu lệnh k> ở đó cho đến khi gặp
câu lệnh break thì thoát khỏi switch hoặc đã đến cuối cấu trúc và thực hiện câu lệnh viết
ngay sau thân switch.
- Nếu giá trị của <biểu thức> không có trong các giá trị đƣợc liệt kê sau case thì câu lệnh
sau default (nếu có) sẽ đƣợc thực hiện hoặc thoát ra khỏi câu lệnh switch (trƣờng hợp
không có default).
Ví dụ:
#include <stdio.h>
void main()
{
int x;
printf("Nhập số nguyên: ");

scanf("%d",&x);
switch (x){
case 0: printf("\n Số 0");break
case 1: printf("\n Số 1");break
case 2: printf("\n Số 2");break
case 3: printf("\n Số 3"); break;
default: printf("\nCác số khác 0,1,2,3");
}
}
2.2.2 Các cấu trúc lặp while, do...while, for
2.2.2.1 Cấu trúc while
Cú pháp:
while(<biểu thức>)
<câu lệnh>
Cấu trúc while thực hiện qua các bƣớc sau:
- Tính giá trị của <biểu thức>
- Nếu giá trị của <biểu thức> khác 0 thì <câu lệnh> sẽ đƣợc thực hiện, sau đó chƣơng
trình sẽ quay trở lại đầu vòng lặp và quá trình này sẽ lặp cho đến khi <biểu thức> có giá trị
bằng 0 thì thoát ra khỏi vòng lặp, chuyển tới câu lệnh sau thân while.
Chú ý: Đối với cấu trúc while thì <câu lệnh> có thể không đƣợc thực hiện lần nào. Đặc
trƣng của while là kiểm tra điều kiện ngay khi vừa vào cấu trúc, hay còn gọi là cấu trúc
kiểm tra điều kiện trước.
Ví dụ 1: Chƣơng trình sau dùng trúc while tạo vòng lặp để in các giá trị dãy số 9, 8 ... 2, 1.
Chƣơng trình có sử dụng câu lệnh break để thoát vòng lặp.
# include <stdio.h>
# include <conio.h>
void main()
{ int i=10;
while(1)
28



{ if(--i==0) break;
/*gặp câu lệnh này thì thoát*/
printf("%d ",i); /*9 8 7 6 5 4 3 2 1*/
}
getch();
}
Ví dụ 2: Chƣơng trình sau cho phép nhập vào một chuỗi các ký tự, quá trình nhập sẽ dừng
khi nhấn Enter. Màn hình sẽ hiển thị số ký tự trắng trong chuỗi vừa nhập.
#include <stdio.h>
# include <conio.h>
void main()
{
int ch, ky_tu_trang = 0;
printf("Nhập một chuỗi ký tự:\n");
ch = getchar();
while(ch != '\n')
//while(ch!=13)
{ if(ch == ' ')
ky_tu_trang++;
ch = getchar() ;
}
printf("Số ký tự trắng: %d\n",ky_tu_trang);
getch();
}
Ví dụ 3: Chƣơng trình sau đếm số ký tự của một chuỗi nhập vào từ bàn phím. Chuỗi đƣợc
kết thúc bởi Ctrl – Z (hoặc phím F6).
#include <stdio.h>
# include <conio.h>

void main()
{ long nc;
nc = 0;
while(getchar() != EOF) ++nc;
printf("%ld\n", nc);
getch();
}
Ví dụ 4: Chƣơng trình sau đây dùng để đếm số dòng, số từ và số ký tự của các dòng văn
bản nhập vào từ bàn phím. Quá trình nhập kết thúc khi bấm Ctrl-Z và Enter. Giả sử từ là dãy
ký tự không chứa khoảng trống, ký tự xuống dòng „n‟ và dấu tab.
#include <stdio.h>
#include <conio.h>
#define IN
1
#define OUT 0
void main()
{int c, nl, nw, nc, state;
state = OUT;
29


nl = nw = nc = 0;
while((c = getchar()) != EOF) {
++nc;
if(c == '\n')++nl;
if(c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if(state == OUT){state = IN;
++nw;
}

}
printf("%d %d %d\n", nl, nw, nc);
}
2.2.2.2 Cấu trúc do ... while
Cú pháp:
do
<câu lệnh>
while(<biểu thức>);
Cấu trúc do ... while về bản chất và cách thực hiện thì hoàn toàn giống nhƣ cấu trúc
while, nhƣng chỉ khác ở mỗi một điểm: cấu trúc này thực hiện <câu lệnh> rồi mới kiểm tra
giá trị của <biểu thức>, do đó <câu lệnh> đƣợc thực hiện ít nhất là một lần. Điều kiện thoát
của câu lệnh này là <biểu thức> có giá trị 0. Ta gọi cấu trúc này là cấu trúc kiểm tra điều
kiện sau.
Ví dụ 1: Ta viết lại chƣơng trình ở ví dụ 2 ở trên, dùng cấu trúc do ... while
#include <stdio.h>
#include <conio.h>
void main()
{
int ch, ky_tu_trang =0;
clrscr();
printf("Nhập một chuỗi ký tự:\n");
do{ ch = getchar();
if(ch == ' ')
ky_tu_trang ++;
} while(ch != '\n');
printf("Số ký tự trắng: %d\n", ky_tu_trang);
getch();
}
Ví dụ 2: Chƣơng trình sau tính tổng: S = 12 + 22 +...+ n2
với n nguyên dƣơng đƣợc nhập vào từ bàn phím.

# include <stdio.h>
# include <conio.h>
void main()
{long S = 0, int i=1, n;
30


clrscr();
printf("\n Nhập n: "); scanf("%d",&n);
do{
S += (i*i);
++i;
}while(i<=n);
printf("\nTong binh phuong la: %ld ",S);
getch();
}
2.2.2.3 Cấu trúc for
Cú pháp:
for(<biểu thức 1>; <biểu thức 2>; <biểu thức 3>)<câu lệnh>
Cấu trúc for thực hiện qua các bƣớc:
Bước 1: Tính giá trị của <biểu thức 1> (thƣờng là phép gán để khởi gán một hay nhiều
biến).
Bước 2: Tính giá trị của <biểu thức 2>.
Nếu giá trị của <biểu thức 2> khác 0 thì <câu lệnh> sẽ đƣợc thực hiện, sau đó tính giá
trị của <biểu thức 3> , quay trở lại bƣớc 2.
Nếu <biểu thức 2> có giá trị 0 thì chƣơng trình sẽ thoát khỏi cấu trúc for và thực hiện
lệnh ở sau cấu trúc for.
Chú ý:
- <biểu thức 1> chỉ đƣợc thực hiện một lần khi bắt đầu cấu trúc, ngƣợc lại 2> và <biểu thức 3> sẽ đƣợc thực hiện vào mỗi lần lặp.

- <biểu thức 1>, <biểu thức 2>, <biểu thức 3> có thể vắng mặt, tuy nhiên dấu chấm
phẩy bắt buộc phải đặt vào đúng vị trí của biểu thức đó. Nếu <biểu thức 2> vắng mặt thì
điều kiện kiểm tra bởi biểu thức này luôn luôn đƣợc đánh giá là đúng. Trong trƣờng hợp
này để thoát khỏi vòng lặp cần phải thực hiện lệnh thoát, chẳng hạn break.
- <biểu thức 1>, <biểu thức 2>, <biểu thức 3> có thể là các biểu thức phẩy.
Cấu trúc for đầy đủ có thể thay thế bằng:
<biểu thức 1>;
while(<biểu thức 2>)
{<câu lệnh>;
<biểu thức 3>;
}
Ví dụ 1: Tính tổng n số nguyên dƣơng đầu tiên: S = 1 + 2 + ... + n.
#include <stdio.h>
# include <conio.h>
void main()
{
int n, i; long S;
printf("Nhập n: ");
scanf("%d", &n);
S = 0;
for(i=1; i<=n; i++)S += i;
31


×