Bài giảng Ngôn ngữ lập trình C/C++ - Phạm Hồng Thái - Chương 4: Hàm và chương trình

Mọi chương trình trước khi chạy đều phải bố trí các biến do NSD khai báo vào đâu đó trong bộ nhớ. Để tạo điều kiện truy nhập dễ dàng trở lại các biến này, bộ nhớ được đánh số, mỗi byte sẽ được ứng với một số nguyên, được gọi là địa chỉ của byte đó từ 0 đến hết bộ nhớ. Từ đó, mỗi biến (với tên biến) được gắn với một số nguyên là địa chỉ của byte đầu tiên mà biến đó được phân phối. Số lượng các byte phân phối cho biến là khác nhau (nhưng đặt liền nhau từ thấp đến cao) tuỳ thuộc kiểu dữ liệu của biến (và tuỳ thuộc vào quan niệm của từng NNLT), tuy nhiên chỉ cần biết tên biến hoặc địa chỉ của biến ta có thể đọc/viết dữ liệu vào/ra các biến đó. Từ đó ngoài việc thông qua tên biến chúng ta còn có thể thông qua địa chỉ của chúng để truy nhập vào nội dung. Tóm lại biến, ô nhớ và địa chỉ có quan hệ khăng khít với nhau. C++ cung cấp một toán tử một ngôi & để lấy địa chỉ của các biến (ngoại trừ biến mảng và xâu kí tự). Nếu x là một biến thì &x là địa chỉ của x.

