C_C++
Chia sẻ bởi Đức Bình |
Ngày 29/04/2019 |
92
Chia sẻ tài liệu: C_C++ thuộc Bài giảng khác
Nội dung tài liệu:
Object-Oriented Programming
1
Ngôn ngữ lập trình
Với C & C++
(Lập trình 1)
Giảng viên : Phạm Doãn Tĩnh
Bộ môn : Điện tử tin học
Khoa : Điện tử - Viễn Thông
Trường : Đại học Bách khoa- Hà nội
Tài liệu tham khảo
Ngôn ngữ lập trình C++ và cấu trúc dữ liệu -PGS.TS Nguyễn Việt Hương.
Kỹ thuật lập trình C - GS. Phạm Văn ất - NXB Thống kê
The C Programming Language - Ritchie kernighan- Prentice Hall Software series.
Practical C Programming, 3rd Edition - Steve Oualline - O`Reilly
The C++ Programming Language Special 3rd Edition- Bjarne Stroustrup - C++ Creator -Addison Wesley
C++ by Dissection - Ira Pohl (University of California Santa Cruz)- Addison Wesley.
Object-Oriented Programming
3
Chương 1
Các khái niệm cơ bản về lập trình
1.1 Phân tích bài toán
Với "phần cứng" và phần mềm trong tay rồi, người lập trình cần làm gì?
Học một ngôn ngữ lập trình.
Vấn đề cần giải quyết cần được xem xét kỹ lưỡng.
Phân tích bài toán là quá trình làm hoàn tất các mức chi tiết cần thiết khi giải quyết một vấn đề. Nó bao gồm các bước chính như sau:
Vấn đề cần giải quyết phải được hiểu một cách thấu đáo. Bởi nếu người giải quyết chưa hiểu vấn đề thì tất nhiên máy tính cũng không thể giải quyết tốt được
Cần phải chọn được một phương án giải quyết và phát triển phương án.
Tiến trình giải cần được mô tả dưới dạng từng bước từng bước một. Đôi khi chúng ta gọi là "Thuật giải" (Solution algorithm).
Thuật toán được lập trình và chương trình được chạy thử.
Cuối cùng thuật toán được kiểm định.
1.2 Giải thuật và các vấn đề liên quan
Giải thuật là gì?
"Giải thuật là một danh sách các chỉ dẫn mô tả một cách chính xác các bước của một quá trình mà đảm bảo là quá trình này sẽ phải kết thúc sau một số bước nhất định với câu trả lời đúng cho từng trường hợp cụ thể của một vấn đề cần giải quyết".
Mỗi thuật giải phải đảm bảo 4 đặc tính sau:
Sự chính xác.
Tính hiệu quả- Đưa ra câu trả lời đúng.
Đảm bảo sự kết thúc.
Tổng quát hoá.
Ví dụ: Giải thuật cho giải phương trình bậc nhất a.x+b=0
Bước 1: Xét a =0, nếu đúng tiếp tục bước 2, nếu sai tiếp tục bước 5.
Bước 2: Xét b=0, nếu đúng tiếp tục bước 3, nếu sai tiếp tục bước 4.
Bước 3: Hiển thị vô số nghiệm và kết thúc.
Bước 4: Hiển thị vô nghiệm và kết thúc.
Bước 5: Hiển thị nghiệm duy nhất x=-b/a và kết thúc.
1.3 Quá trình thiết kế.
1.3.1 Đặc tả chương trình.
Xuất phát điểm cho quá trình thiết kế bất kỳ một chương trình máy tính nào cũng đều phải có một đặc tả phù hợp về hoạt động của chương trình dự định thực hiện.
Thông thường đặc tả của chương trình bào gồm:
Mô tả chức năng của chương trình.
Các yêu cầu đầu vào và đầu ra.
Các biện pháp lưu trữ dữ liệu.
Các thủ tục quản lý tệp.
Mô tả các thuật toán xử lý đặc biệt được sử dụng.
Định dạng của đầu ra.
1.3 Quá trình thiết kế.
1.3.2 Các kiểu tệp (File types)
Tệp chứa các bản ghi một cách lặp đi lặp lại.
Tuỳ theo việc tổ chức các bản ghi trong tệp, người ta chia tệp thành 4 loại khác nhau:
Tệp nối tiếp (Serial file)
Các bản ghi được ghi nối tiếp nhau theo trình tự thời gian đưa bản ghi vào. Ví dụ các bản ghi ghi lại các phiên giao dịch.
Tệp tuần tự (sequential file)
ở đây các bản ghi được sắp xếp theo trình tự của một hoặc nhiều trường khoá.
Tệp này được tạo ra nhờ sắp xếp các tệp nối tiếp. VD: Danh sách sinh viên theo số hiệu sinh viên.
1.3 Quá trình thiết kế.
1.3.2 Các kiểu tệp (File types)
Tệp tuần tự được chỉ mục (Indexed sequential file)
Thay vì sắp xếp lại toàn bộ tệp, người ta tạo ra các tệp chỉ mục và trong các tệp này chứa các trường khoá đã sắp xếp đi kèm với địa chỉ các bản ghi trong tệp chính.
Tệp truy cập trực tiếp (Direct Access file)
Để có thể truy cập nhanh, mỗi bản ghi sẽ được ghi vào địa chỉ tạo ra nhờ áp dụng một công thức đối với trường khoá- không cần tệp chỉ mục nhung tốn không gian lưu trữ.
1.3 Quá trình thiết kế.
1.3.3 Bảng quyết định (Decision Table)
Bảng quyết định?
Bảng quyết định là một bảng chỉ ra các hành động khác nhau được thực hiện dựa theo các sự kết hợp khác nhau của các điều kiện.
1.3 Quá trình thiết kế.
1.3.3 Bảng quyết định (Decision Table)
Ví dụ: Giả sử một cửa hàng điện tử thực hiện việc giảm giá cho khách hàng dựa vào tiêu chí: Khách quen tiêu trên $200 giảm giá 20%, nếu không thì giảm giá 10%. Khách không quen thì tiêu trên $200 giảm giá 10%, nếu không thì không giảm giá.
Quy tắc tổ hợp: Các điều kiện giống nhau, trừ một hàng; và các hành động là giống nhau hoàn toàn thì ta có thể kết hợp chúng lại, thay điều kiện khác nhau bằng dấu "-".
1.3.4 Kiểm tra thiết kế (Design checking)
Sau khi thiết kế xong, chúng ta phải kiểm tra tính đúng đắn của thiết kế. Có rất nhiều phương pháp khác nhau để kiểm tra thiết kế.
1. Dry-run.
Phương pháp này, người kiểm tra dùng giấy bút để tính toán và ghi lại các bước thực hiện của chương trình dựa theo một số dữ liệu thử.
2. Walk through:
Đây là phương pháp mà người thiết kế mô tả thiết kế của mình cho các đồng nghiệp và ghi nhận lại tất cả các đóng góp ý kiến.
Với PP này, cho phép bộc lộ sớm các vấn đề, tương tác các thành viên trong nhóm, đào tạo lẫn nhau, tiến trình ổn định, tính nhất quán trong thiết kế.
Catalytic Checking.
Người thiết kế mô tả thiết kế, đồng nghiệp luôn hỏi "Tại sao?" "Làm thế nào?" và sẽ tự bộc lộ ra điểm sai trong thiết kế.
Independent Inspection
Đây là phương pháp dùng nhiều người độc lập kiểm tra thiết kế dưới sự chỉ đạo của một người có kinh nghiệm.
1.3.5 Thiết kế hướng đối tượng (Object-Oriented Design OOD)
Phương pháp thiết kế hướng đối tượng OOD là phương pháp thiết kế gồm có 4 bước chính sau đây:
1. Xác định các loại đối tượng (Các lớp - classes) xuất hiện trong giải pháp.
2. Xác định và mô tả các biến thể hiện trong mỗi loại đối tượng.
3. Xác định các hành động của mỗi một loại đối tượng.
4. Đối với mỗi hành động, mô tả chức năng của nó, các tham số, các điều kiện tiên quyết và các hậu điều kiện.
Ví dụ: Giả sử chúng ta cần xây dựng một CTrình tính điểm trung bình và lấy ra điểm trung bình cho các sinh viên. Mỗi sinh viên trong lớp được có các thông tin sau: tên SV, 3 điểm thi, điểm trung bình.
Bước 1: Xác định các loại đối tượng, ở đây có 2 loại đối tượng là Sinhvien và Lophoc.
Bước 2: Xác định các biến thể hiện của mỗi loại đối tượng:
Sinhvien: TenSV, Diem1, Diem2, Diem3, DiemTB
Lophoc: TenLop,SoSV, DSSV
1.3.5 Thiết kế hướng đối tượng (Object-Oriented Design OOD)
Bước 2: Xác định các biến thể hiện của mỗi loại đối tượng:
Sinhvien: TenSV, Diem1, Diem2, Diem3, DiemTB
Lophoc: TenLop,SoSV, DSSV
Bước 3:
Sinhvien:
Constructor
Destructor
GetName: Trả lại tên SV
SetName: Đổi tên SV
GetData: Nhập số liệu SV từ bàn phím
ComputeAverage: Tính điểm TB.
DisplayAverage: Hiển thị điểm TB.
Lophoc:
Constructor
Destructor
ThemSV: Thêm một sinh viên vào lớp học.
XoaSV: Xoá một SV khỏi lớp học.
1.4 Lịch sử phát triển của kỹ thuật lập trình
Lập trình có cấu trúc - Lập trình thủ tục (structural-procedural)
Lập trình hướng đối tượng
2 Mô hình lập trình
Structural (Procedural) Object-Oriented
PROGRAM PROGRAM
FUNCTION
FUNCTION
FUNCTION
Các đặc tính của ngôn ngữ lập trình hướng đối tượng
1. Data abstraction (Trừu tượng hoá dữ liệu)
2. Inheritance of properties (Sự kế thừa các thuộc tính)
3. Dynamic binding of operations to objects (Sự ràng buộc các thao tác với các đối tượng)
Được trình bày chi tiết ở phần sau
1.5 Thử nghiệm chương trình (testing)
Chạy thử là quá trình xác thực một chương trình tuân theo đúng những đặc tả mà nó cần thực hiện.
Testing gồm những bước sau:
Chọn bộ dữ liệu thử phù hợp.
Xác định kết quả đầu ra mong muốn.
Chạy chương trình
Phân tích kết quả đầu ra của chương trình.
Các phương pháp:
Unit testing: Thực hiện ở mức module
Integration testing (test tích hợp): diễn ra ở mức cao hơn
Bottom-up testing: Trong phương pháp này thì các module mức thấp được tích hợp và chạy thử trước, như vậy ta cần một driver để thực hiện.
Top-down testing: Các module mức cao được tích hợp và chạy thử trước, lúc đó ta cần các dummy module (module giả) ở mức thấp.
System testing: Đảm bảo rằng toàn bộ chương trình chạy đúng.
Acceptance testing: Kiểm tra nghiệm thu liên quan nhiều đến người sử dụng (họ coi hệ thống như hộp đen).
1.5 Thử nghiệm chương trình (testing)
Test data (Dữ liệu thử)
Dữ liệu thử là thành phần cốt lõi nhằm đảm bảo tính hiệu quả của việc chạy thử chương trình. Nó bao gồm 2 nhiệm vụ:
Chọn bộ dữ liệu thử đầu vào
Xác định kết quả mong đợi ở đầu ra.
Các loại dữ liệu thử:
Dữ liệu tự tạo: Tự tạo theo cách thủ công hoặc dùng bộ ngẫu nhiên
Dữ liệu sửa từ dữ liệu thật
Dữ liệu sống thực sự (Live data).
1.6 Gỡ rối chương trình (Debugging)
Gỡ lỗi và chạy thử luôn song hành cùng nhau, gỡ lỗi là quá trình phát hiện ra nguồn gốc việc gây lỗi trong chạy thử chương trình.
Các phương pháp gỡ lỗi:
Gỡ lỗi riêng lẻ: Người lập trình làm việc một mình để tìm ra lỗi.
Gỡ lỗi theo nhóm: Một nhóm người lập trình cùng tập trung trong rà soát mã nguồn để tìm ra nguyên nhân gây lỗi.
Gỡ lỗi tổng hợp: Chương trình giao cho nhiều người, kết quả sẽ được tập hợp lại.
Các công cụ gỡ lỗi:
In mã nguồn
Dựa vào đặc tả chi tiết của chương trình
Dựa vào flowchart
In kết quả đầu ra.
Dò theo từng câu lệnh và xem giá trị các biến
Tự động chỉ ra manh mối và loại lỗi.
1.7 Các giai đoạn trong chu trình sống của một hệ thống
Dự định ban đầu
Nghiên cứu tính khả thi
Phân tích yêu cầu của người sử dụng
Phân tích hệ thống
Đặc tả hệ thống
Thiết kế hệ thống
Phát triển hệ thống
Chạy thử
Triển khai
Bảo trì
Nhận xét đánh giá.
1.8 Lập trình hướng đối tượng (OOP) và C++
Tính trừu tượng (Abstraction)
Lọc ra các đặc tính chính trong khi loại bỏ những cái không cần thiết
Sự đóng gói (Encapsulation)
ẩn và bảo vệ các các dữ liệu quan trọng thông qua một giao diện có điều khiển
Tính modun hoá (Modularity)
Chia đối tượng thành các modun nhỏ hơn cho dễ hiểu và dễ thao tác.
Sự phân cấp (hierachy)
Sắp xếp tôn ti trật tự cho các đối tượng dựa trên mối quan hệ giữa chúng
1.8 Lập trình hướng đối tượng (OOP) và C++
Data abstraction:
Cho ta một định nghĩa về đối tượng
Ví dụ:
Người buôn xe ôtô nhìn xe với: Giá, thời hạn bảo hành, màu sắc,...
Người thợ máy thì nhìn xe với: Kích thước lọc dầu,loại bugi,...
Encapsulation:
Phân tích đối tượng thành các phần
Giấu đi hoặc bảo vệ các thông tin quan trọng
Cung cấp một giao diện cho phép truy cập vào các thuộc tính một cách an toàn.
Các thông tin nội bộ có thể bị thay đổi mà không làm ảnh hưởng đến các bộ phận khác.
Ví dụ - car radio
Giao diện gồm các núm điều khiển, antena, nguồn
Chi tiết hoạt động của nó người sử dụng không biết
Nhưng để lắp đặt và sử dụng cái đài thì hầu như ai cũng biết
1.8 Lập trình hướng đối tượng (OOP) và C++
Object-Oriented Programming
24
Chương 2
Hướng dẫn các bước lập trình với C++
Giảng viên : Phạm Doãn Tĩnh
Bộ môn : Điện tử tin học
Khoa : Điện tử - Viễn Thông
Trường : Đại học Bách khoa- Hà nội
2.1 Tạo lập và thực hiện một chương trình C++
Các công cụ có thể sử dụng trong khoá học này:
Turbo C++ 3.0 trở lên
Borland C++ 4.5 trở lên
Microsoft Visual C++ 98 (*)
Nên sử dụng Microsoft Visual C++ 98 vì nó chạy trên môi trường windows dễ sử dụng cũng như tính năng trong soạn thảo tốt và làm cơ sở để xây dựng các ứng dụng phức tạp (như lập trình mạng, kết nối CSDL,...).
-Khi tạo một Project mới:
+Chọn "Win32 console application"
+ Chọn "new" -> C++ source file
- Chạy chương trình nhấn ctrl+F5
Visual C++ IDE
// Program: Display greetings
// Author(s): Author name
// Date: 15-Aug-2004
#include
#include
using namespace std;
int main() {
cout << "Hello world!" << endl;
return 0;
}
A First Program - Greeting.cpp
Các chỉ dẫn
tiền xử lý
Insertion
statement
Kết thúc main() đồng thời kết thúc chương trình
Lời giải thích
Function
hàm main()
ám chỉ chương trình bắt đầu từ đây
Cho phép dễ dàng truy cập
Greeting Output
#include
using namespace std;
int main() {
// Extract length and width
cout << "Rectangle dimensions: ";
float Length;
float Width;
cin >> Length >> Width;
// Compute and insert the area
float Area = Length * Width;
cout << "Area = " << Area << " = Length "
<< Length << " * Width " << Width << endl;
return 0;
}
Nhập số liệu
Area.cpp
Area.cpp Output
Object-Oriented Programming
31
Chương 3
Cơ sở lập trình
với ngôn ngữ C
Giảng viên : Phạm Doãn Tĩnh
Bộ môn : Điện tử tin học
Khoa : Điện tử - Viễn Thông
Trường : Đại học Bách khoa- Hà nội
Giới thiệu vài nét về ngôn ngữ lập trình C
Vào đầu những năm 1970 Dennis Ritchie tại phòng thí nghiệm Bell đã xây dựng ngôn ngữ lập trình C khi cùng Ken Thompson xây dựng hệ điều hành Unix, khởi đầu C được dùng trên UNIX.
Lý do khiến C trở nên phổ biến là do:
C có lượng từ khoá ít.
Là ngôn ngữ nền cho hệ điều hành (Unix).
Nó đã được chuẩn hoá (ANSI C).
Là ngôn ngữ mạnh và hiệu quả.
Nó là cơ sở cho các ngôn ngữ C++ và Java
Một chương trình C tiêu biểu gồm có các phần sau:
Các lệnh tiền xử lý (Preprocessor commands)
Các định nghĩa kiểu (Type definition)
Các nguyên mẫu hàm (Function prototype)
Các biến (variables)
Các hàm
Đặc biệt chú ý là phải có một hàm tên là main()
Ví dụ:
#include
void main()
{
printf("Chuong trinh dau tien ");
}
3.1 Cấu trúc của chương trình C
Chỉ dẫn tiền xử lý: sử dụng thư viện vào ra chuẩn
Hàm chương trình chính, "void" ám chỉ không trả lại giá trị
Lệnh in một xâu ký tự ra màn hình
Kết thúc mỗi lệnh dùng dấu ";"
3.2 Mô tả ngôn ngữ
3.2.1 Định danh và từ khoá (identifier & keyword)
Các ký tự cơ bản được sử dụng trong chương trình C:
Các chữ in thường (Lower case): a b c . z
Các chữ in hoa (Upper case) : A B C . Z
Các chữ số (Digits) : 0 1 2 . 9
Các ký tự khác:
+ - * / ( ) { } [ ] < > ` " ! # $ % ^ ~ & | ; : , . / ?
Các từ khoá
auto do goto signed unsigned
break double if sizeof void
case else int static volatile
char enum long struct while
const extern register switch continue
float return typedef default for
short union
3.2.1 Định danh và từ khoá (identifier & keyword) (cont)
Định danh - tên (identifier):
Được tạo nên từ chuỗi các chữ cái, chữ số và dấu gạch dưới _
Tên phân biệt hoa thường
Bắt đầu bằng một chữ cái hoặc dấu gạch dưới _
Tên phải duy nhất
Không được sử dụng từ khoá
Độ dài tên phụ thuộc hệ thống (cho phép đến hơn 31 ký tự).
Nguyên tắc đặt tên sao cho dễ hiểu.
Ví dụ: my_name, _your_name, field01
Lời giải thích (Comment)
Trong C, lời giải thích nhằm làm sáng sủa hơn ý nghĩa của các câu lệnh hay một khối lệnh của chương trình.
Lời giải thích được bắt đầu bằng /* và kết thúc bằng */, ví dụ:
/* Lệnh sau in ra màn hình dòng chữ "Hello, world! " */
printf( "Hello, world! ");
3.2.3 Các kiểu dữ liệu
Cách khai báo, viết biểu thức và phép gán.
Các ký tự và kiểu char
Kiểu dữ liệu int
Các kiểu nguyên short, long và unsigned
Kiểu dấu phảy động (float)
Cách khai báo typedef và sizeof
Các hàm toán học
3.2.3.1 Cách khai báo, viết biểu thức và phép gán
Trong C, tất cả các biến đều nên khai báo ở đầu file, hàm, hoặc khối lệnh.
#include
#include
void main()
{
int a,b,c;
char x,y;
...
}
Trong C, một khối lệnh được đặt trong cặp dấu { }
Các biến được khai báo trong một khối thì chỉ có hiệu dụng trong khối đó.
Một biểu thức là sự kết hợp: Các hằng, các biến, các toán tử, và các lời gọi hàm. Hầu hết các biểu thức có trả về giá trị.
ví dụ: a+b; c=x*y +z;
Biểu thức có thể được gán cho một biến
3.2.3.2 Xâu kí tự và kiểu char
Kiểu char chiếm 01 byte trong bộ nhớ máy tính, do đó chúng lưu trữ được tối đa 256 giá trị phân biệt.
Kiểu char được dùng để lưu trữ các chữ cái, các chữ số, các dấu chấm câu cũng như các kí tự đặc biệt.
Kiểu hằng kí tự được đặt trong dấu nháy đơn `, ví dụ như `A`, `1`,`N`,...
Các kí tự điều khiển (bảng bên)
Meaning uses ASCII
Alert a 7
Backslash \ 92
Backspace 8
Carriage return 13
Double quote " 34
Form-feed f 12
Horizontal tab 9
New-line 10
Null character 0
Single quote ` 39
Vertical tab v 11
Question mark ? 63
Nhập số liệu kiểu char và hiển thị trên màn hình?
Để nhập số liệu kiểu char, ta có thể sử dụng các hàm trong thư viện:
char getch() trả về 1 ký tự từ bàn phím nhưng kô hiển thị trên màn hình.
char getche() trả về 1 ký tự từ bàn phím nhưng có hiển thị trên màn hình.
Để in 1 ký tự trên màn hình, ta dùng định dạng %c, để in dưới dạng hexa dùng %x, để in dưới dạng số dùng %d
NgoàI ra ta còn có thể sử dụng hàm putch(char)
3.2.3.2 Xâu kí tự và kiểu char
Một số ví dụ:
printf("%c", `a`); /* cho ra tiếng bíp */
printf(""Book on C" is published"); /* In ra xâu "Book on C" is published */
printf("`Book on C` is published"); /* In ra xâu `Book on C` is published */
char c=`a`;
printf("%c", c); /*In ra màn hình kí tự a */
printf("%b", c); /* in ra màn hình số thứ giá trị trong bảng ascii 97 */
printf("%c%c%c, c, c+1, c+2); /* In ra màn hình a, b, c */
3.2.3.3 Kiểu nguyên (integer)
Kiểu nguyên có thể là 2 bytes (short) hoặc 4 bytes (long)
Hậu tố cho các số nguyên như sau:
Nhập số liệu kiểu nguyên và hiển thị giá trị nguyên trên màn hình
Để nhập giá trị nguyên ta dùng hàm scanf() trong thư viện
cú pháp:
scanf("Định dạng", &bien1, &bien2, .);
Nếu muốn nhập số liệu vào từ 1 xâu, ta sử dụng
sscanf(Xau,"Định dạng", &bien1, &bien2,.)
Ví dụ:
char *s="125";
int i;
sscanf(s,"%d",&i);
printf("i=%d ",i); /* KQ: i=125 */
Ngoài ra ta có thể dùng định dạng %nd với n là số vị trí cần in ra trên màn hình, nếu n lớn hơn độ dài cần in thì các ký tự trắng sẽ tự động được chèn vào phía trước.
3.2.3.4 Kiểu dấu phảy động (floating point)
Hậu tố cho các số dấu phảy động:
Mỗi số dấu phảy động được cấu thành từ 4 phần:
Phần nguyên
Dấu phảy
Phần thập phân
và phần mũ
Ví dụ: 33.777e-22
Nhập số dấu phảy động và hiển thị trên màn hình
Để nhập số dấu phảy động ta dùng hàm scanf() trong thư viện
cú pháp:
scanf("Định dạng", &bien1, &bien2, .);
Nếu muốn nhập số liệu vào từ 1 xâu, ta sử dụng
sscanf(Xau,"Định dạng", &bien1, &bien2,.)
Ví dụ:
char *s="125.788";
double f;
sscanf(s,"%f",&f);
printf("f=%10.3f ",i); /* KQ: f=125.788 */
3.2.3.5 Cách khai báo typedef và hàm sizeof()
Từ khoá "typedef" cho phép người lập trình khai báo một cách rõ ràng cho các tên mới, nó làm chương trình sáng sủa và dễ đọc hơn.
typedef char uppercase;
typedef int INCHES, FEET;
typedef unsigned long size_t;
uppercase u; /* sử dụng khai báo trên */
INCHES length, width;
Hàm sizeof() cho ta biết thông tin về một kiểu dữ liệu nào đó (kích thước)
/* Compute the size of some fundamental types. */
#include
int main(void) {
printf("The size of some fundamental types is computed. ");
printf(" char:%3d byte ",sizeof(char));
printf(" short:%3d bytes ",sizeof(short));
printf("int:%3d bytes ",sizeof(int));
printf(" long:%3d bytes ",sizeof(long));
printf(" unsigned:%3d bytes ",sizeof(unsigned));
printf(" float:%3d bytes ",sizeof(float));
printf(" double:%3d bytes ",sizeof(double));
printf("long double:%3d bytes ",sizeof(long double));
return 0; }
3.2.3.6 Các hàm toán học
Trong C, các hàm hàm toán học sẵn có trong thư viện "math.h", chẳng hạn như:
double sqrt(double): hàm khai căn
double pow(double,double): hàm luỹ thừa
double exp(double): Hàm mũ
double log(double): hàm logarit
...
#include
#include
int main(void)
{
double x;
printf(" %s %s %s ",
"The square root of x and x raised",
"to the x power will be computed.",
"---");
while (1)
{
/* do it forever, endless loop */
printf("Input x: ");
scanf("%lf", &x);
if (x >= 0.0)
printf(" %15s%22.15e %15s%22.15e %15s%22 .15e ",
"x = ", x,
"sqrt(x) = ",sqrt(x),
"pow(x, x) = ",pow(x, x));
else
printf(" Sorry, your number must be nonnegative. ");
}
return 0;
}
3.2.3.6 Các hàm toán học (tiếp)
Bài tập
Cho hàm số:
Hãy viết 1 chương trình C nhập vào x, n (n nguyên) và tính f(x)?
#include
#include
void main()
{ double tu,mau;
float x;
int n;
printf("Nhap vao x:"); scanf("%f",&x);
printf("Nhap vao n:"); scanf("%d",&n);
tu=5*powl(x,7)*powl(x,5/n);
mau=(6*powl(x,3)+powl(x,n));
printf("f(x)=%10.10f ",tu/mau);
}
3.2.4 Các kiểu hằng
Hằng ký tự (char) được biểu diễn trong cặp dấu nháy đơn ``, ví dụ: `a`,`G`,...
Hằng nguyên được biểu diễn giống trong toán học, ví dụ 125, -56, 90
Các hằng dấu phảy động được biểu diễn theo hai cách:
Giống toán học thông thường: 12.56, 28.067
Theo khoa học: 12.34e+2
Các hằng xâu ký tự được biểu diễn trong cặp dấu nháy kép " ", khi hằng quá dài để viết trên nhiều dòng thì dùng dấu để nối dòng, ví dụ:
"Day la mot hang xau ky tu"
"Day la hang xau voi
2 dong "
Để khai báo hằng chúng ta sử dụng cú pháp:
const Kiểu Tên_Hằng=Giá_Trị;
VD: const float PI=3.14;
3.3 Các toán tử
Các toán tử toán học như:
+ phép cộng
- phép trừ
* phép nhân
/ phép chia
% phép lấy phần dư, ví dụ 8 % 3 sẽ cho ta 2.
Các thao tác theo bit
& phép và theo bit (AND), VD 0xFF & 0xF1 -> 0xF1
| Hoặc theo bit (OR), VD 0x0F | 0xF1 -> 0xFF
^ Hoặc loại trừ (XOR), VD 0xFF ^ 0xF1 -> 0x0E
~ Lấy phần bù theo bit, VD ~0 -> 1
<< Phép dịch trái, VD 0x01 << 1 -> 0x02
>> Phép dịch phải, VD 0xFF >> 2 -> 0x3F
3.3 Các toán tử
Giá trị logic là đúng - true (1) hoặc sai - false (0)
Các phép toán so sánh (có thứ tự ưu tiên thấp hơn các phép toán số học)
Các phép toán logic
Phép phủ định một ngôi !, ví dụ 3> 7 cho giá trị 0, !(3 >7) cho giá trị 1
Phép và (AND) &&, ví dụ (3>7) && (5 > 0) cho giá trị 0
Phép hoặc (OR) ||, ví dụ (3>7) || (5 > 0) cho giá trị 1
Thứ tự ưu tiên của các phép toán như sau: ! , > >= < <=, == !=, && ||
3.3 Các toán tử
Các toán tử tăng giảm (increment and decrement operators)
Chúng được sử dụng để tăng hoặc giảm giá trị của một biến lên hoặc xuống 1 đơn vị.
Chúng có thể được sử dụng dưới dạng postfix hoặc prefix.
Cú pháp:
ten_bien++, ++ten_bien
ten_bien--, --ten_bien
Dù ở trước hay sau thì giá trị của biến đều tăng lên 1 đơn vị.
Chúng có mức độ ưu tiên cao trong một biểu thức.
Sự khác nhau cơ bản trong postfix và prefix thể hiện qua ví dụ sau
#include
void main() {
int a,b,c=0;
a=++c; b=c++;
printf("Gia tri cua a=%d, b=%d, c=%d", a,b,++c); }
Cho ta kết quả:
Gia tri cua a=1, b=1, c=3
3.3 Các toán tử
Trong C, toán tử gán được sử dụng là "=" khác với PASCAL là ":="
Ten_bien=bieu_thuc;
Ten_bien=gia_tri;
Ngoài ra trong C còn cho phép ta gán cùng một giá trị cho nhiều biến cùng một lúc
Ví dụ:
int a,b,c,d; a=b=c=d=100;
a=(b+2)+(c=3); /* tuong duong voi b=2; c=3; a=b+c; */
Các phương pháp gán khác:
Cú pháp:
Ten_bien Toan_tu= bieu_thuc; tương đương với
Ten_bien= Ten_bien Toan_tu Bieu_thuc;
+= -= *= /= %=
>>= <<= &= ^= |=
Ví dụ: j +=3; /* tuong duong j=j+3; */
Biểu thức điều kiện (?):
Cú pháp: s=ex1 ? gt1:gt2;
Nếu ex1 nhận giá trị đúng (1- true) thì s nhận gt1 nếu không s nhận gt2.
3.3 Các toán tử
Trong C dấu "," cũng được xem như một toán tử, toán tử này có trình tự ưu tiên thấp nhất.
Ví dụ int a,b=0,c;
a=100,b=200;
Trình tự ưu tiên của các toán tử như sau (Từ trên xuống, từ trái qua phải)
() [] ->> .
- + ++ -- ! ~ * & sizeof (type)
* / % + -
<< >>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %= &= ^= |= <<= >>=
,
3.3 Các toán tử
Chuyển đổi kiểu (type casting)
Trong C, việc chuyển đổi kiểu khá linh hoạt.
Cú pháp cho chuyển đổi kiểu như sau:
(type) (bieu_thuc);
#include
void main()
{
int a;
double b=10.1,c=20.55;
a=(int)(c-b);
printf("a=%d ",a);
}
Cho ta kết quả:
a=10
3.4 Các lệnh điều khiển chương trình
Lệnh if ... else
Lệnh switch ... case
Lệnh while(dieu_kien)...
Lệnh do ... while(dieu_kien)
Lệnh for ...
Lệnh break thoát một vòng lặp
Lệnh continue
Lệnh goto
3.4.1 Lệnh if
Cú pháp:
if ( expression )
stmt1;
hoặc
if ( expression )
stmt1;
else
stmt2;
Khi số câu lệnh trên mỗi nhánh rẽ lớn hơn 1 thì đặt chúng trong cặp dấu { }
if ( c == `Y` )
{
printf( "Yes, " );
printf( "we have no bananas! " )`
bananas = 0;
}
if ( ( c >= `a` ) && ( c <= `z` ))
{
printf( "lower case " );
++lowers;
}
else if ( ( c >= `A` ) && ( c <= `Z` ))
{
printf( "upper case " );
++uppers;
}
else
{
++others;
}
3.4.2 Lệnh switch ... case
Câu lệnh switch sử dụng để chọn một từ vài nhánh rẽ dựa trên giá trị một biểu thức nào đó.
Cú pháp:
switch( expression )
{
case constant-expr1:
stmt;
break;
case constant-expr2:
stmt;
break;
. . .
default:
stmt
}
Chú ý: Nếu không có break sẽ dẫn đến các câu lệnh còn lại sẽ bị ảnh hưởng.
Ví dụ:
switch( c )
{
case `Y`:
printf( "Yes" );
break;
case `N`:
printf( "No" );
break;
default:
printf( "What?a" );
}
Bài tập
Viết 1 chương trình C, nhập vào tháng và năm và hiển thị trên màn hình số ngày trong tháng.
3.4.2 Lệnh switch ... case
Có thể dùng nhiều nhãn case cho cùng một nhánh:
switch( c )
{
case `Y`:
case `y`:
printf( "Yes" );
break;
case `N`: case `n`:
/* 2 ĐK Cùng dòng */
printf( "No" );
break;
default:
printf( "What?a" );
}
switch(month)
{
case 1:case 3: case 5: case 7:case 8:case 12:case 10:
printf("Thang 31 ngay! ");
break;
case 4:case 6:case 9:case 11:
printf("Thang 30 ngay! ");
break;
case 2:
if ((year % 4) ==0)
printf("Thang 29 ngay! ");
else
printf("Thang 28 ngay! ");
break;
}
3.4.3 Lệnh while ...
Câu lệnh while được sử dụng để lặp lại một lệnh hoặc khối lệnh khi biểu thức logic đúng.
Cú pháp:
while ( expression )
stmt ;
Ví dụ
x = 1;
while ( (x * 5) >= (x * x) )
{
printf( "%d %d %d ", x, x*5, x*x );
x++;
}
Với câu lệnh này thì lệnh (khối lệnh) chỉ và chỉ được thực hiện khi expression là đúng!
3.4.4 Lệnh do ... while
Câu lệnh while được sử dụng để lặp lại một lệnh hoặc khối lệnh khi biểu thức logic đúng.
Cú pháp
do
stmt ;
while ( expression );
Ví dụ:
lng = 0;
do
{
c = getchar();
++lng;
}
while ( c != ` ` );
printf( "line length %d", lng );
3.4.5 Lệnh for (...)
Cú pháp:
for ( init-expr; cont-expr; loop-expr )
stmt;
Thực hiện:
Tính toán init_expr nếu có
Tính toán cont-expr nếu có
Nếu cont-expr là true hoặc bỏ qua thì stmt được thực hiện ít nhất 1 lần, rồi sau đó loop-expr sẽ được thực hiện.
Lặp lại 2 bước trên đến khi cont-expr là false.
9 times 0 is 0
9 times 1 is 9
9 times 2 is 18
9 times 3 is 27
9 times 4 is 36
9 times 5 is 45
9 times 6 is 54
9 times 7 is 63
9 times 8 is 72
9 times 9 is 81
/* Bảng cửu chương */
#define MAX 9
for ( i = 0; i <= MAX; i++ )
{
for ( j = 0; j <= MAX; j++ )
{
printf( "%d times %d is %d ", i, j, i*j );
}
}
printf( " " );
3.4.6 Lệnh break thoát một vòng lặp
Với các vòng lặp for, while, do ... while thì lệnh break thoát khỏi vòng lặp ở mức thấp nhất mà tại đó lệnh break xuất hiện!
Ví dụ:
int c,max=10;
printf( "Enter up to %d chars", max );
for ( i = 0; i < max; i++ )
{
c = getchar();
if ( c == EOF || c == ` ` )
{
break;
}
putchar( 255 - c ); /* encrypt char */
}
putchar( ` ` );
3.4.7 Lệnh goto chuyển điều khiển chương trình
Lệnh goto dùng để chuyển điều khiển của chương trình tới một nhãn (label) nào đó.
Cú pháp: goto label;
ở đây label có cú pháp:
Ten_label:
{
Khoi_lenh_cua_label;
}
Nói chung là nên hạn chế dùng lệnh này, vì nó là lệnh chuyển điều khiển phi cấu trúc.
#include
#include
void main()
{
int i,max=10,linelng;
char c;
printf( "Enter %d lines... ", max );
for ( i = 1; i <= max; i++ )
{
linelng = 0;
while ( ( c = getchar() ) != ` ` )
{
if ( c == EOF )
{
goto SickOfIt;
}
++linelng;
}
printf( "Length of line %d is %d ",
i, linelng );
}
SickOfIt:
printf( "All done... " );
}
Bài tập
1. Viết 1 chương trình C, nhập vào N số (N xác định bằng cách nhập từ bàn phím).
Tính giá trị trung bình của các số dương?
2. Viết 1 chương trình nhập vào 1 dãy các ký tự và đưa ra thống kê xem có bao nhiêu chữ cái, bao nhiêu chữ số, bao nhiêu ký tự đặc biệt?
3. Cho:
A(n)= 1+2 + 3 + 5 + 8 + ... an-2 + an-1 + an
Với a0 =1, a1 =2.
và an = an-2 + an-1
Viết 1 chương trình nhập vào n và hiển thị dãy số trên màn hình?
3.5 Mảng (array)
Mảng là một kiểu cấu trúc dữ liệu dùng lưu trữ nhiều phần tử dữ liệu cùng kiểu.
Khai báo giống như biến thông thường, trừ việc ta chỉ ra số chiều và số phần tử mảng.
Các phần tử có thể được khởi tạo giá trị ban đầu, khi được khởi tạo giá trị đầu, chiều đầu tiên có thể bỏ qua và để chương trình dịch tự tính.
Mỗi phần tử mảng được truy cập thông qua tên mảng và chỉ số phần tử (subscript).
3.5.1 Khai báo và khởi tạo mảng
Cú pháp:
data_type array_name[so_phan_tu];
Ví dụ:
int a[10]; /* Khai báo mảng 10 số nguyên */
char my_name[35]; /* Khai một xâu 35 ký tự */
Khi muốn khởi tạo (initialize) các phần tử mảng ta đưa các giá trị khởi tạo vào dấu {gt1,gt2,...,gtN }
Với phần tử chưa khởi tạo thì giá trị của nó bằng 0.
Khi được khởi tạo giá trị đầu, có thể bỏ tham số chiều (compiler sẽ tự động tính toán)
Ví dụ:
char whitesp[5] = {` `,` `,` `,` `,`f`}; /* Mảng chứa các ký tự trắng */
int prodcod[] = { 16, 60, 75, 101, 17 }; /* Mảng chứa các mã sản phẩm */
Ta có thể sử dụng sizeof() để xác định số phần tử mảng:
int tb3[] = { 10, 20, 30, 40, 95 }; /* khởi tạo mảng */
#define TB3_CT (sizeof(tb3)/sizeof(tb3[0]))
Trong đó sizeof(tb3) cho ta số bytes mà mảng chiếm chỗ, sizeof(tb3[0]) cho ta kích thước 1 phần tử .
3.5.2 Truy cập các phần tử mảng.
Các phần tử mảng được truy cập dùng cú pháp:
ten_mang[chi_so_phan_tu];
Chỉ số của phần tử đầu tiên là 0.
Ví dụ
int Larry[5] = { 5, 10, 15, 20, 25 };
int i, Curly; tot = 0;
Curly = Larry[0]; /* Curly <-- 5 *>Curly = Larry[3]; /* Curly <-- 20 *>Curly = Larry[4]; /* Curly <-- 25 *>i = 1;
Curly = Larry[i]; /* Curly <-- 10 *>Larry[0] = 30; /* Larry=30,10,15,20,25 */
/* sum and print all array elements */
for ( i = 0; i < 5; i++ )
{
printf( "%d", Larry[i] );
tot += Larry[i];
}
/* increment each array element */
for ( i = 0; i < 5; i++ )
{
++Larry[i];
}
3.5.3 Mảng nhiều chiều
Mảng nhiều chiều khai báo tương tự như mảng 1 chiều, chỉ có điều ta thêm chiều bằng các cặp dấu [].
Để truy cập ta dùng các chỉ số tương ứng.
Ví dụ:
/* Khai báo mảng 4 hàng, 3 cột */
int hah[4][3];
Sự phân bố vị trí trong bộ nhớ như hình vẽ bên.
Để duyệt mảng nhiều chiều dùng vòng lặp lồng nhau.
Để khởi tạo mảng nhiều chiều
int a[2][3]={{1,2,3},{4,5,6}};
#define NROWS 15 /* symbol for # rows */
#define NCOLS 24 /* symbol for # cols */
int i, j;
long mx[NROWS][NCOLS], totmx;
double pct[NROWS][NCOLS];
... /* Nhập mảng */
/* Tổng các PT mảng */
for ( i = 0; i < NROWS; i++ )
{
for ( j = 0; j < NCOLS; j++ )
{
totmx += mx[i][j];
}
}
/* compute pct of total for each */
if ( totmx != 0 )
{
for ( i = 0; i < NROWS; i++ )
{ for ( j = 0; j < NCOLS; j++ )
{pct[i][j] = mx[i][j] / totmx; }
}
}
3.6 Con trỏ (pointer)
Trong chương trình, mỗi biến chiếm một số bytes nhất định và lưu ở một vị trí cụ thể trong bộ nhớ máy tính.
Con trỏ thực chất là một loại biến đặc biệt được sử dụng để lưu địa chỉ một ô nhớ cụ thể nào đó hoặc lưu địa chỉ của một biến khác.
Khai báo:
Data_Type *pointer_var_name;
hoặc
Data_Type* pointer_var_name;
Để khởi tạo giá trị của con trỏ, ta có thể cho nó trỏ vào một địa chỉ nhớ cụ thể hoặc lấy địa chỉ của một biến khác thông qua toán tử lấy địa chỉ "&".
Để truy cập vào ô nhớ tại địa chỉ mà con trỏ đang trỏ tới dùng toán tử tham chiếu ngược *, với cú pháp:
*Ten_contro = gia_tri;
hoặc
ten_bien=*Ten_contro;
Ví dụ:
int *int_ptr; /* Khai báo con trỏ int */
float *float_ptr; /* Con trỏ float */
int a;
char b;
int *ip=&i;
char *cp=&b;
int i=3, j=5, *p=&i, *q=&j, *r;
double x;
p==&i p==(&i) 1
**&p *(*&p) 3
r=&x r=(&x) illegal
7**p/*q+7 (((7*(*p)))/(*q)+7 11
*(r=&j)*=*p (*(r=(&j)))*=(*p) 15
3.6 Con trỏ (pointer) (tiếp)
Bên cạnh con trỏ xác định kiểu, ta còn có thể dùng con trỏ không xác định kiểu (void *) để lưu trữ địa chỉ của bất kỳ ô nhớ nào. Nhưng lưu ý với con trỏ này khi truy cập ô nhớ mà nó trỏ tới cần chuyển đổi kiểu tương ứng!
Ngoài ra ta còn có thể dùng các phép toán số học đối với con trỏ.
int *p1;
char *p2;
float *p3;
++p1; /* p1 tăng lên 4~4 bytes */
++p2; /* p2 tăng lên 1~1 byte */
++p3; /* p3 tăng lên 4~4 bytes */
#include
void main()
{
short i=10, *p1=&i;
char c=`A`,*p2=&c;
float f=100.8,*p3=&f;
printf("p1=%p p2=%p p3=%p ",p1,p2,p3);
printf("++p1=%p ++p2=
%p --p3=%p ",++p1,++p2,--p3);
}
3.7 Mối liên hệ giữa con trỏ và mảng
Bản thân tên mảng là địa chỉ của phần tử đầu tiên trong mảng
Ví dụ:
int a[100],*p;
Khi đó a[i] *(a+i)
p=a+1
p=&a[1];
#define N 100
int a[N], i, *p, sum=0;p=a;
p=&a[0];
for (p=a;p<&a[N]; p++) for (i=0;i sum+=*p; sum+=a[i];
for (i=0;i sum+=*(a+i); for (i=0;i sum+=p[i];
3.8 Cấu trúc struct
Để khai báo cấu trúc ta dùng cú pháp:
struct struct_name
{
type1 field1;
type2 field2;
...
} [bien_co_kieu_struct_name];
Để truy cập đến các thuộc tính của struct ta sử dụng toán tử "."
Ta có thể khởi tạo giá trị cho một biến struct giống như đối với mảng , đặt các giá trị trong cặp dấu { } phân cách giá trị bằng dấu ","
#include
struct emp
{
int empno;
char ename[35];
};
void main()
{
struct emp e1={100,"Nguyen X"};
printf("ENo:%d, Ename: %s ",e1.empno,e1.ename);
}
3.9 Hợp Union
Với cấu trúc struct, mỗi trường chiếm một vị trí nhớ khác nhau, đối với union chúng chia sẻ cùng một vùng nhớ.
Cú pháp khai báo:
union union_name
{
Type1 field1;
Type2 field2;
...
}
* Define a variable to hold an integer or
* a real number (but not both)
union value {
long int i_value; /* The real number */
float f_value; /* The floating-point number */
} data;
int i; /* Random integer */
float f; /* Random floating-point number */
void main()
{
data.f_value = 5.0;
data.i_value = 3; /* data.f_value overwritten */
i = data.i_value; /* legal */
f = data.f_value; /* not legal, will generate unexpected results */
data.f_value = 5.5; /* put something in f_value/clobber i_value */
i = data.i_value; /* not legal, will generate unexpected results */
}
3.10 lệnh typedef
typedef cho phép ta định nghĩa một kiểu dữ liệu mới cho C.
Cú pháp:
typedef kieu_dang_co kieu_moi;
Ví dụ
main()
{
typedef int group[10]; /* Tạo kiểu mới "group" */
group totals; /* Dùng kiểu mới cho biến totals */
for (i = 0; i < 10; i++)
totals[i] = 0;
return (0);
}
3.11 kiểu enum
enum được dùng cho các biến mà sẽ chỉ nhận một số giá trị nhất định, các giá trị được liên hệ đến thông qua tên.
typedef int week_day;
/* define the type for week_days */
const int SUNDAY = 0;
const int MONDAY = 1;
const int TUESDAY = 2;
const int WEDNESDAY = 3;
const int THURSDAY = 4;
const int FRIDAY = 5;
const int SATURDAY = 6;
/* now to use it */
week_day today = TUESDAY;
enum week_day {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
FRIDAY, SATURDAY};
/* now use it */
enum week_day today = TUESDAY;
3.12 Bit Fields và mảng cấu trúc
struct item {
unsigned int list:1; /* true if item is in the list */
unsigned int seen:1; /* true if this item has been seen */
unsigned int number:14; /* item number */
};
Ta có thể tạo một mảng gồm 10 phần tử có kiểu là cấu trúc item:
struct item mang_ct[10];
Trong C, việc kết hợp cấu trúc với con trỏ sẽ cho phép ta tạo ra những cấu trúc dữ liệu rất mạnh trong lập trình:
struct linked_list
{
int node_data;
struct linked_list * next;
};
3.13 Hàm (function)
Trong C, tất cả các chương trình con đều được coi là hàm.
Có 2 loại hàm: trả lại giá trị và không trả lại giá trị (void).
Để khai báo 1 hàm trong C, dùng cú pháp sau:
Kieu_Tra_lai ten_ham(tham_so)
{
/* Neu tra lai gia tri co them return (giatri); */
}
Ví dụ:
int cong_so(int a,int b)
{
return(a+b);
}
Trong C, các tham số khi truyền vào hàm thường là qua giá trị sao chép, do vậy cho dù trong hàm có làm thay đổi giá trị của nó thì khi kết thúc hàm, giá trị của nó vẫn không thay đổi.
Trong trường hợp muốn thay đổi giá trị của tham số khi thoát khỏi hàm, ta phải khai báo tham số gọi qua tham chiếu địa chỉ (&) hoặc dùng con trỏ!
3.13 Hàm (function)
Giả sử trong ví dụ sau, ta muốn tăng giá trị tham số thứ nhất lên 1, tham số 2 lên 2 đơn vị khi kết thúc hàm thì hàm cong_so_1 sẽ cho ta điều mong muốn.
void main()
{
int a=10,b=20,c;
c=cong_so(a,b);
printf("a=%d,b=%d ",a,b);
c=cong_so_1(a,b);
printf("a=%d,b=%d ",a,b);
c=cong_so_2(&a,&b);
printf("a=%d,b=%d ",a,b);
}
#include
int cong_so(int a,int b)
{
a++;b+=2;
return(a+b);
}
int cong_so_1(int &a,int &b)
{
a++;b+=2;
return(a+b);
}
int cong_so_2(int *a,int *b)
{
(*a)++;(*b)+=2;
return(*a+*b);
}
Cho ta kết quả như sau:
a=10,b=20
a=11,b=22
a=12,b=24
Truyền tham số mảng
Để truyền tham số có kiểu mảng, ta dùng cú pháp
Kieu_Tra_Ve Ten_Ham(Kieu_PT_Mang a[] ,...)
Ví dụ:
/* Hàm sắp xếp 1 mảng nguyên a gồm N phần tử */
void SX_NoiBot(int a[], int N)
{
int i,j,tmp;
for(i=0;i for(j=0;j if(a[j]>a[j+1])
{ tmp=a[j];a[j]=a[j+1];a[j+1]=tmp;}
}
void main()
{ int a[10]={9,2,7,4,3,6,1,12,8,5}, i;
SX_NoiBot(a,10);
for(i=0;i<10;i++) printf("%3d",a[i]);
}
3.13 Hàm (function)
Ngoài cách dùng hàm thông thường đã biết, ta còn có thể dùng hàm dưới dạng con trỏ tới hàm.
Cách này thường được dùng trong trường hợp ta cần lập trình gọi hàm một cách tổng quát.
Ví dụ:
#include
#include
double dien_tich_hinh_tron(float bk)
{
return(3.14*bk*bk);
}
typedef double (*fptr)(float);
void main()
{
fptr x=dien_tich_hinh_tron;
printf("%f ",x(2));
}
Trong C, hàm còn có thể có tính đệ quy (recursive): Một hàm có thể có lời gọi đến chính nó.
Ví dụ: Tính giai thừa của một số N
#include
#include
long giai_thua(int N)
{
return(N<=1? 1:N * giai_thua(N-1));
}
void main()
{
printf("4!=%d ", giai_thua(4));
}
3.13 Hàm (function)-Các tham số cho hàm main()
C cung cấp cho ta một cách để truyền tham số cho chương trình khi ta chạy chương trình thông qua các tham số của hàm main()
cú pháp như sau:
main( int argc, char *argv[] )
Trong đó:
"argc" là số tham số
"argv[]" là mảng chứa giá trị các tham số.
Nhưng argv[0] là tên của chương trình, như vậy giá trị tham số bắt đầu từ argv[1].
Ví dụ:
#include
main( int argc, char *argv[] )
{
if( argc == 2 )
printf("The argument supplied is %s ", argv[1]);
else if( argc > 2 )
printf("Too many arguments supplied. ");
else
printf("One argument expected. ");
}
3.13 Hàm (function)- Gọi các chương trình ngoài
Ta có thể thực hiện các lệnh của hệ điều hành thông qua lời gọi hệ thống.
Để thực hiện, ta dùng thư viện hàm với lệnh:
system("OS command");
Ví dụ:
#include
main() /* SYS.C */
{
char *command = "dir";
system( "cls" );
system( command );
}
3.14 Vào/ra với C
Trong C, stdio.h là thư viện hàm cho vào ra. Trong đó ta sử dụng một số hàm thông dụng như:
printf("format",args) để kết xuất dữ liệu.
scanf("format",args) để nhập số liệu từ bàn phím.
Ngoài ra, ta có thể dùng hàm gets(char *s) để nhập một xâu ký tự từ bàn phím.
Chú ý: Vào ra với C, cần lưu ý đến bộ đệm bàn phím. Khi cần xoá bộ đệm ta dùng hàm:
fflush(stdin);
3.14 Vào/ra với C
để nhập m
1
Ngôn ngữ lập trình
Với C & C++
(Lập trình 1)
Giảng viên : Phạm Doãn Tĩnh
Bộ môn : Điện tử tin học
Khoa : Điện tử - Viễn Thông
Trường : Đại học Bách khoa- Hà nội
Tài liệu tham khảo
Ngôn ngữ lập trình C++ và cấu trúc dữ liệu -PGS.TS Nguyễn Việt Hương.
Kỹ thuật lập trình C - GS. Phạm Văn ất - NXB Thống kê
The C Programming Language - Ritchie kernighan- Prentice Hall Software series.
Practical C Programming, 3rd Edition - Steve Oualline - O`Reilly
The C++ Programming Language Special 3rd Edition- Bjarne Stroustrup - C++ Creator -Addison Wesley
C++ by Dissection - Ira Pohl (University of California Santa Cruz)- Addison Wesley.
Object-Oriented Programming
3
Chương 1
Các khái niệm cơ bản về lập trình
1.1 Phân tích bài toán
Với "phần cứng" và phần mềm trong tay rồi, người lập trình cần làm gì?
Học một ngôn ngữ lập trình.
Vấn đề cần giải quyết cần được xem xét kỹ lưỡng.
Phân tích bài toán là quá trình làm hoàn tất các mức chi tiết cần thiết khi giải quyết một vấn đề. Nó bao gồm các bước chính như sau:
Vấn đề cần giải quyết phải được hiểu một cách thấu đáo. Bởi nếu người giải quyết chưa hiểu vấn đề thì tất nhiên máy tính cũng không thể giải quyết tốt được
Cần phải chọn được một phương án giải quyết và phát triển phương án.
Tiến trình giải cần được mô tả dưới dạng từng bước từng bước một. Đôi khi chúng ta gọi là "Thuật giải" (Solution algorithm).
Thuật toán được lập trình và chương trình được chạy thử.
Cuối cùng thuật toán được kiểm định.
1.2 Giải thuật và các vấn đề liên quan
Giải thuật là gì?
"Giải thuật là một danh sách các chỉ dẫn mô tả một cách chính xác các bước của một quá trình mà đảm bảo là quá trình này sẽ phải kết thúc sau một số bước nhất định với câu trả lời đúng cho từng trường hợp cụ thể của một vấn đề cần giải quyết".
Mỗi thuật giải phải đảm bảo 4 đặc tính sau:
Sự chính xác.
Tính hiệu quả- Đưa ra câu trả lời đúng.
Đảm bảo sự kết thúc.
Tổng quát hoá.
Ví dụ: Giải thuật cho giải phương trình bậc nhất a.x+b=0
Bước 1: Xét a =0, nếu đúng tiếp tục bước 2, nếu sai tiếp tục bước 5.
Bước 2: Xét b=0, nếu đúng tiếp tục bước 3, nếu sai tiếp tục bước 4.
Bước 3: Hiển thị vô số nghiệm và kết thúc.
Bước 4: Hiển thị vô nghiệm và kết thúc.
Bước 5: Hiển thị nghiệm duy nhất x=-b/a và kết thúc.
1.3 Quá trình thiết kế.
1.3.1 Đặc tả chương trình.
Xuất phát điểm cho quá trình thiết kế bất kỳ một chương trình máy tính nào cũng đều phải có một đặc tả phù hợp về hoạt động của chương trình dự định thực hiện.
Thông thường đặc tả của chương trình bào gồm:
Mô tả chức năng của chương trình.
Các yêu cầu đầu vào và đầu ra.
Các biện pháp lưu trữ dữ liệu.
Các thủ tục quản lý tệp.
Mô tả các thuật toán xử lý đặc biệt được sử dụng.
Định dạng của đầu ra.
1.3 Quá trình thiết kế.
1.3.2 Các kiểu tệp (File types)
Tệp chứa các bản ghi một cách lặp đi lặp lại.
Tuỳ theo việc tổ chức các bản ghi trong tệp, người ta chia tệp thành 4 loại khác nhau:
Tệp nối tiếp (Serial file)
Các bản ghi được ghi nối tiếp nhau theo trình tự thời gian đưa bản ghi vào. Ví dụ các bản ghi ghi lại các phiên giao dịch.
Tệp tuần tự (sequential file)
ở đây các bản ghi được sắp xếp theo trình tự của một hoặc nhiều trường khoá.
Tệp này được tạo ra nhờ sắp xếp các tệp nối tiếp. VD: Danh sách sinh viên theo số hiệu sinh viên.
1.3 Quá trình thiết kế.
1.3.2 Các kiểu tệp (File types)
Tệp tuần tự được chỉ mục (Indexed sequential file)
Thay vì sắp xếp lại toàn bộ tệp, người ta tạo ra các tệp chỉ mục và trong các tệp này chứa các trường khoá đã sắp xếp đi kèm với địa chỉ các bản ghi trong tệp chính.
Tệp truy cập trực tiếp (Direct Access file)
Để có thể truy cập nhanh, mỗi bản ghi sẽ được ghi vào địa chỉ tạo ra nhờ áp dụng một công thức đối với trường khoá- không cần tệp chỉ mục nhung tốn không gian lưu trữ.
1.3 Quá trình thiết kế.
1.3.3 Bảng quyết định (Decision Table)
Bảng quyết định?
Bảng quyết định là một bảng chỉ ra các hành động khác nhau được thực hiện dựa theo các sự kết hợp khác nhau của các điều kiện.
1.3 Quá trình thiết kế.
1.3.3 Bảng quyết định (Decision Table)
Ví dụ: Giả sử một cửa hàng điện tử thực hiện việc giảm giá cho khách hàng dựa vào tiêu chí: Khách quen tiêu trên $200 giảm giá 20%, nếu không thì giảm giá 10%. Khách không quen thì tiêu trên $200 giảm giá 10%, nếu không thì không giảm giá.
Quy tắc tổ hợp: Các điều kiện giống nhau, trừ một hàng; và các hành động là giống nhau hoàn toàn thì ta có thể kết hợp chúng lại, thay điều kiện khác nhau bằng dấu "-".
1.3.4 Kiểm tra thiết kế (Design checking)
Sau khi thiết kế xong, chúng ta phải kiểm tra tính đúng đắn của thiết kế. Có rất nhiều phương pháp khác nhau để kiểm tra thiết kế.
1. Dry-run.
Phương pháp này, người kiểm tra dùng giấy bút để tính toán và ghi lại các bước thực hiện của chương trình dựa theo một số dữ liệu thử.
2. Walk through:
Đây là phương pháp mà người thiết kế mô tả thiết kế của mình cho các đồng nghiệp và ghi nhận lại tất cả các đóng góp ý kiến.
Với PP này, cho phép bộc lộ sớm các vấn đề, tương tác các thành viên trong nhóm, đào tạo lẫn nhau, tiến trình ổn định, tính nhất quán trong thiết kế.
Catalytic Checking.
Người thiết kế mô tả thiết kế, đồng nghiệp luôn hỏi "Tại sao?" "Làm thế nào?" và sẽ tự bộc lộ ra điểm sai trong thiết kế.
Independent Inspection
Đây là phương pháp dùng nhiều người độc lập kiểm tra thiết kế dưới sự chỉ đạo của một người có kinh nghiệm.
1.3.5 Thiết kế hướng đối tượng (Object-Oriented Design OOD)
Phương pháp thiết kế hướng đối tượng OOD là phương pháp thiết kế gồm có 4 bước chính sau đây:
1. Xác định các loại đối tượng (Các lớp - classes) xuất hiện trong giải pháp.
2. Xác định và mô tả các biến thể hiện trong mỗi loại đối tượng.
3. Xác định các hành động của mỗi một loại đối tượng.
4. Đối với mỗi hành động, mô tả chức năng của nó, các tham số, các điều kiện tiên quyết và các hậu điều kiện.
Ví dụ: Giả sử chúng ta cần xây dựng một CTrình tính điểm trung bình và lấy ra điểm trung bình cho các sinh viên. Mỗi sinh viên trong lớp được có các thông tin sau: tên SV, 3 điểm thi, điểm trung bình.
Bước 1: Xác định các loại đối tượng, ở đây có 2 loại đối tượng là Sinhvien và Lophoc.
Bước 2: Xác định các biến thể hiện của mỗi loại đối tượng:
Sinhvien: TenSV, Diem1, Diem2, Diem3, DiemTB
Lophoc: TenLop,SoSV, DSSV
1.3.5 Thiết kế hướng đối tượng (Object-Oriented Design OOD)
Bước 2: Xác định các biến thể hiện của mỗi loại đối tượng:
Sinhvien: TenSV, Diem1, Diem2, Diem3, DiemTB
Lophoc: TenLop,SoSV, DSSV
Bước 3:
Sinhvien:
Constructor
Destructor
GetName: Trả lại tên SV
SetName: Đổi tên SV
GetData: Nhập số liệu SV từ bàn phím
ComputeAverage: Tính điểm TB.
DisplayAverage: Hiển thị điểm TB.
Lophoc:
Constructor
Destructor
ThemSV: Thêm một sinh viên vào lớp học.
XoaSV: Xoá một SV khỏi lớp học.
1.4 Lịch sử phát triển của kỹ thuật lập trình
Lập trình có cấu trúc - Lập trình thủ tục (structural-procedural)
Lập trình hướng đối tượng
2 Mô hình lập trình
Structural (Procedural) Object-Oriented
PROGRAM PROGRAM
FUNCTION
FUNCTION
FUNCTION
Các đặc tính của ngôn ngữ lập trình hướng đối tượng
1. Data abstraction (Trừu tượng hoá dữ liệu)
2. Inheritance of properties (Sự kế thừa các thuộc tính)
3. Dynamic binding of operations to objects (Sự ràng buộc các thao tác với các đối tượng)
Được trình bày chi tiết ở phần sau
1.5 Thử nghiệm chương trình (testing)
Chạy thử là quá trình xác thực một chương trình tuân theo đúng những đặc tả mà nó cần thực hiện.
Testing gồm những bước sau:
Chọn bộ dữ liệu thử phù hợp.
Xác định kết quả đầu ra mong muốn.
Chạy chương trình
Phân tích kết quả đầu ra của chương trình.
Các phương pháp:
Unit testing: Thực hiện ở mức module
Integration testing (test tích hợp): diễn ra ở mức cao hơn
Bottom-up testing: Trong phương pháp này thì các module mức thấp được tích hợp và chạy thử trước, như vậy ta cần một driver để thực hiện.
Top-down testing: Các module mức cao được tích hợp và chạy thử trước, lúc đó ta cần các dummy module (module giả) ở mức thấp.
System testing: Đảm bảo rằng toàn bộ chương trình chạy đúng.
Acceptance testing: Kiểm tra nghiệm thu liên quan nhiều đến người sử dụng (họ coi hệ thống như hộp đen).
1.5 Thử nghiệm chương trình (testing)
Test data (Dữ liệu thử)
Dữ liệu thử là thành phần cốt lõi nhằm đảm bảo tính hiệu quả của việc chạy thử chương trình. Nó bao gồm 2 nhiệm vụ:
Chọn bộ dữ liệu thử đầu vào
Xác định kết quả mong đợi ở đầu ra.
Các loại dữ liệu thử:
Dữ liệu tự tạo: Tự tạo theo cách thủ công hoặc dùng bộ ngẫu nhiên
Dữ liệu sửa từ dữ liệu thật
Dữ liệu sống thực sự (Live data).
1.6 Gỡ rối chương trình (Debugging)
Gỡ lỗi và chạy thử luôn song hành cùng nhau, gỡ lỗi là quá trình phát hiện ra nguồn gốc việc gây lỗi trong chạy thử chương trình.
Các phương pháp gỡ lỗi:
Gỡ lỗi riêng lẻ: Người lập trình làm việc một mình để tìm ra lỗi.
Gỡ lỗi theo nhóm: Một nhóm người lập trình cùng tập trung trong rà soát mã nguồn để tìm ra nguyên nhân gây lỗi.
Gỡ lỗi tổng hợp: Chương trình giao cho nhiều người, kết quả sẽ được tập hợp lại.
Các công cụ gỡ lỗi:
In mã nguồn
Dựa vào đặc tả chi tiết của chương trình
Dựa vào flowchart
In kết quả đầu ra.
Dò theo từng câu lệnh và xem giá trị các biến
Tự động chỉ ra manh mối và loại lỗi.
1.7 Các giai đoạn trong chu trình sống của một hệ thống
Dự định ban đầu
Nghiên cứu tính khả thi
Phân tích yêu cầu của người sử dụng
Phân tích hệ thống
Đặc tả hệ thống
Thiết kế hệ thống
Phát triển hệ thống
Chạy thử
Triển khai
Bảo trì
Nhận xét đánh giá.
1.8 Lập trình hướng đối tượng (OOP) và C++
Tính trừu tượng (Abstraction)
Lọc ra các đặc tính chính trong khi loại bỏ những cái không cần thiết
Sự đóng gói (Encapsulation)
ẩn và bảo vệ các các dữ liệu quan trọng thông qua một giao diện có điều khiển
Tính modun hoá (Modularity)
Chia đối tượng thành các modun nhỏ hơn cho dễ hiểu và dễ thao tác.
Sự phân cấp (hierachy)
Sắp xếp tôn ti trật tự cho các đối tượng dựa trên mối quan hệ giữa chúng
1.8 Lập trình hướng đối tượng (OOP) và C++
Data abstraction:
Cho ta một định nghĩa về đối tượng
Ví dụ:
Người buôn xe ôtô nhìn xe với: Giá, thời hạn bảo hành, màu sắc,...
Người thợ máy thì nhìn xe với: Kích thước lọc dầu,loại bugi,...
Encapsulation:
Phân tích đối tượng thành các phần
Giấu đi hoặc bảo vệ các thông tin quan trọng
Cung cấp một giao diện cho phép truy cập vào các thuộc tính một cách an toàn.
Các thông tin nội bộ có thể bị thay đổi mà không làm ảnh hưởng đến các bộ phận khác.
Ví dụ - car radio
Giao diện gồm các núm điều khiển, antena, nguồn
Chi tiết hoạt động của nó người sử dụng không biết
Nhưng để lắp đặt và sử dụng cái đài thì hầu như ai cũng biết
1.8 Lập trình hướng đối tượng (OOP) và C++
Object-Oriented Programming
24
Chương 2
Hướng dẫn các bước lập trình với C++
Giảng viên : Phạm Doãn Tĩnh
Bộ môn : Điện tử tin học
Khoa : Điện tử - Viễn Thông
Trường : Đại học Bách khoa- Hà nội
2.1 Tạo lập và thực hiện một chương trình C++
Các công cụ có thể sử dụng trong khoá học này:
Turbo C++ 3.0 trở lên
Borland C++ 4.5 trở lên
Microsoft Visual C++ 98 (*)
Nên sử dụng Microsoft Visual C++ 98 vì nó chạy trên môi trường windows dễ sử dụng cũng như tính năng trong soạn thảo tốt và làm cơ sở để xây dựng các ứng dụng phức tạp (như lập trình mạng, kết nối CSDL,...).
-Khi tạo một Project mới:
+Chọn "Win32 console application"
+ Chọn "new" -> C++ source file
- Chạy chương trình nhấn ctrl+F5
Visual C++ IDE
// Program: Display greetings
// Author(s): Author name
// Date: 15-Aug-2004
#include
#include
using namespace std;
int main() {
cout << "Hello world!" << endl;
return 0;
}
A First Program - Greeting.cpp
Các chỉ dẫn
tiền xử lý
Insertion
statement
Kết thúc main() đồng thời kết thúc chương trình
Lời giải thích
Function
hàm main()
ám chỉ chương trình bắt đầu từ đây
Cho phép dễ dàng truy cập
Greeting Output
#include
using namespace std;
int main() {
// Extract length and width
cout << "Rectangle dimensions: ";
float Length;
float Width;
cin >> Length >> Width;
// Compute and insert the area
float Area = Length * Width;
cout << "Area = " << Area << " = Length "
<< Length << " * Width " << Width << endl;
return 0;
}
Nhập số liệu
Area.cpp
Area.cpp Output
Object-Oriented Programming
31
Chương 3
Cơ sở lập trình
với ngôn ngữ C
Giảng viên : Phạm Doãn Tĩnh
Bộ môn : Điện tử tin học
Khoa : Điện tử - Viễn Thông
Trường : Đại học Bách khoa- Hà nội
Giới thiệu vài nét về ngôn ngữ lập trình C
Vào đầu những năm 1970 Dennis Ritchie tại phòng thí nghiệm Bell đã xây dựng ngôn ngữ lập trình C khi cùng Ken Thompson xây dựng hệ điều hành Unix, khởi đầu C được dùng trên UNIX.
Lý do khiến C trở nên phổ biến là do:
C có lượng từ khoá ít.
Là ngôn ngữ nền cho hệ điều hành (Unix).
Nó đã được chuẩn hoá (ANSI C).
Là ngôn ngữ mạnh và hiệu quả.
Nó là cơ sở cho các ngôn ngữ C++ và Java
Một chương trình C tiêu biểu gồm có các phần sau:
Các lệnh tiền xử lý (Preprocessor commands)
Các định nghĩa kiểu (Type definition)
Các nguyên mẫu hàm (Function prototype)
Các biến (variables)
Các hàm
Đặc biệt chú ý là phải có một hàm tên là main()
Ví dụ:
#include
void main()
{
printf("Chuong trinh dau tien ");
}
3.1 Cấu trúc của chương trình C
Chỉ dẫn tiền xử lý: sử dụng thư viện vào ra chuẩn
Hàm chương trình chính, "void" ám chỉ không trả lại giá trị
Lệnh in một xâu ký tự ra màn hình
Kết thúc mỗi lệnh dùng dấu ";"
3.2 Mô tả ngôn ngữ
3.2.1 Định danh và từ khoá (identifier & keyword)
Các ký tự cơ bản được sử dụng trong chương trình C:
Các chữ in thường (Lower case): a b c . z
Các chữ in hoa (Upper case) : A B C . Z
Các chữ số (Digits) : 0 1 2 . 9
Các ký tự khác:
+ - * / ( ) { } [ ] < > ` " ! # $ % ^ ~ & | ; : , . / ?
Các từ khoá
auto do goto signed unsigned
break double if sizeof void
case else int static volatile
char enum long struct while
const extern register switch continue
float return typedef default for
short union
3.2.1 Định danh và từ khoá (identifier & keyword) (cont)
Định danh - tên (identifier):
Được tạo nên từ chuỗi các chữ cái, chữ số và dấu gạch dưới _
Tên phân biệt hoa thường
Bắt đầu bằng một chữ cái hoặc dấu gạch dưới _
Tên phải duy nhất
Không được sử dụng từ khoá
Độ dài tên phụ thuộc hệ thống (cho phép đến hơn 31 ký tự).
Nguyên tắc đặt tên sao cho dễ hiểu.
Ví dụ: my_name, _your_name, field01
Lời giải thích (Comment)
Trong C, lời giải thích nhằm làm sáng sủa hơn ý nghĩa của các câu lệnh hay một khối lệnh của chương trình.
Lời giải thích được bắt đầu bằng /* và kết thúc bằng */, ví dụ:
/* Lệnh sau in ra màn hình dòng chữ "Hello, world! " */
printf( "Hello, world! ");
3.2.3 Các kiểu dữ liệu
Cách khai báo, viết biểu thức và phép gán.
Các ký tự và kiểu char
Kiểu dữ liệu int
Các kiểu nguyên short, long và unsigned
Kiểu dấu phảy động (float)
Cách khai báo typedef và sizeof
Các hàm toán học
3.2.3.1 Cách khai báo, viết biểu thức và phép gán
Trong C, tất cả các biến đều nên khai báo ở đầu file, hàm, hoặc khối lệnh.
#include
#include
void main()
{
int a,b,c;
char x,y;
...
}
Trong C, một khối lệnh được đặt trong cặp dấu { }
Các biến được khai báo trong một khối thì chỉ có hiệu dụng trong khối đó.
Một biểu thức là sự kết hợp: Các hằng, các biến, các toán tử, và các lời gọi hàm. Hầu hết các biểu thức có trả về giá trị.
ví dụ: a+b; c=x*y +z;
Biểu thức có thể được gán cho một biến
3.2.3.2 Xâu kí tự và kiểu char
Kiểu char chiếm 01 byte trong bộ nhớ máy tính, do đó chúng lưu trữ được tối đa 256 giá trị phân biệt.
Kiểu char được dùng để lưu trữ các chữ cái, các chữ số, các dấu chấm câu cũng như các kí tự đặc biệt.
Kiểu hằng kí tự được đặt trong dấu nháy đơn `, ví dụ như `A`, `1`,`N`,...
Các kí tự điều khiển (bảng bên)
Meaning uses ASCII
Alert a 7
Backslash \ 92
Backspace 8
Carriage return 13
Double quote " 34
Form-feed f 12
Horizontal tab 9
New-line 10
Null character 0
Single quote ` 39
Vertical tab v 11
Question mark ? 63
Nhập số liệu kiểu char và hiển thị trên màn hình?
Để nhập số liệu kiểu char, ta có thể sử dụng các hàm trong thư viện
char getch() trả về 1 ký tự từ bàn phím nhưng kô hiển thị trên màn hình.
char getche() trả về 1 ký tự từ bàn phím nhưng có hiển thị trên màn hình.
Để in 1 ký tự trên màn hình, ta dùng định dạng %c, để in dưới dạng hexa dùng %x, để in dưới dạng số dùng %d
NgoàI ra ta còn có thể sử dụng hàm putch(char)
3.2.3.2 Xâu kí tự và kiểu char
Một số ví dụ:
printf("%c", `a`); /* cho ra tiếng bíp */
printf(""Book on C" is published"); /* In ra xâu "Book on C" is published */
printf("`Book on C` is published"); /* In ra xâu `Book on C` is published */
char c=`a`;
printf("%c", c); /*In ra màn hình kí tự a */
printf("%b", c); /* in ra màn hình số thứ giá trị trong bảng ascii 97 */
printf("%c%c%c, c, c+1, c+2); /* In ra màn hình a, b, c */
3.2.3.3 Kiểu nguyên (integer)
Kiểu nguyên có thể là 2 bytes (short) hoặc 4 bytes (long)
Hậu tố cho các số nguyên như sau:
Nhập số liệu kiểu nguyên và hiển thị giá trị nguyên trên màn hình
Để nhập giá trị nguyên ta dùng hàm scanf() trong thư viện
cú pháp:
scanf("Định dạng", &bien1, &bien2, .);
Nếu muốn nhập số liệu vào từ 1 xâu, ta sử dụng
sscanf(Xau,"Định dạng", &bien1, &bien2,.)
Ví dụ:
char *s="125";
int i;
sscanf(s,"%d",&i);
printf("i=%d ",i); /* KQ: i=125 */
Ngoài ra ta có thể dùng định dạng %nd với n là số vị trí cần in ra trên màn hình, nếu n lớn hơn độ dài cần in thì các ký tự trắng sẽ tự động được chèn vào phía trước.
3.2.3.4 Kiểu dấu phảy động (floating point)
Hậu tố cho các số dấu phảy động:
Mỗi số dấu phảy động được cấu thành từ 4 phần:
Phần nguyên
Dấu phảy
Phần thập phân
và phần mũ
Ví dụ: 33.777e-22
Nhập số dấu phảy động và hiển thị trên màn hình
Để nhập số dấu phảy động ta dùng hàm scanf() trong thư viện
cú pháp:
scanf("Định dạng", &bien1, &bien2, .);
Nếu muốn nhập số liệu vào từ 1 xâu, ta sử dụng
sscanf(Xau,"Định dạng", &bien1, &bien2,.)
Ví dụ:
char *s="125.788";
double f;
sscanf(s,"%f",&f);
printf("f=%10.3f ",i); /* KQ: f=125.788 */
3.2.3.5 Cách khai báo typedef và hàm sizeof()
Từ khoá "typedef" cho phép người lập trình khai báo một cách rõ ràng cho các tên mới, nó làm chương trình sáng sủa và dễ đọc hơn.
typedef char uppercase;
typedef int INCHES, FEET;
typedef unsigned long size_t;
uppercase u; /* sử dụng khai báo trên */
INCHES length, width;
Hàm sizeof() cho ta biết thông tin về một kiểu dữ liệu nào đó (kích thước)
/* Compute the size of some fundamental types. */
#include
int main(void) {
printf("The size of some fundamental types is computed. ");
printf(" char:%3d byte ",sizeof(char));
printf(" short:%3d bytes ",sizeof(short));
printf("int:%3d bytes ",sizeof(int));
printf(" long:%3d bytes ",sizeof(long));
printf(" unsigned:%3d bytes ",sizeof(unsigned));
printf(" float:%3d bytes ",sizeof(float));
printf(" double:%3d bytes ",sizeof(double));
printf("long double:%3d bytes ",sizeof(long double));
return 0; }
3.2.3.6 Các hàm toán học
Trong C, các hàm hàm toán học sẵn có trong thư viện "math.h", chẳng hạn như:
double sqrt(double): hàm khai căn
double pow(double,double): hàm luỹ thừa
double exp(double): Hàm mũ
double log(double): hàm logarit
...
#include
#include
int main(void)
{
double x;
printf(" %s %s %s ",
"The square root of x and x raised",
"to the x power will be computed.",
"---");
while (1)
{
/* do it forever, endless loop */
printf("Input x: ");
scanf("%lf", &x);
if (x >= 0.0)
printf(" %15s%22.15e %15s%22.15e %15s%22 .15e ",
"x = ", x,
"sqrt(x) = ",sqrt(x),
"pow(x, x) = ",pow(x, x));
else
printf(" Sorry, your number must be nonnegative. ");
}
return 0;
}
3.2.3.6 Các hàm toán học (tiếp)
Bài tập
Cho hàm số:
Hãy viết 1 chương trình C nhập vào x, n (n nguyên) và tính f(x)?
#include
#include
void main()
{ double tu,mau;
float x;
int n;
printf("Nhap vao x:"); scanf("%f",&x);
printf("Nhap vao n:"); scanf("%d",&n);
tu=5*powl(x,7)*powl(x,5/n);
mau=(6*powl(x,3)+powl(x,n));
printf("f(x)=%10.10f ",tu/mau);
}
3.2.4 Các kiểu hằng
Hằng ký tự (char) được biểu diễn trong cặp dấu nháy đơn ``, ví dụ: `a`,`G`,...
Hằng nguyên được biểu diễn giống trong toán học, ví dụ 125, -56, 90
Các hằng dấu phảy động được biểu diễn theo hai cách:
Giống toán học thông thường: 12.56, 28.067
Theo khoa học: 12.34e+2
Các hằng xâu ký tự được biểu diễn trong cặp dấu nháy kép " ", khi hằng quá dài để viết trên nhiều dòng thì dùng dấu để nối dòng, ví dụ:
"Day la mot hang xau ky tu"
"Day la hang xau voi
2 dong "
Để khai báo hằng chúng ta sử dụng cú pháp:
const Kiểu Tên_Hằng=Giá_Trị;
VD: const float PI=3.14;
3.3 Các toán tử
Các toán tử toán học như:
+ phép cộng
- phép trừ
* phép nhân
/ phép chia
% phép lấy phần dư, ví dụ 8 % 3 sẽ cho ta 2.
Các thao tác theo bit
& phép và theo bit (AND), VD 0xFF & 0xF1 -> 0xF1
| Hoặc theo bit (OR), VD 0x0F | 0xF1 -> 0xFF
^ Hoặc loại trừ (XOR), VD 0xFF ^ 0xF1 -> 0x0E
~ Lấy phần bù theo bit, VD ~0 -> 1
<< Phép dịch trái, VD 0x01 << 1 -> 0x02
>> Phép dịch phải, VD 0xFF >> 2 -> 0x3F
3.3 Các toán tử
Giá trị logic là đúng - true (1) hoặc sai - false (0)
Các phép toán so sánh (có thứ tự ưu tiên thấp hơn các phép toán số học)
Các phép toán logic
Phép phủ định một ngôi !, ví dụ 3> 7 cho giá trị 0, !(3 >7) cho giá trị 1
Phép và (AND) &&, ví dụ (3>7) && (5 > 0) cho giá trị 0
Phép hoặc (OR) ||, ví dụ (3>7) || (5 > 0) cho giá trị 1
Thứ tự ưu tiên của các phép toán như sau: ! , > >= < <=, == !=, && ||
3.3 Các toán tử
Các toán tử tăng giảm (increment and decrement operators)
Chúng được sử dụng để tăng hoặc giảm giá trị của một biến lên hoặc xuống 1 đơn vị.
Chúng có thể được sử dụng dưới dạng postfix hoặc prefix.
Cú pháp:
ten_bien++, ++ten_bien
ten_bien--, --ten_bien
Dù ở trước hay sau thì giá trị của biến đều tăng lên 1 đơn vị.
Chúng có mức độ ưu tiên cao trong một biểu thức.
Sự khác nhau cơ bản trong postfix và prefix thể hiện qua ví dụ sau
#include
void main() {
int a,b,c=0;
a=++c; b=c++;
printf("Gia tri cua a=%d, b=%d, c=%d", a,b,++c); }
Cho ta kết quả:
Gia tri cua a=1, b=1, c=3
3.3 Các toán tử
Trong C, toán tử gán được sử dụng là "=" khác với PASCAL là ":="
Ten_bien=bieu_thuc;
Ten_bien=gia_tri;
Ngoài ra trong C còn cho phép ta gán cùng một giá trị cho nhiều biến cùng một lúc
Ví dụ:
int a,b,c,d; a=b=c=d=100;
a=(b+2)+(c=3); /* tuong duong voi b=2; c=3; a=b+c; */
Các phương pháp gán khác:
Cú pháp:
Ten_bien Toan_tu= bieu_thuc; tương đương với
Ten_bien= Ten_bien Toan_tu Bieu_thuc;
+= -= *= /= %=
>>= <<= &= ^= |=
Ví dụ: j +=3; /* tuong duong j=j+3; */
Biểu thức điều kiện (?):
Cú pháp: s=ex1 ? gt1:gt2;
Nếu ex1 nhận giá trị đúng (1- true) thì s nhận gt1 nếu không s nhận gt2.
3.3 Các toán tử
Trong C dấu "," cũng được xem như một toán tử, toán tử này có trình tự ưu tiên thấp nhất.
Ví dụ int a,b=0,c;
a=100,b=200;
Trình tự ưu tiên của các toán tử như sau (Từ trên xuống, từ trái qua phải)
() [] ->> .
- + ++ -- ! ~ * & sizeof (type)
* / % + -
<< >>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %= &= ^= |= <<= >>=
,
3.3 Các toán tử
Chuyển đổi kiểu (type casting)
Trong C, việc chuyển đổi kiểu khá linh hoạt.
Cú pháp cho chuyển đổi kiểu như sau:
(type) (bieu_thuc);
#include
void main()
{
int a;
double b=10.1,c=20.55;
a=(int)(c-b);
printf("a=%d ",a);
}
Cho ta kết quả:
a=10
3.4 Các lệnh điều khiển chương trình
Lệnh if ... else
Lệnh switch ... case
Lệnh while(dieu_kien)...
Lệnh do ... while(dieu_kien)
Lệnh for ...
Lệnh break thoát một vòng lặp
Lệnh continue
Lệnh goto
3.4.1 Lệnh if
Cú pháp:
if ( expression )
stmt1;
hoặc
if ( expression )
stmt1;
else
stmt2;
Khi số câu lệnh trên mỗi nhánh rẽ lớn hơn 1 thì đặt chúng trong cặp dấu { }
if ( c == `Y` )
{
printf( "Yes, " );
printf( "we have no bananas! " )`
bananas = 0;
}
if ( ( c >= `a` ) && ( c <= `z` ))
{
printf( "lower case " );
++lowers;
}
else if ( ( c >= `A` ) && ( c <= `Z` ))
{
printf( "upper case " );
++uppers;
}
else
{
++others;
}
3.4.2 Lệnh switch ... case
Câu lệnh switch sử dụng để chọn một từ vài nhánh rẽ dựa trên giá trị một biểu thức nào đó.
Cú pháp:
switch( expression )
{
case constant-expr1:
stmt;
break;
case constant-expr2:
stmt;
break;
. . .
default:
stmt
}
Chú ý: Nếu không có break sẽ dẫn đến các câu lệnh còn lại sẽ bị ảnh hưởng.
Ví dụ:
switch( c )
{
case `Y`:
printf( "Yes" );
break;
case `N`:
printf( "No" );
break;
default:
printf( "What?a" );
}
Bài tập
Viết 1 chương trình C, nhập vào tháng và năm và hiển thị trên màn hình số ngày trong tháng.
3.4.2 Lệnh switch ... case
Có thể dùng nhiều nhãn case cho cùng một nhánh:
switch( c )
{
case `Y`:
case `y`:
printf( "Yes" );
break;
case `N`: case `n`:
/* 2 ĐK Cùng dòng */
printf( "No" );
break;
default:
printf( "What?a" );
}
switch(month)
{
case 1:case 3: case 5: case 7:case 8:case 12:case 10:
printf("Thang 31 ngay! ");
break;
case 4:case 6:case 9:case 11:
printf("Thang 30 ngay! ");
break;
case 2:
if ((year % 4) ==0)
printf("Thang 29 ngay! ");
else
printf("Thang 28 ngay! ");
break;
}
3.4.3 Lệnh while ...
Câu lệnh while được sử dụng để lặp lại một lệnh hoặc khối lệnh khi biểu thức logic đúng.
Cú pháp:
while ( expression )
stmt ;
Ví dụ
x = 1;
while ( (x * 5) >= (x * x) )
{
printf( "%d %d %d ", x, x*5, x*x );
x++;
}
Với câu lệnh này thì lệnh (khối lệnh) chỉ và chỉ được thực hiện khi expression là đúng!
3.4.4 Lệnh do ... while
Câu lệnh while được sử dụng để lặp lại một lệnh hoặc khối lệnh khi biểu thức logic đúng.
Cú pháp
do
stmt ;
while ( expression );
Ví dụ:
lng = 0;
do
{
c = getchar();
++lng;
}
while ( c != ` ` );
printf( "line length %d", lng );
3.4.5 Lệnh for (...)
Cú pháp:
for ( init-expr; cont-expr; loop-expr )
stmt;
Thực hiện:
Tính toán init_expr nếu có
Tính toán cont-expr nếu có
Nếu cont-expr là true hoặc bỏ qua thì stmt được thực hiện ít nhất 1 lần, rồi sau đó loop-expr sẽ được thực hiện.
Lặp lại 2 bước trên đến khi cont-expr là false.
9 times 0 is 0
9 times 1 is 9
9 times 2 is 18
9 times 3 is 27
9 times 4 is 36
9 times 5 is 45
9 times 6 is 54
9 times 7 is 63
9 times 8 is 72
9 times 9 is 81
/* Bảng cửu chương */
#define MAX 9
for ( i = 0; i <= MAX; i++ )
{
for ( j = 0; j <= MAX; j++ )
{
printf( "%d times %d is %d ", i, j, i*j );
}
}
printf( " " );
3.4.6 Lệnh break thoát một vòng lặp
Với các vòng lặp for, while, do ... while thì lệnh break thoát khỏi vòng lặp ở mức thấp nhất mà tại đó lệnh break xuất hiện!
Ví dụ:
int c,max=10;
printf( "Enter up to %d chars", max );
for ( i = 0; i < max; i++ )
{
c = getchar();
if ( c == EOF || c == ` ` )
{
break;
}
putchar( 255 - c ); /* encrypt char */
}
putchar( ` ` );
3.4.7 Lệnh goto chuyển điều khiển chương trình
Lệnh goto dùng để chuyển điều khiển của chương trình tới một nhãn (label) nào đó.
Cú pháp: goto label;
ở đây label có cú pháp:
Ten_label:
{
Khoi_lenh_cua_label;
}
Nói chung là nên hạn chế dùng lệnh này, vì nó là lệnh chuyển điều khiển phi cấu trúc.
#include
#include
void main()
{
int i,max=10,linelng;
char c;
printf( "Enter %d lines... ", max );
for ( i = 1; i <= max; i++ )
{
linelng = 0;
while ( ( c = getchar() ) != ` ` )
{
if ( c == EOF )
{
goto SickOfIt;
}
++linelng;
}
printf( "Length of line %d is %d ",
i, linelng );
}
SickOfIt:
printf( "All done... " );
}
Bài tập
1. Viết 1 chương trình C, nhập vào N số (N xác định bằng cách nhập từ bàn phím).
Tính giá trị trung bình của các số dương?
2. Viết 1 chương trình nhập vào 1 dãy các ký tự và đưa ra thống kê xem có bao nhiêu chữ cái, bao nhiêu chữ số, bao nhiêu ký tự đặc biệt?
3. Cho:
A(n)= 1+2 + 3 + 5 + 8 + ... an-2 + an-1 + an
Với a0 =1, a1 =2.
và an = an-2 + an-1
Viết 1 chương trình nhập vào n và hiển thị dãy số trên màn hình?
3.5 Mảng (array)
Mảng là một kiểu cấu trúc dữ liệu dùng lưu trữ nhiều phần tử dữ liệu cùng kiểu.
Khai báo giống như biến thông thường, trừ việc ta chỉ ra số chiều và số phần tử mảng.
Các phần tử có thể được khởi tạo giá trị ban đầu, khi được khởi tạo giá trị đầu, chiều đầu tiên có thể bỏ qua và để chương trình dịch tự tính.
Mỗi phần tử mảng được truy cập thông qua tên mảng và chỉ số phần tử (subscript).
3.5.1 Khai báo và khởi tạo mảng
Cú pháp:
data_type array_name[so_phan_tu];
Ví dụ:
int a[10]; /* Khai báo mảng 10 số nguyên */
char my_name[35]; /* Khai một xâu 35 ký tự */
Khi muốn khởi tạo (initialize) các phần tử mảng ta đưa các giá trị khởi tạo vào dấu {gt1,gt2,...,gtN }
Với phần tử chưa khởi tạo thì giá trị của nó bằng 0.
Khi được khởi tạo giá trị đầu, có thể bỏ tham số chiều (compiler sẽ tự động tính toán)
Ví dụ:
char whitesp[5] = {` `,` `,` `,` `,`f`}; /* Mảng chứa các ký tự trắng */
int prodcod[] = { 16, 60, 75, 101, 17 }; /* Mảng chứa các mã sản phẩm */
Ta có thể sử dụng sizeof() để xác định số phần tử mảng:
int tb3[] = { 10, 20, 30, 40, 95 }; /* khởi tạo mảng */
#define TB3_CT (sizeof(tb3)/sizeof(tb3[0]))
Trong đó sizeof(tb3) cho ta số bytes mà mảng chiếm chỗ, sizeof(tb3[0]) cho ta kích thước 1 phần tử .
3.5.2 Truy cập các phần tử mảng.
Các phần tử mảng được truy cập dùng cú pháp:
ten_mang[chi_so_phan_tu];
Chỉ số của phần tử đầu tiên là 0.
Ví dụ
int Larry[5] = { 5, 10, 15, 20, 25 };
int i, Curly; tot = 0;
Curly = Larry[0]; /* Curly <-- 5 *>Curly = Larry[3]; /* Curly <-- 20 *>Curly = Larry[4]; /* Curly <-- 25 *>i = 1;
Curly = Larry[i]; /* Curly <-- 10 *>Larry[0] = 30; /* Larry=30,10,15,20,25 */
/* sum and print all array elements */
for ( i = 0; i < 5; i++ )
{
printf( "%d", Larry[i] );
tot += Larry[i];
}
/* increment each array element */
for ( i = 0; i < 5; i++ )
{
++Larry[i];
}
3.5.3 Mảng nhiều chiều
Mảng nhiều chiều khai báo tương tự như mảng 1 chiều, chỉ có điều ta thêm chiều bằng các cặp dấu [].
Để truy cập ta dùng các chỉ số tương ứng.
Ví dụ:
/* Khai báo mảng 4 hàng, 3 cột */
int hah[4][3];
Sự phân bố vị trí trong bộ nhớ như hình vẽ bên.
Để duyệt mảng nhiều chiều dùng vòng lặp lồng nhau.
Để khởi tạo mảng nhiều chiều
int a[2][3]={{1,2,3},{4,5,6}};
#define NROWS 15 /* symbol for # rows */
#define NCOLS 24 /* symbol for # cols */
int i, j;
long mx[NROWS][NCOLS], totmx;
double pct[NROWS][NCOLS];
... /* Nhập mảng */
/* Tổng các PT mảng */
for ( i = 0; i < NROWS; i++ )
{
for ( j = 0; j < NCOLS; j++ )
{
totmx += mx[i][j];
}
}
/* compute pct of total for each */
if ( totmx != 0 )
{
for ( i = 0; i < NROWS; i++ )
{ for ( j = 0; j < NCOLS; j++ )
{pct[i][j] = mx[i][j] / totmx; }
}
}
3.6 Con trỏ (pointer)
Trong chương trình, mỗi biến chiếm một số bytes nhất định và lưu ở một vị trí cụ thể trong bộ nhớ máy tính.
Con trỏ thực chất là một loại biến đặc biệt được sử dụng để lưu địa chỉ một ô nhớ cụ thể nào đó hoặc lưu địa chỉ của một biến khác.
Khai báo:
Data_Type *pointer_var_name;
hoặc
Data_Type* pointer_var_name;
Để khởi tạo giá trị của con trỏ, ta có thể cho nó trỏ vào một địa chỉ nhớ cụ thể hoặc lấy địa chỉ của một biến khác thông qua toán tử lấy địa chỉ "&".
Để truy cập vào ô nhớ tại địa chỉ mà con trỏ đang trỏ tới dùng toán tử tham chiếu ngược *, với cú pháp:
*Ten_contro = gia_tri;
hoặc
ten_bien=*Ten_contro;
Ví dụ:
int *int_ptr; /* Khai báo con trỏ int */
float *float_ptr; /* Con trỏ float */
int a;
char b;
int *ip=&i;
char *cp=&b;
int i=3, j=5, *p=&i, *q=&j, *r;
double x;
p==&i p==(&i) 1
**&p *(*&p) 3
r=&x r=(&x) illegal
7**p/*q+7 (((7*(*p)))/(*q)+7 11
*(r=&j)*=*p (*(r=(&j)))*=(*p) 15
3.6 Con trỏ (pointer) (tiếp)
Bên cạnh con trỏ xác định kiểu, ta còn có thể dùng con trỏ không xác định kiểu (void *) để lưu trữ địa chỉ của bất kỳ ô nhớ nào. Nhưng lưu ý với con trỏ này khi truy cập ô nhớ mà nó trỏ tới cần chuyển đổi kiểu tương ứng!
Ngoài ra ta còn có thể dùng các phép toán số học đối với con trỏ.
int *p1;
char *p2;
float *p3;
++p1; /* p1 tăng lên 4~4 bytes */
++p2; /* p2 tăng lên 1~1 byte */
++p3; /* p3 tăng lên 4~4 bytes */
#include
void main()
{
short i=10, *p1=&i;
char c=`A`,*p2=&c;
float f=100.8,*p3=&f;
printf("p1=%p p2=%p p3=%p ",p1,p2,p3);
printf("++p1=%p ++p2=
%p --p3=%p ",++p1,++p2,--p3);
}
3.7 Mối liên hệ giữa con trỏ và mảng
Bản thân tên mảng là địa chỉ của phần tử đầu tiên trong mảng
Ví dụ:
int a[100],*p;
Khi đó a[i] *(a+i)
p=a+1
p=&a[1];
#define N 100
int a[N], i, *p, sum=0;p=a;
p=&a[0];
for (p=a;p<&a[N]; p++) for (i=0;i
for (i=0;i
3.8 Cấu trúc struct
Để khai báo cấu trúc ta dùng cú pháp:
struct struct_name
{
type1 field1;
type2 field2;
...
} [bien_co_kieu_struct_name];
Để truy cập đến các thuộc tính của struct ta sử dụng toán tử "."
Ta có thể khởi tạo giá trị cho một biến struct giống như đối với mảng , đặt các giá trị trong cặp dấu { } phân cách giá trị bằng dấu ","
#include
struct emp
{
int empno;
char ename[35];
};
void main()
{
struct emp e1={100,"Nguyen X"};
printf("ENo:%d, Ename: %s ",e1.empno,e1.ename);
}
3.9 Hợp Union
Với cấu trúc struct, mỗi trường chiếm một vị trí nhớ khác nhau, đối với union chúng chia sẻ cùng một vùng nhớ.
Cú pháp khai báo:
union union_name
{
Type1 field1;
Type2 field2;
...
}
* Define a variable to hold an integer or
* a real number (but not both)
union value {
long int i_value; /* The real number */
float f_value; /* The floating-point number */
} data;
int i; /* Random integer */
float f; /* Random floating-point number */
void main()
{
data.f_value = 5.0;
data.i_value = 3; /* data.f_value overwritten */
i = data.i_value; /* legal */
f = data.f_value; /* not legal, will generate unexpected results */
data.f_value = 5.5; /* put something in f_value/clobber i_value */
i = data.i_value; /* not legal, will generate unexpected results */
}
3.10 lệnh typedef
typedef cho phép ta định nghĩa một kiểu dữ liệu mới cho C.
Cú pháp:
typedef kieu_dang_co kieu_moi;
Ví dụ
main()
{
typedef int group[10]; /* Tạo kiểu mới "group" */
group totals; /* Dùng kiểu mới cho biến totals */
for (i = 0; i < 10; i++)
totals[i] = 0;
return (0);
}
3.11 kiểu enum
enum được dùng cho các biến mà sẽ chỉ nhận một số giá trị nhất định, các giá trị được liên hệ đến thông qua tên.
typedef int week_day;
/* define the type for week_days */
const int SUNDAY = 0;
const int MONDAY = 1;
const int TUESDAY = 2;
const int WEDNESDAY = 3;
const int THURSDAY = 4;
const int FRIDAY = 5;
const int SATURDAY = 6;
/* now to use it */
week_day today = TUESDAY;
enum week_day {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
FRIDAY, SATURDAY};
/* now use it */
enum week_day today = TUESDAY;
3.12 Bit Fields và mảng cấu trúc
struct item {
unsigned int list:1; /* true if item is in the list */
unsigned int seen:1; /* true if this item has been seen */
unsigned int number:14; /* item number */
};
Ta có thể tạo một mảng gồm 10 phần tử có kiểu là cấu trúc item:
struct item mang_ct[10];
Trong C, việc kết hợp cấu trúc với con trỏ sẽ cho phép ta tạo ra những cấu trúc dữ liệu rất mạnh trong lập trình:
struct linked_list
{
int node_data;
struct linked_list * next;
};
3.13 Hàm (function)
Trong C, tất cả các chương trình con đều được coi là hàm.
Có 2 loại hàm: trả lại giá trị và không trả lại giá trị (void).
Để khai báo 1 hàm trong C, dùng cú pháp sau:
Kieu_Tra_lai ten_ham(tham_so)
{
/* Neu tra lai gia tri co them return (giatri); */
}
Ví dụ:
int cong_so(int a,int b)
{
return(a+b);
}
Trong C, các tham số khi truyền vào hàm thường là qua giá trị sao chép, do vậy cho dù trong hàm có làm thay đổi giá trị của nó thì khi kết thúc hàm, giá trị của nó vẫn không thay đổi.
Trong trường hợp muốn thay đổi giá trị của tham số khi thoát khỏi hàm, ta phải khai báo tham số gọi qua tham chiếu địa chỉ (&) hoặc dùng con trỏ!
3.13 Hàm (function)
Giả sử trong ví dụ sau, ta muốn tăng giá trị tham số thứ nhất lên 1, tham số 2 lên 2 đơn vị khi kết thúc hàm thì hàm cong_so_1 sẽ cho ta điều mong muốn.
void main()
{
int a=10,b=20,c;
c=cong_so(a,b);
printf("a=%d,b=%d ",a,b);
c=cong_so_1(a,b);
printf("a=%d,b=%d ",a,b);
c=cong_so_2(&a,&b);
printf("a=%d,b=%d ",a,b);
}
#include
int cong_so(int a,int b)
{
a++;b+=2;
return(a+b);
}
int cong_so_1(int &a,int &b)
{
a++;b+=2;
return(a+b);
}
int cong_so_2(int *a,int *b)
{
(*a)++;(*b)+=2;
return(*a+*b);
}
Cho ta kết quả như sau:
a=10,b=20
a=11,b=22
a=12,b=24
Truyền tham số mảng
Để truyền tham số có kiểu mảng, ta dùng cú pháp
Kieu_Tra_Ve Ten_Ham(Kieu_PT_Mang a[] ,...)
Ví dụ:
/* Hàm sắp xếp 1 mảng nguyên a gồm N phần tử */
void SX_NoiBot(int a[], int N)
{
int i,j,tmp;
for(i=0;i
{ tmp=a[j];a[j]=a[j+1];a[j+1]=tmp;}
}
void main()
{ int a[10]={9,2,7,4,3,6,1,12,8,5}, i;
SX_NoiBot(a,10);
for(i=0;i<10;i++) printf("%3d",a[i]);
}
3.13 Hàm (function)
Ngoài cách dùng hàm thông thường đã biết, ta còn có thể dùng hàm dưới dạng con trỏ tới hàm.
Cách này thường được dùng trong trường hợp ta cần lập trình gọi hàm một cách tổng quát.
Ví dụ:
#include
#include
double dien_tich_hinh_tron(float bk)
{
return(3.14*bk*bk);
}
typedef double (*fptr)(float);
void main()
{
fptr x=dien_tich_hinh_tron;
printf("%f ",x(2));
}
Trong C, hàm còn có thể có tính đệ quy (recursive): Một hàm có thể có lời gọi đến chính nó.
Ví dụ: Tính giai thừa của một số N
#include
#include
long giai_thua(int N)
{
return(N<=1? 1:N * giai_thua(N-1));
}
void main()
{
printf("4!=%d ", giai_thua(4));
}
3.13 Hàm (function)-Các tham số cho hàm main()
C cung cấp cho ta một cách để truyền tham số cho chương trình khi ta chạy chương trình thông qua các tham số của hàm main()
cú pháp như sau:
main( int argc, char *argv[] )
Trong đó:
"argc" là số tham số
"argv[]" là mảng chứa giá trị các tham số.
Nhưng argv[0] là tên của chương trình, như vậy giá trị tham số bắt đầu từ argv[1].
Ví dụ:
#include
main( int argc, char *argv[] )
{
if( argc == 2 )
printf("The argument supplied is %s ", argv[1]);
else if( argc > 2 )
printf("Too many arguments supplied. ");
else
printf("One argument expected. ");
}
3.13 Hàm (function)- Gọi các chương trình ngoài
Ta có thể thực hiện các lệnh của hệ điều hành thông qua lời gọi hệ thống.
Để thực hiện, ta dùng thư viện hàm
system("OS command");
Ví dụ:
#include
main() /* SYS.C */
{
char *command = "dir";
system( "cls" );
system( command );
}
3.14 Vào/ra với C
Trong C, stdio.h là thư viện hàm cho vào ra. Trong đó ta sử dụng một số hàm thông dụng như:
printf("format",args) để kết xuất dữ liệu.
scanf("format",args) để nhập số liệu từ bàn phím.
Ngoài ra, ta có thể dùng hàm gets(char *s) để nhập một xâu ký tự từ bàn phím.
Chú ý: Vào ra với C, cần lưu ý đến bộ đệm bàn phím. Khi cần xoá bộ đệm ta dùng hàm:
fflush(stdin);
3.14 Vào/ra với C
để nhập m
* Một số tài liệu cũ có thể bị lỗi font khi hiển thị do dùng bộ mã không phải Unikey ...
Người chia sẻ: Đức Bình
Dung lượng: |
Lượt tài: 1
Loại file:
Nguồn : Chưa rõ
(Tài liệu chưa được thẩm định)