Xem mẫu

  1. CHƢƠNG 5 HÀM Giới thiệu Một chƣơng trình viết trong ngôn ngữ C là một dãy các hàm. Hàm chia các bài toán lớn thành các công việc nhỏ hơn, giúp thực hiện những công việc lặp lại nào đó một cách nhanh chóng mà không phải viết lại đoạn chƣơng trình. Bài này sẽ trình bày cách viết chƣơng trình theo cấu trúc hàm, cách truyền tham số cho hàm trong lập trình, sử dụng đệ qui trong lập trình Mục tiêu - Viết chƣơng trình theo cấu trúc hàm - Vận dụng các cách truyền tham số cho hàm trong lập trình - Sử dụng đệ qui trong lập trình Nội dung chính I. KHÁI NIỆM Một chƣơng trình viết trong ngôn ngữ C là một dãy các hàm, trong đó có một hàm chính (hàm main()). Hàm chia các bài toán lớn thành các công việc nhỏ hơn, giúp thực hiện những công việc lặp lại nào đó một cách nhanh chóng mà không phải viết lại đoạn chƣơng trình. Thứ tự các hàm trong chƣơng trình là bất kỳ, song chƣơng trình bao giờ cũng đi thực hiện từ hàm main() II. KHAI BÁO HÀM type tên hàm (khai báo các đối số) { Khai báo các biến cục bộ Các câu lệnh [return[biểu thức];] } Dòng tiêu đề: Trong dòng đầu tiên của hàm chứa các thông tin về: kiểu hàm, tên hàm, kiểu và tên mỗi đối. Ví dụ: float max3s(float a, float b, float c) khai báo các đối có dạng: 57
  2. Kiểu đối 1 tên đối 1, kiểu đối 2 tên đối 2,..., kiểu đối n tên đối n Thân hàm: Sau dòng tiêu đề là thân hàm. Thân hàm là nội dung chính của hàm bắt đầu và kết thúc bằng các dấu { }. Trong thân hàm chứa các câu lệnh cần thiết để thực hiện một yêu cầu nào đó đã đề ra cho hàm. Thân hàm có thể sử dụng một câu lệnh return, có thể dùng nhiều câu lệnh return ở các chỗ khác nhau, và cũng có thể không sử dụng câu lệnh này. Dạng tổng quát của nó là: return [biểu thức]; Giá trị của biểu thức trong câu lệnh return sẽ đƣợc gán cho hàm. Ví dụ: Xét bài toán: Tìm giá trị lớn nhất của ba số mà giá trị mà giá trị của chúng đƣợc đƣa vào bàn phím. Xây dựng chƣơng trình và tổ chức thành hai hàm: Hàm main() và hàm max3s. Nhiệm vụ của hàm max3s là tính giá trị lớn nhất của ba số đọc vào, giả sử là a,b,c. Nhiệm vụ của hàm main() là đọc ba giá trị vào từ bàn phím, rồi dùng hàm max3s để tính nhƣ trên, rồi đƣa kết quả ra màn hình. Chƣơng trình đƣợc viết nhƣ sau: #include float max3s(float a,float b,float c); /* Nguyên mẫu hàm*/ void main() { float x,y,z; printf("\n Vao ba so x,y,z:"); scanf("%f%f%f",&x&y&z); printf("\n Max cua ba so x=%8.2f y=%8.2f z=%8.2f la: %8.2f", x,y,z,max3s(x,y,z)); } /* Kết thúc hàm main*/ float max3s(float a,float b,float c) { float max; max=a; 58
  3. if (max
  4. Khi hàm khai báo không có kiểu ở trƣớc nó thì nó đƣợc mặc định là kiểu int. Không nhất thiết phải khai báo nguyên mẫu hàm. Nhƣng nói chung nên có vì nó cho phép chƣơng trình biên dịch phát hiện lỗi khi gọi hàm hay tự động việc chuyển dạng. Nguyên mẫu của hàm thực chất là dòng đầu tiên của hàm thêm vào dấu ;. Tuy nhiên trong nguyên mẫu có thể bỏ tên các đối. Hàm thƣờng có một vài đối. Ví dụ nhƣ hàm max3s có ba đối là a,b,c. cả ba đối này đều có giá trị float. Tuy nhiên, cũng có hàm không đối nhƣ hàm main. Hàm thƣờng cho ta một giá trị nào đó. Lẽ dĩ nhiên giá trị của hàm phụ thuộc vào giá trị các đối. III. KẾT QUẢ TRẢ VỀ CỦA HÀM - Hàm có thể nhận một hoặc nhiều giá trị đầu vào và trả về một giá trị thuộc kiểu dữ liệu nào đó. Kiểu dữ liệu đƣợc trả về của hàm đƣợc khai báo ở type. - Hàm có thề có hoặc không có giá trị trả về. Nếu hàm không có nhận giá trị đầu vào và không có giá trị trả về thì ở khai báo bằng từ khóa void. - Các biến hoặc biểu thức cung cấp giá trị đầu vào cho hàm đƣợc gọi là đối số. Hàm có thể thay đổi các đối số của nó. IV. CÁCH TRUYỀN THAM SỐ CHO HÀM Cho đến nay, trong tất cả các hàm chúng ta đã biết, tất cả các tham số truyền cho hàm đều đƣợc truyền theo giá trị. Điều này có nghĩa là khi chúng ta gọi hàm với các tham số, những gì chúng ta truyền cho hàm là các giá trị chứ không phải bản thân các biến. Ví dụ, giả sử chúng ta gọi hàm addition nhƣ sau: int x=5, y=3, z; z = addition ( x , y ); Trong trƣờng hợp này khi chúng ta gọi hàm addition thì các giá trị 5 and 3 đƣợc truyền cho hàm, không phải là bản thân các biến Điều đáng nói ở đây là khi chúng ta thay đổi giá trị của các biến a hay b bên trong hàm thì các biến x và y vẫn không thay đổi vì chúng đâu có đƣợc truyền cho hàm chỉ có giá trị của chúng đƣợc truyền mà thôi. 60
  5. Hãy xét trƣờng hợp cần thao tác với một biến ngoài ở bên trong một hàm. Vì vậy ta sẽ phải truyền tham số dƣới dạng tham số biến nhƣ ở trong hàm duplicate trong ví dụ dƣới đây: // passing parameters by reference x=2, y=6, z=14 #include void duplicate (int& a, int& b, int& c) { a*=2; b*=2; c*=2; } int main () { int x=1, y=3, z=7; duplicate (x, y, z); cout
  6. Trong ví dụ trên, chúng ta đã liên kết a, b và c với các tham số khi gọi hàm (x, y và z) và mọi sự thay đổi với a bên trong hàm sẽ ảnh hƣởng đến giá trị của x và hoàn toàn tƣơng tự với b và y, c và z. Kiểu khai báo tham số theo dạng tham số biến sử dụng dấu và (&) chỉ có trong C++. Trong ngôn ngữ C chúng ta phải sử dụng con trỏ để làm việc tƣơng tự nhƣ thế. Truyền tham số dƣới dạng tham số biến cho phép một hàm trả về nhiều hơn một giá trị. V. ĐỆ QUI 1. Giới thiệu C không những cho phép từ hàm này gọi tới hàm khác, mà nó còn cho phép từ một điểm trong thân của một hàm gọi tới chính hàm đó. Hàm nhƣ vậy gọi là hàm đệ qui. Khi hàm gọi đệ qui đến chính nó, thì mỗi lần gọi máy sẽ tạo ra một tập các biến cục bộ mới hoàn toàn độc lập với tập các biến cục bộ đã đƣợc tạo ra trong các lần gọi trƣớc. Để minh hoạ chi tiết những điều trên, ta xét một ví dụ về tính giai thừa của số nguyên dƣơng n. Khi không dùng phƣơng pháp đệ qui hàm có thể đƣợc viết nhƣ sau: long int gt(int n) /* Tính n! với n>=0*/ { long int gtphu=1; int i; for (i=1;i0 Hàm tính n! theo phƣơng pháp đệ qui có thể đƣợc viết nhƣ sau: long int gtdq(int n) { if (n==0 || n==1) return 1; 62
  7. else return(n*gtdq(n-1)); } Giải thích hoạt động của hàm đệ qui khi sử dụng trong hàm main dƣới đây: #include void main() { printf("\n 3!=%d",gtdq(3)); } Lần gọi đầu tiên tới hàm gtdq đƣợc thực hiện từ hàm main(). Máy sẽ tạo ra một tập các biến tự động của hàm gtdq. Tập này chỉ gồm các đối n. Ta gọi đối n đƣợc tạo ra lần thứ nhất là n thứ nhất. Giá trị của tham số thực (số 3) đƣợc gán cho n thứ nhất. Lúc này biến n trong thân hàm đƣợc xem là n thứ nhất. Do n thứ nhất có giá trị bằng 3 nên điều kiện trong toán tử if là sai và do đó máy sẽ lựa chọn câu lệnh else. Theo câu lệnh này, máy sẽ tính giá trị biểu thức: n*gtdq(n-1) (*) Để tính biểu thức trên, máy cần gọi chính hàm gtdq vì thế lần gọi thứ hai sẽ thực hiện. Máy sẽ tạo ra đối n mới, ta gọi đó là n thứ hai. Giá trị của n-1 ở đây lại là đối của hàm , đƣợc truyền cho hàm và hiểu là n thứ hai, do vậy n thứ hai có giá trị là 2. Bây giờ, do n thứ hai vẫn chƣa thoả mãn điều kiện if nên máy lại tiếp tục tính biểu thức: n*gtdq(n-1) (**) Biểu thức trên lại gọi hàm gtdq lần thứ ba. Máy lại tạo ra đối n lần thứ ba và ở đây n thứ ba có giá trị bằng 1. Đối n=1 thứ ba lại đƣợc truyền cho hàm, lúc này điều kiện trong lệnh if đƣợc thoả mãn, máy đi thực hiện câu lệnh: return 1=gtdq(1) (***) Bắt đầu từ đây, máy sẽ thực hiện ba lần ra khỏi hàm gtdq. Lần ra khỏi hàm thứ nhất ứng với lần vào thứ ba. Kết quả là đối n thứ ba đƣợc giải phóng, hàm gtdq(1) cho giá trị là 1 và máy trở về xét giá trị biểu thức n*gtdq(1) đây là kết quả của (**) ở đây, n là n thứ hai và có giá trị bằng 2. Theo câu lệnh return, máy sẽ thực hiện lần ra khỏi hàm lần thứ hai, đối n thứ hai sẽ đƣợc giải phóng, kết quả là biểu thức trong (**) có giá trị là 2.1. Sau đó máy trở về biểu thức (*) lúc này là: n*gtdq(2)=n*2*1 63
  8. n lại hiểu là thứ nhất, nó có giá trị bằng 3, do vậy giá trị của biểu thức trong (*) là 3.2.1=6. Chính giá trị này đƣợc sử dụng trong câu lệnh printf của hàm main() nên kết quả in ra trên màn hình là: 3!=6 Chú ý: Hàm đệ qui so với hàm có thể dùng vòng lặp thì đơn giản hơn, tuy nhiên với máy tính khi dùng hàm đệ qui sẽ dùng nhiều bộ nhớ trên ngăn xếp và có thể dẫn đến tràn ngăn xếp. Vì vậy khi gặp một bài toán mà có thể có cách giải lặp (không dùng đệ qui) thì ta nên dùng cách lặp này. Song vẫn tồn tại những bài toán chỉ có thể giải bằng đệ qui. 2. Các bài toán có thể dùng đệ qui Phƣơng pháp đệ qui thƣờng áp dụng cho các bài toán phụ thuộc tham số có hai đặc điểm sau: Bài toán dễ dàng giải quyết trong một số trƣờng hợp riêng ứng với các giá trị đặc biệt của tham số. Ngƣời ta thƣờng gọi là trƣờng hợp suy biến. Trong trƣờng hợp tổng quát, bài toán có thể qui về một bài toán cùng dạng nhƣng giá trị tham số thì bị thay đổi. Sau một số hữu hạn bƣớc biến đổi dệ qui nó sẽ dẫn tới trƣờng hợp suy biến. Bài toán tính n giai thừa nêu trên thể hiện rõ nét đặc điểu này. 3. Cách xây dựng hàm đệ qui: Hàm đệ qui thƣờng đƣợc xây dựng theo thuật toán sau: if (trƣờng hợp suy biến) { Trình bày cách giải bài toán khi suy biến } else /* Trƣờng hợp tổng quát */ { Gọi đệ qui tới hàm (đang viết) với các giá trị khác của tham số } 4. Các ví dụ về dùng hàm đệ qui: Ví dụ 1: Bài toán dùng đệ qui tìm USCLN của hai số nguyên dƣơng a và b. 64
  9. Trong trƣờng hợp suy biến, khi a=b thì USCLN của a và b chính là giá trị của chúng. Trong trƣờng hợp chung: uscln(a,b)=uscln(a-b,b) nếu a>b uscln(a,b)=uscln(a,b-a) nếu ab) return uscln(a-b,b); else return uscln(a,b-a); } Ví dụ 2: Chƣơng trình đọc vào một số rồi in nó ra dƣới dạng các ký tự liên tiếp. # include # include void prind(int n); void main() 65
  10. { int a; clrscr(); printf("n="); scanf("%d",&a); prind(a); getch(); } void prind(int n) { int i; if (n2 66
  11. CHƢƠNG 6 MẢNG Giới thiệu Bài này sẽ trình bày cách khai báo và khởi tạo mảng, sử dụng mảng trong lập trình, sử dụng mảng làm tham số trong các bài toán Mục tiêu - Khai báo và khởi tạo mảng - Sử dụng mảng trong lập trình - Sử dụng mảng làm tham số trong các bài toán Nội dung chính I. KHÁI NIỆM Một mảng là một tập hợp các phần tử dữ liệu có cùng kiểu. Mỗi phần tử đƣợc lƣu trữ ở các vị trí kế tiếp nhau trong bộ nhớ chính. Những phần tử này đƣợc gọi là phần tử mảng. Mỗi phần tử của mảng đƣợc định danh bằng một chỉ mục hoặc chỉ số gán cho nó. Chiều của mảng đƣợc xác định bằng số chỉ số cần thiết để định danh duy nhất mỗi phần tử. Một chỉ số là một số nguyên dƣơng đƣợc bao bằng dấu ngoặc vuông [ ] đặt ngay sau tên mảng, không có khoảng trắng ở giữa. Một chỉ số chứa các giá trị nguyên bắt đầu bằng 0. Vì vậy, một mảng player với 11 phần tử đƣợc biểu diễn nhƣ sau: player[0], player[1], player[2], ... , player[10]. II. KHAI BÁO MẢNG Một mảng có một vài đặc tính riêng biệt và phải đƣợc khai báo khi sử dụng chúng. Những đặc tính này bao gồm:  Lớp lƣu trữ  Kiểu dữ liệu của các phần tử mảng.  Tên mảng – xác định vị trí phần tử đầu tiên của mảng.  Kích thƣớc mảng - một hằng số có giá trị nguyên dƣơng. Một mảng đƣợc khai báo giống nhƣ cách khai báo một biến, ngoại trừ tên mảng đƣợc theo sau bởi một hoặc nhiều biểu thức, đƣợc đặt trong dấu ngoặc vuông [] xác định chiều dài của mảng. Cú pháp tổng quát khai báo một mảng nhƣ sau: lớp_lƣu_trữ kiểu_dữ_liệu tên_mảng[biểu_thức_kích_thƣớc] 67
  12. Ở đây, biểu_thức_kích_thƣớc là một biểu thức xác định số phần tử trong mảng và phải định ra một trị nguyên dƣơng. Lớp_lƣu_trữ là một tùy chọn. Mặc định lớp automatic đƣợc dùng cho mảng khai báo bên trong một hàm hoặc một khối lệnh, và lớp external đƣợc dùng cho mảng khai báo bên ngoài một hàm. Vì vậy mảng player đƣợc khai báo nhƣ sau: int player[11]; Nên nhớ rằng, trong khi khai báo mảng, kích thƣớc của mảng sẽ là 11, tuy nhiên các chỉ số của từng phần tử bên trong mảng sẽ là từ 0 đến 10. Các qui tắc đặt tên mảng là giống với qui tắc đặt tên biến. Một tên mảng và một tên biến không đƣợc giống nhau, nó dẫn đến sự nhập nhằng. Nếu một sự khai báo nhƣ vậy xuất hiện trong chƣơng trình, trình biên dịch sẽ hiển thị thông báo lỗi.  Một vài qui tắc với mảng:  Tất cả các phần tử của một mảng có cùng kiểu. Điều này có nghĩa là, nếu một mảng đƣợc khai báo kiểu int, nó không thể chứa các phần tử có kiểu khác.  Mỗi phần tử của mảng có thể đƣợc sử dụng bất cứ nơi nào mà một biến đƣợc cho phép hay đƣợc yêu cầu.  Một phần tử của mảng có thể đƣợc tham chiếu đến bằng cách sử dụng một biến hoặc một biểu thức nguyên. Sau đây là các tham chiếu hợp lệ: player[i]; /*Ở đó i là một biến, tuy nhiên cần phải chú ý rằng i nằm trong miền giới hạn của chỉ số đã đƣợc khai báo cho mảng player*/ player[3] = player[2] + 5; player[0] += 2; player[i / 2 + 1];  Kiểu dữ liệu của mảng có thể là int, char, float, hoặc double. III. KHỞI TẠO MẢNG Các mảng không đƣợc khởi tạo tự động, trừ khi mỗi phần tử mảng đƣợc gán một giá trị riêng lẻ. Không nên dùng các mảng trƣớc khi có sự khởi tạo thích hợp. Điều này là bởi vì không gian lƣu trữ của mảng không đƣợc khởi tạo tự động, do đó dễ gây ra kết quả không lƣờng trƣớc. Mỗi khi các phần tử của một mảng chƣa khởi tạo đƣợc sử dụng trong các biểu thức toán học, các giá trị đã tồn tại sẵn trong ô nhớ sẽ đƣợc sử dụng, các giá trị này không đảm bảo rằng có cùng kiểu nhƣ khai báo của mảng, trừ khi các phần tử của mảng đƣợc khởi tạo một cách rõ ràng. Điều này đúng không chỉ cho các mảng mà còn cho các biến thông thƣờng. Trong đoạn mã lệnh sau, các phần tử của mảng đƣợc gán giá trị bằng các dùng vòng lặp for. 68
  13. int ary[20], i; for(i=0; i
  14. Ví dụ: int deci[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; static float rates[4] = {0.0, -2.5, 13.75, 18.0}; char company[5] = {„A‟, „P‟, „P‟, „L‟, „E‟}; int marks[100] = {15, 13, 11, 9} Các giá trị khởi tạo của mảng phải là các hằng, không thể là biến hoặc các biểu thức. Một vài phần tử đầu tiên của mảng sẽ đƣợc khởi tạo nếu số lƣợng giá trị khởi tạo là ít hơn số phần tử mảng đƣợc khai báo. Các phần tử còn lại sẽ đƣợc khởi tạo giá trị 0. Ví dụ, trong mảng marks sau khi có sự khởi tạo nhƣ trên, bốn phần tử đầu tiên (từ 0 đến 3) tƣơng ứng đƣợc khởi tạo là 15, 13, 11 và 9. Các phần tử còn lại có giá trị 0. Không thể chỉ khởi tạo các phần tử từ 1 đến 4, hoặc từ 2 đến 4, hay từ 2 đến 5 khi sự khởi tạo đƣợc thực hiện tại thời điểm khai báo. Trong C không có khả năng lặp lại sự khởi tạo giá trị. Trong trƣờng hợp sự khởi tạo là tƣờng minh, lớp extern hoặc static, các phần tử của mảng đƣợc đảm bảo khởi tạo là 0 (không giống lớp auto). Không cần thiết khai báo kích thƣớc của mảng đang đƣợc khởi tạo. Nếu kích thƣớc của mảng đƣợc bỏ qua khi khai báo, trình biên dịch sẽ xác định kích thƣớc của mảng bằng cách đếm các giá trị đang đƣợc khởi tạo. Ví dụ, sự khai báo mảng external sau đây sẽ chỉ định kích thƣớc của mảng ary là 5 vì có 5 giá trị khởi tạo. int ary[] = {1, 2, 3, 4, 5}; IV. DÙNG MẢNG LÀM THAM SỐ Trong C, khi một mảng đƣợc truyền vào hàm nhƣ một tham số, thì chỉ có địa chỉ của mảng đƣợc truyền vào. Tên mảng không kèm theo chỉ số là địa chỉ của mảng. Đoạn mã dƣới đây mô tả cách truyền địa chỉ của mảng ary cho hàm fn_ary(): void main() { int ary[10]; . fn_ary(ary); . . } Nếu tham số của hàm là mảng một chiều thì tham số có thể đƣợc khai báo theo một trong các cách sau: fn_ary (int ary [10]) /* sized array */ 70
  15. { : } hoặc fn_arry (int ary []) /*unsized array */ { : } Cả hai khai báo ở trên đều cho cùng kết quả. Kiểu thứ nhất sử dụng cách khai báo mảng chuẩn, chỉ rõ ra kích thƣớc của mảng. Kiểu thứ hai chỉ ra rằng tham số là một mảng kiểu int có kích thƣớc bất kỳ Chƣơng trình sau đây nhận các số vào một mảng số nguyên. Sau đó mảng này sẽ đƣợc truyền vào hàm sum_arr(). Hàm sẽ tính toán và trả về tổng của các số nguyên trong mảng. Ví dụ 8: #include void main() { int num[5], ctr, sum = 0; int sum_arr(int num_arr[]); /* Function declaration */ clrscr(); for(ctr = 0; ctr < 5; ctr++) /*Accepts numbers into the array*/ { printf("\nEnter number %d: ", ctr+1); scanf("%d", &num[ctr]); } 71
  16. sum = sum_arr(num); /* Invokes the function */ printf("\nThe sum of the array is %d", sum); getch(); } int sum_arr(int num_arr[]) /* Function definition */ { int i, total; for(i = 0, total = 0; i < 5; i++) /* Calculates the sum */ total += num_arr[i]; return total; /* Returns the sum to main() */ } Kết quả của chƣơng trình trên đƣợc minh họa nhƣ sau: Enter number 1: 5 Enter number 2: 10 Enter number 3: 13 Enter number 4: 26 Enter number 5: 21 The sum of the array is 75 V. MẢNG NHIỀU CHIỀU Chúng ta đã biết thế nào là mảng một chiều. Điều này có nghĩa là các mảng chỉ có một chỉ số. Các mảng có thể có nhiều hơn một chiều. Các mảng đa chiều giúp dễ dàng trình bày các đối tƣợng đa chiều, chẳng hạn một đồ thị với các dòng và cột hay tọa độ màn hình của máy tính. Các mảng đa chiều đƣợc khai báo giống nhƣ các mảng một chiều, ngoại trừ có thêm một cặp dấu ngoặc vuông [] trong trƣờng hợp mảng hai chiều. Một mảng ba chiều sẽ cần ba cặp dấu ngoặc vuông,... Một cách tổng quát, một mảng đa chiều có thể đƣợc biểu diễn nhƣ sau: 72
  17. storage_class data_type ary[exp1][exp2]....[expN]; Ở đó, ary là một mảng có lớp là storage_class, kiểu dữ liệu là data_type, và exp1, exp2,..... , expN là các biểu thức nguyên dƣơng xác định số phần tử của mảng đƣợc kết hợp với mỗi chiều. Dạng đơn giản nhất và thƣờng đƣợc sử dụng nhất của các mảng đa chiều là mảng hai chiều. Một mảng hai chiều có thể xem nhƣ là một mảng của hai „mảng một chiều‟. Một mảng hai chiều đặc trƣng nhƣ bảng lịch trình của máy bay, xe lửa. Để xác định thông tin, ta sẽ chỉ định dòng và cột cần thiết, và thông tin đƣợc đọc ra từ vị trí (dòng và cột) đƣợc tìm thấy. Tƣơng tự nhƣ vậy, một mảng hai chiều là một khung lƣới chứa các dòng và cột trong đó mỗi phần tử đƣợc xác định duy nhất bằng toạ độ dòng và cột của nó. Một mảng hai chiều tmp có kiểu int với 2 dòng và 3 cột có thể đƣợc khai báo nhƣ sau: int tmp[2][3]; Mảng này sẽ chứa 2 x 3 (6) phần tử, và chúng có thể đƣợc biểu diễn nhƣ sau: Dòng 0 1 2 Cột 0 e1 e2 e3 1 e4 e5 e6 Ở đó e1 – e6 biểu diễn cho các phần tử của mảng. Cả dòng và cột đƣợc đánh số từ 0. Phần tử e6 đƣợc xác định bằng dòng 1 và cột 2. Truy xuất đến phần tử này nhƣ sau: tmp[1][2]; Ví dụ : /* Chƣơng trình nhập các số vào một mảng hai chiều. */ #include void main() { int arr[2][3]; int row, col; for(row = 0; row < 2; row++) 73
  18. { for(col = 0; col < 3; col++) { printf(“\nEnter a Number at [%d][%d]: ”, row, col); scanf(“%d”, &arr[row][col]); } } for(row = 0; row < 2; row++) { for(col = 0; col < 3; col++) { printf(“\nThe Number at [%d][%d] is %d”, row, col, arr[row][col]); } } } BÀI TẬP 1. Viết một chƣơng trình nhập mảng 1 chiều n phần tử (n đƣợc nhập từ bàn phím) sắp xếp mảng tăng dần và xuất mảng đã sắp xếp. 2. Viết một chƣơng trình nhập mảng 1 chiều n phần tử (n đƣợc nhập từ bàn phím), nhập m (m phần tử liên tiếp). Kiểm tra mảng có chuỗi con tăng hay không. 3. Viết một chƣơng trình nhập các số sau đây vào một mảng và đảo ngƣợc mảng 34 45 56 67 89 4. Viết chƣơng trình nhập mảng 1 chiều n phần tử (n đƣợc nhập từ bàn phím) - Tính tổng các số dƣơng - Tính tổng bình phƣơng các số âm - Xóa các phần tử 0 - Xuất vị trí của phần tử a xuất hiện trong màng (a nhập từ bàn phím) - Xuất các phần tử chẳn - Xuất phần tử min, max. 5. Viết chƣơng trình nhập ma trận vuông n phần tử (n đƣợc nhập từ bàn phím) - Xuất 2 đƣờng chéo của ma trận. 74
  19. - Tính tổng các phần tử chẵn - Kiểm tra ma trận có đối xứng qua đƣờng chéo chính không. - Xuất các phần tử lẻ của ma trận - Xuất số lƣợng các phần tử a (a nhập từ bàn phím) CHƢƠNG 7 CON TRỎ Giới thiệu Con trỏ là biến chứa địa chỉ của một biến khác. Con trỏ đƣợc sử dụng rất nhiều trong C, một phần là do chúng đôi khi là cách duy nhất để biểu diễn tính toán, và phần nữa do chúng thƣờng làm cho chƣơng trình ngắn gọn và có hiệu quả hơn các cách khác. Bài này sẽ trình bày cách khai báo và sử dụng đƣợc con trỏ, các phép toán trên con trỏ trong lập trình, phân biệt các kiểu con trỏ, cách sử dụng con trỏ trong lập trình 75
  20. Mục tiêu - Khai báo và sử dụng đƣợc con trỏ - Vận dụng đƣợc các phép toán trên con trỏ trong lập trình - Phân biệt đƣợc các kiểu con trỏ - Sử dụng đƣợc con trỏ trong lập trình Nội dung chính I. KHÁI NIỆM Con trỏ là biến chứa địa chỉ của một biến khác. Con trỏ đƣợc sử dụng rất nhiều trong C, một phần là do chúng đôi khi là cách duy nhất để biểu diễn tính toán, và phần nữa do chúng thƣờng làm cho chƣơng trình ngắn gọn và có hiệu quả hơn các cách khác. Con trỏ có thể đƣợc sử dụng trong một số trƣờng hợp sau:  Để trả về nhiều hơn một giá trị từ một hàm  Thuận tiện hơn trong việc truyền các mảng và chuỗi từ một hàm đến một hàm khác  Sử dụng con trỏ để làm việc với các phần tử của mảng thay vì truy xuất trực tiếp vào các phần tử này  Để cấp phát bộ nhớ động và truy xuất vào vùng nhớ đƣợc cấp phát này (dynamic memory allocation) II. CON TRỎ VÀ ĐỊA CHỈ Vì con trỏ chứa địa chỉ của đối tƣợng nên nó có thể xâm nhập vào đối tƣợng gián tiếp qua con trỏ. Giả sử x là một biến kiểu int, và giả sử px là con trỏ đƣợc tạo ra theo một cách nào đó. Phép toán một ngôi & sẽ cho địa chỉ của đối tƣợng, nên câu lệnh: px=&x; sẽ gán địa chỉ của biến x cho trỏ px, và px bây giờ đƣợc gọi là " trỏ tới biến x ". Phép toán một ngôi * coi là toán hạng của nó là đại chỉ cần xét và thâm nhập tới địa chỉ đó để lấy ra nội dung. Nếu biến y có kiểu int thì thì lệnh: y=*px; sẽ gán giá trị của biến mà trỏ px trỏ tới. Vậy dãy lệnh: px=&x; y=*px; sẽ gán giá trị của x cho y nhƣ trong lệnh: 76
nguon tai.lieu . vn