doc62 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 2877 | Lượt tải: 1download
Tóm tắt nội dung Bài giảng Ngôn ngữ lập trình C/C++ - Phạm Hồng Thái - Chương 4: Hàm và chương trình, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
, vì nó có thể gây nên những hiệu ứng phụ khó kiểm soát.
Các chỉ thị biên dịch có điều kiện #if, #ifdef, #ifndef
Chỉ thị:
#if dãy lệnh … #endif
#if dãy lệnh … #else dãy lệnh … #endif, 
Các chỉ thị này giống như câu lệnh if, mục đích của nó là báo cho chương trình dịch biết đoạn lệnh giữa #if (điều kiện ) và #endif chỉ được dịch nếu điều kiện đúng. Ví dụ: 
const int M = 1;
void main() {
int i = 5;
#if M==1
cout << i ;
#endif
}
hoặc:
const int M = 10;
void main() {
int i = 5;
#if M > 8
cout << i+i ;
#else
cout << i*i ;
#endif
}
Chỉ thị #ifdef và #ifndef
Chỉ thị này báo cho chương trình dịch biết đoạn lệnh có được dịch hay không khi một tên gọi đã được định nghĩa hay chưa. #ifdef được hiểu là nếu tên đã được định nghĩa thì dịch, còn #ifndef được hiểu là nếu tên chưa được định nghĩa thì dịch. Để định nghĩa một tên gọi ta dùng chỉ thị #define tên.
Chỉ thị này đặc biệt có ích khi chèn các tệp thư viện vào để sử dụng. Một tệp thư viện có thể được chèn nhiều lần trong văn bản do vậy nó có thể sẽ được dịch nhiều lần, điều này sẽ gây ra lỗi vì các biến được khai báo nhiều lần. Để tránh việc này, ta cần sử dụng chỉ thị trên như ví dụ minh hoạ sau: Giả sử ta đã viết sẵn 2 tệp thư viện là mylib.h và mathfunc.h, trong đó mylib.h chứa hàm max(a,b) tìm số lớn nhất giữa 2 số, mathfunc.h chứa hàm max(a,b,c) tìm số lớn nhất giữa 3 số thông qua sử dụng hàm max(a,b). Do vậy mathfunc.h phải có chỉ thị #include mylib.h để sử dụng được hàm max(a,b). 
Thư viện 1. tên tệp: MYLIB.H
int max(int a, int b)
{
	return (a>b? a: b);
}
Thư viện 2. tên tệp: MATHFUNC.H
#include "mylib.h"
int max(int a, int b)
{
	return (a>b? a: b);
}
Hàm main của chúng ta nhập 3 số, in ra max của từng cặp số và max của cả 3 số. Chương trình cần phải sử dụng cả 2 thư viện.
#include "mylib.h"
#include "mathfunc.h"
main()
{
	int a, b, c;
	cout > a >> b >> c;
	cout << max(a,b) << max(b,c) << max(a,c) << max(a,b,c) ;
}
Trước khi dịch chương trình, bộ tiền xử lý sẽ chèn các thư viện vào trong tệp chính (chứa main()) trong đó mylib.h được chèn vào 2 lần (một lần của tệp chính và một lần của mathfunc.h), do vậy khi dịch chương trình, C++ sẽ báo lỗi (do hàm int max(inta, int b) được khai báo hai lần). Để khắc phục tình trạng này trong mylib.h ta thêm chỉ thị mới như sau: 
// tệp mylib.h
#ifndef _MYLIB_	// nếu chưa định nghĩa tên gọi _MYLIB_
#define _MYLIB_	// thì định nghĩa nó
int max(int a, int b)	// và các hàm khác
{
	return (a>b? a: b);
}
#endif
Như vậy khi chương trình dịch xử lý mylib.h lần đầu do _MYLIB_ chưa định nghĩa nên máy sẽ định nghĩa từ này, và dịch đoạn chương trình tiếp theo cho đến #endif. Lần thứ hai khi gặp lại đoạn lệnh này do _MYLIB_ đã được định nghĩa nên chương trình bỏ qua đoạn lệnh này không dịch.
Để cẩn thận trong cả mathfunc.h ta cũng sử dụng cú pháp này, vì có thể trong một chương trình khác mathfunc.h lại được sử dụng nhiều lần.
Bài tẬp
Con trỏ
Hãy khai báo biến kí tự ch và con trỏ kiểu kí tự pc trỏ vào biến ch. Viết ra các cách gán giá trị ‘A’ cho biến ch. 
Cho mảng nguyên cost. Viết ra các cách gán giá trị 100 cho phần tử thứ 3 của mảng.
Cho p, q là các con trỏ cùng trỏ đến kí tự c. Đặt *p = *q + 1. Có thể khẳng định: *q = *p - 1 ?
Cho p, q là các con trỏ trỏ đến biến nguyên x = 5. Đặt *p = *q + 1; Hỏi *q ?
Cho p, q, r, s là các con trỏ trỏ đến biến nguyên x = 10. Đặt *q = *p + 1; *r = *q + 1; *s = *r + 1. Hỏi giá trị của biến x ?
Chọn câu đúng nhất trong các câu sau: 
A: Địa chỉ của một biến là số thứ tự của byte đầu tiên máy dành cho biến đó. 
B: Địa chỉ của một biến là một số nguyên.
C: Số học địa chỉ là các phép toán làm việc trên các số nguyên biểu diễn địa chỉ của biến 
D: a và b đúng
Chọn câu sai trong các câu sau: 
A: Các con trỏ có thể phân biệt nhau bởi kiểu của biến mà nó trỏ đến. 
B: Hai con trỏ trỏ đến các kiểu khác nhau sẽ có kích thước khác nhau.
C: Một con trỏ kiểu void có thể được gán bởi con trỏ có kiểu bất kỳ (cần ép kiểu).
D: Hai con trỏ cùng trỏ đến kiểu cấu trúc có thể gán cho nhau.
Cho con trỏ p trỏ đến biến x kiểu float. Có thể khẳng định ? 
A: p là một biến và *p cũng là một biến
B: p là một biến và *p là một giá trị hằng
C: Để sử dụng được p cần phải khai báo float *p; và gán *p = x;
D: Cũng có thể khai báo void *p; và gán (float)p = &x;
Cho khai báo float x, y, z, *px, *py; và các lệnh px = &x; py = &y; Có thể khẳng định ?
A: Nếu x = *px thì y = *py	B: Nếu x = y + z thì *px = y + z
C: Nếu *px = y + z thì *px = *py + z	D: a, b, c đúng
Cho khai báo float x, y, z, *px, *py; và các lệnh px = &x; py = &y; Có thể khẳng định ? 
A: Nếu *px = x thì *py = y	B: Nếu *px = *py - z thì *px = y - z
C: Nếu *px = y - z thì x = y - z	D: a, b, c đúng
Không dùng mảng, hãy nhập một dãy số nguyên và in ngược dãy ra màn hình.
Không dùng mảng, hãy nhập một dãy số nguyên và chỉ ra vị trí của số bé nhất, lớn nhất.
Không dùng mảng, hãy nhập một dãy số nguyên và in ra dãy đã được sắp xếp.
Không dùng mảng, hãy nhập một dãy kí tự. Thay mỗi kí tự ‘a’ trong dãy thành kí tự ‘b’ và in kết quả ra màn hình.
Con trỏ và xâu kí tự 
Giả sử p là một con trỏ kiểu kí tự trỏ đến xâu "Tin học". Chọn câu đúng nhất trong các câu sau: 
A: cout << p sẽ in ra dòng "Tin học"	B: cout << p sẽ in ra dòng "Tin học"
C: cout << p sẽ in ra chữ cái 'T'	D: b và c đúng
Xét chương trình (không kể các khai báo file nguyên mẫu): 
char st[] = "tin học"; 
main() {
char *p; p = new char[10]; 
for (int i=0; st[i] != '\0'; i++) p[i] = st[i]; 
} 
Chương trình trên chưa hoàn chỉnh vì: 
A: Sử dụng sai cú pháp toán tử new 
B: Sử dụng sai cú pháp p[i] (đúng ra là *(p+i))
C: Xâu p chưa có kết thúc
D: Cả a, b, c, đều sai
Để tính độ dài xâu một sinh viên viết đoạn chương trình sau:
char *st; 
main() 
{
int len = 0; gets(st); while (st++ != '\0') len++; printf("%d",len); 
}
Hãy chọn câu đúng nhất:
A: Chương trình trên là hoàn chỉnh	B: Cần thay len++ bởi ++len
C: Cần thay st++ bởi *st++	D: Cần thay st++ != '\0' bởi st++ == '\0'
Cho xâu kí tự (dạng con trỏ) s. Hãy in ngược xâu ra màn hình.
Cho xâu kí tự (dạng con trỏ) s. Hãy copy từ s sang xâu t một đoạn bắt đầu tại vị trí m với độ dài n.
Cho xâu kí tự (dạng con trỏ) s. Hãy thống kê tần xuất xuất hiện của các kí tự có trong s. In ra màn hình theo thứ tự giảm dần của các tần xuất (tần xuất là tỉ lệ % số lần xuất hiện của x trên tổng số kí tự trong s).
Hàm
Chọn câu sai trong các câu sau đây: 
A: Hàm không trả lại giá trị thì không cần khai báo kiểu giá trị của hàm.
B: Các biến được khai báo trong hàm là cục bộ, tự xoá khi hàm thực hiện xong
C: Hàm không trả lại giá trị sẽ có kiểu giá trị ngầm định là void.
D: Hàm là đơn vị độc lập, không được khai báo hàm lồng nhau.
Chọn câu đúng nhất trong các câu sau đây: 
A: Hàm phải được kết thúc với 1 câu lệnh return
B: Phải có ít nhất 1 câu lệnh return cho hàm
C: Các câu lệnh return được phép nằm ở vị trí bất kỳ trong thân hàm 
D: Không cần khai báo kiểu giá trị trả lại của hàm nếu hàm không có lệnh return
Chọn câu sai trong các câu sau đây: 
A: Số tham số thực sự phải bằng số tham số hình thức trong lời gọi hàm
B: Các biến cục bộ trong thân hàm được chương trình dịch cấp phát bộ nhớ
C: Các tham số hình thức sẽ được cấp phát bộ nhớ tạm thời khi hàm được gọi
D: Kiểu của tham số thực sự phải bằng kiểu của tham số hình thức tương ứng với nó trong lời gọi hàm
Để thay đổi giá trị của tham biến, các đối của hàm cần khai báo dưới dạng: 
A: biến bình thường và tham đối được truyền theo giá trị
B: biến con trỏ và tham đối được truyền theo giá trị 
C: biến bình thường và tham đối được truyền theo địa chỉ
D: biến tham chiếu và tham đối được truyền theo giá trị 
Viết hàm tìm UCLN của 2 số. áp dụng hàm này (AD: ) để tìm UCLN của 4 số nhập từ bàn phím. 
Viết hàm kiểm tra một số nguyên n có là số nguyên tố. AD: In ra các số nguyên tố bé hơn 1000.
Viết hàm kiểm tra một số nguyên n có là số nguyên tố. AD: In các cặp số sinh đôi < 1000. (Các số "sinh đôi" là các số nguyên tố mà khoảng cách giữa chúng là 2).
Viết hàm kiểm tra một năm có là năm nhuận. AD: In ra các năm nhuận từ năm 1000 đến 2000. 
Viết hàm xoá dấu cách đầu tiên trong một xâu. AD: Xoá tất cả dấu cách trong xâu.
Viết hàm thay 2 dấu cách bởi 1 dấu cách. AD: Cắt các dấu cách giữa 2 từ của một xâu về còn 1 dấu cách.
Viết hàm tráo đổi giá trị của 2 số. AD: sắp xếp dãy số.
Viết hàm giải phương trình bậc 2. Dùng chương trình con này tìm nghiệm của một phương trình chính phương bậc 4.
Số hoàn chỉnh là số bằng tổng mọi ước của nó (Ví dụ 6 = 1 + 2 + 3). Hãy in ra mọi số hoàn chỉnh từ 1 đến 100.
Tính tổng của dãy phân số. In ra màn hình kết quả dưới dạng phân số tối giản.
Nhập số tự nhiên chẵn n > 2. Hãy kiểm tra số này có thể biểu diễn được dưới dạng tổng của 2 số nguyên tố hay không ?.
In tổng của n số nguyên tố đầu tiên.
Tính phần diện tích giới hạn bởi hình tròn bán kính R và hình vuông ngoại tiếp của nó.
Chuẩn hoá một xâu (cắt kí tự trắng 2 đầu, cắt bớt các dấu trắng (chỉ để lại 1) giữa các từ, viết hoa đầu từ).
Viết chương trình nhập số nguyên lớn (không quá một tỷ), hãy đọc giá trị của nó bằng cách in ra xâu kí tự tương ứng với giá trị của nó. Ví dụ 1094507 là “Một triệu, (không trăm) chín tư nghìn, năm trăm linh bảy đơn vị”.
Viết chương trình sắp xếp theo tên một mảng họ tên nào đó.
Tìm tất cả số tự nhiên có 4 chữ số mà trong mỗi số không có 2 chữ số nào giống nhau.
Nhập số tự nhiên n. Hãy biểu diễn n dưới dạng tích của các thừa số nguyên tố.
Đệ qui
Nhập số nguyên dương N. Viết hàm đệ qui tính:
Nhập số nguyên dương n. Viết hàm đệ qui tính:
 n dấu căn
 n dấu chia
Viết hàm đệ qui tính n!. áp dụng chương trình con này tính tổ hợp chập k theo công thức truy hồi: C(n, k) = n!/(k! (n-k)!)
Viết hàm đệ qui tính số fibonaci thứ n. Dùng chương trình con này tính f(2) + f(4) + f(6) + f(8).
Viết dưới dạng đệ qui các hàm 
daoxau 	b. UCLN 	c. Fibonaci	d. Tháp Hà Nội
Viết macro tráo đổi nội dung 2 biến. AD: Sắp xếp dãy số.

File đính kèm:

  • docBài giảng Ngôn ngữ lập trình CC++ - Phạm Hồng Thái - Chương 4 Hàm và chương trình.doc