5.7.1. Khỏi niệm cấu trỳc
Một cấu trỳc dữ liệu là một tập hợp của những kiểu dữ liệu khỏc nhau được gộp lại với một cỏi tờn duy nhất.
5.7.2.Khai bỏo cấu trỳc
struct model_name { type1 element1; type2 element2; type3 element3; … } object_name;
trong đú model_name là tờn của mẫu kiểu dữ liệu và tham số tựy chọn object_name một tờn hợp lệ cho đối tượng. Bờn trong cặp ngoặc nhọn là tờn cỏc phần tử của cấu trỳc và kiểu của chỳng.
Nếu định nghĩa của cấu trỳc bao gồm tham số model_name (tuỳ chọn), tham số này trở thành một tờn kiểu hợp lệ tương đương với cấu trỳc.
Vớ dụ: struct products { char name [30]; float price; } ; products apple;
products orange, melon;
Chỳng ta đó định nghĩa cấu trỳc products với hai trường: name và price, mỗi trường cú một kiểu khỏc nhau. Chỳng ta cũng đó sử dụng tờn của kiểu cấu trỳc (products) để khai bỏo ba đối tượng cú kiểu đú : apple, orange và melon.
Sau khi được khai bỏo, products trở thành một tờn kiểu hợp lệ giống cỏc kiểu cơ bản như int, char
hay short.
Trường tuỳ chọn object_name cú thể nằm ở cuối của phần khai bỏo cấu trỳc dựng để khai bỏo trực tiếp đối tượng cú kiểu cấu trỳc.
Vớ dụ, để khai bỏo cỏc đối tượng apple, orange và melon như đó làm ở phần trước chỳng ta cũng cú thể làm theo cỏch sau:
struct products { char name [30]; float price;
} apple, orange, melon;
Hơn nữa, trong trường hợp này tham số model_name trở thành tuỳ chọn. Mặc dự nếu model_name
khụng được sử dụng thỡ chỳng ta sẽ khụng thể khai bỏo thờm cỏc đối tượng cú kiểu mẫu này.
Một điều quan trọng là cần phõn biệt rừ ràng đõu là kiểu mẫu cấu trỳc, đõu là đối tượng cấu trỳc. Nếu dựng cỏc thuật ngữ chỳng ta đó sử dụng với cỏc biến, kiểu mẫu là tờn kiểu dữ liệu cũn đối tượng là cỏc biến.
5.7.3. Truy cập đến cỏc thành phần của cấu trỳc
Sau khi đó khai bỏo ba đối tượng cú kiểu là một mẫu cấu trỳc xỏc định (apple, orange and melon) chỳng ta cú thể thao tỏc với cỏc trường tạo nờn chỳng. Để làm việc này chỳng ta sử dụng một dấu chấm (.) chốn ở giữa tờn đối tượng và tờn trường. Vớ dụ, chỳng ta cú thể thao tỏc với bất kỡ phần tử nào của cấu trỳc như là đối với cỏc biến chuẩn :
apple.name apple.price orange.name orange.price melon.name melon.price
mỗi trường cú kiểu dữ liệu tương ứng: apple.name, orange.name và melon.name cú kiểu char[30], và apple.price, orange.price và melon.price cú kiểu float.
Chỳng ta tạm biệt apples, oranges và melons để đến với một vớ dụ về cỏc bộ phim: // example about structures
#include <iostream.h> #include <string.h> #include <stdlib.h> struct movies_t { char title [50]; int year; } mine, yours;
Enter title: Alien
Enter year: 1979 My favourite movie is: 2001 A Space Odyssey (1968) And yours: Alien (1979)
void printmovie (movies_t movie);
int main () {
char buffer [50];
strcpy (mine.title, "2001 A Space Odyssey"); mine.year = 1968;
cout << "Enter title: "; cin.getline (yours.title,50); cout << "Enter year: ";
cin.getline (buffer,50); yours.year = atoi (buffer);
cout << "My favourite movie is:\n "; printmovie (mine);
cout << "And yours:\n "; printmovie (yours); return 0;
}
void printmovie (movies_t movie) {
cout << movie.title;
cout << " (" << movie.year << ")\n"; }
Vớ dụ này cho chỳng ta thấy cỏch sử dụng cỏc phần tử của một cấu trỳc và bản thõn cấu trỳc như là cỏc
biến thụng thường. Vớ dụ, yours.year là một biến hợp lệ cú kiểu int cũng như mine.title là một
mảng hợp lệ với 50 phần tử kiểu chars.
Chỳ ý rằng cả mine and yours đều được coi là cỏc biến hợp lệ kiểu movie_t khi được truyền cho
hàm printmovie().Hơn nữa một lợi thế quan trọng của cấu trỳc là chỳng ta cú thể xột cỏc phần tử của chỳng một cỏch riờng biệt hoặc toàn bộ cấu trỳc như là một khối.
Cỏc cấu trỳc được sử dụng rất nhiều để xõy dựng cơ sở dữ liệu đặc biệt nếu chỳng ta xột đến khả năng xõy dựng cỏc mảng của chỳng.
// array of structures #include <iostream.h> #include <stdlib.h>
Enter title: Alien
Enter year: 1979
#define N_MOVIES 5
struct movies_t { char title [50]; int year;
} films [N_MOVIES];
void printmovie (movies_t movie);
int main () { char buffer [50]; int n; for (n=0; n<N_MOVIES; n++) {
cout << "Enter title: ";
cin.getline (films[n].title,50); cout << "Enter year: ";
cin.getline (buffer,50);
films[n].year = atoi (buffer); }
cout << "\nYou have entered these movies:\n"; for (n=0; n<N_MOVIES; n++)
printmovie (films[n]); return 0;
}
void printmovie (movies_t movie) {
cout << movie.title;
cout << " (" << movie.year << ")\n"; }
Enter year: 1982
Enter title: Matrix
Enter year: 1999
Enter title: Rear Window
Enter year: 1954
Enter title: Taxi Driver
Enter year: 1975
You have entered these movies: Alien (1979) Blade Runner (1982) Matrix (1999) Rear Window (1954) Taxi Driver (1975)
Chương 6. HÀM VÀ CON TRỎ 6.1 Hàm và khai bỏo tham số
6.1.1. Khỏi niệm hàm
Hàm là một khối lệnh được thực hiện khi nú được gọi từ một điểm khỏc của chương trỡnh.
6.1.2. Khai bỏi hàm.
<Kiểu dữ liệu trả về> <tờn hàm>(<danh sỏch tham số>) { <Cỏc cõu lệnh> }
Trong đú:
<Kiểu dữ liệu trả về>: kiểu dữ liệu được trả về của hàm.
<tờn hàm>: tờn gọi của hàm.
<danh sỏch tham số>: cỏc tham số (cú nhiều bao nhiờu cũng được tuỳ theo nhu cầu). Một tham số bao gồm tờn kiểu dữ liệu sau đú là tờn của tham số giống như khi khai bỏo biến (vớ dụ int x) và đúng vai trũ bờn trong hàm như bất kỡ biến nào khỏc. Chỳng dựng để truyền tham số cho hàm khi nú được gọi. Cỏc tham số khỏc nhau được ngăn cỏch bởi cỏc dấu phẩy.
<Cỏc cõu lệnh>: thõn của hàm. Nú cú thể là một lệnh đơn hay một khối lệnh. Vớ dụ khai bỏo một hàm.
// function example #include <iostream.h>
int addition (int a, int b) { int r; r=a+b; return (r); } int main () { int z; z = addition (5,3);
cout << "The result is " << z; return 0;
}
6.7.3. Kết quả trả về của hàm – Lệnh return.
Để cú thể hiểu được đoạn mó này, trước hết hóy nhớ lại những điều đó núi ở bài đầu tiờn: một chương trỡnh C++ luụn bắt đầu thực hiện từ hàm main. Vỡ vậy chỳng ta bắt đầu từ đõy.
Chỳng ta cú thể thấy hàm main bắt đầu bằng việc khai bỏo biến z kiểu int. Ngay sau đú là một lời gọi tới hàm addition. Nếu để ý chỳng ta sẽ thấy sự tương tự giữa cấu trỳc của lời gọi hàm với khai bỏo của hàm:
Cỏc tham số cú vai trũ thật rừ ràng. Bờn trong hàm main chỳng ta gọi hàm addition và truyền hai giỏ trị: 5 và 3 tương ứng với hai tham số int a và int b được khai bỏo cho hàm addition.
Vào thời điểm hàm được gọi từ main, quyền điều khiển được chuyển sang cho hàm addition. Giỏ trị của c hai tham số (5 và 3) được copy sang hai biến cục bộ int a và int b bờn trong hàm.
Kết thỳc hàm addition, và trả lại quyền điều khiển cho hàm nào đó gọi nú (main) và tiếp tục
chương trỡnh ở cỏi điểm mà nú bị ngắt bởi lời gọi đến addition. Nhưng thờm vào đú, giỏ trị được
dựng với lệnh return (r) chớnh là giỏ trị được trả về của hàm.\
Giỏ trị trả về bởi một hàm chớnh là giỏ trị của hàm khi nú được tớnh toỏn. Vỡ vậy biến z sẽ cú cú giỏ trị được trả về bởi addition (5, 3), đú là 8.
Xột vớ dụ sau:
// function example #include <iostream.h>
int subtraction (int a, int b) { int r; r=a-b; return (r); } int main () { int x=5, y=3, z; The first result is 5 The second result is 5 The third result is 2 The fourth result is 6
z = subtraction (7,2);
cout << "The first result is " << z << '\n';
cout << "The second result is " << subtraction (7,2) << '\n'; cout << "The third result is " << subtraction (x,y) << '\n'; z= 4 + subtraction (x,y);
cout << "The fourth result is " << z << '\n'; return 0;
}
Trong trường hợp này chỳng ta tạo ra hàm subtraction. Chức năng của hàm này là lấy hiệu của hai tham số rồi trả về kết quả.
Tuy nhiờn, nếu phõn tớch hàm main cỏc bạn sẽ thấy chương trỡnh đó vài lần gọi đến hàm subtraction. Tụi đó sử dụng vài cỏch gọi khỏc nhau để cỏc bạn thấy cỏc cỏch khỏc nhau mà một hàm
cú thể được gọi.
Để cú hiểu cặn kẽ vớ dụ này bạn cần nhớ rằng một lời gọi đến một hàm cú thể hoàn toàn được thay thế bởi giỏ trị của nú. Vớ dụ trong lệnh gọi hàm đầu tiờn :
z = subtraction (7,2);
cout << "The first result is " << z;
Nếu chỳng ta thay lời gọi hàm bằng giỏ trị của nú (đú là 5), chỳng ta sẽ cú: z = 5; cout << "The first result is " << z;
Tương tự như vậy
cout << "The second result is " << subtraction (7,2);
cũng cho kết quả giống như hai dũng lệnh trờn nhưng trong trường hợp này chỳng ta gọi hàm subtraction trực tiếp như là một tham số của cout. Chỳng ta cũng cú thể viết:
cout << "The second result is " << 5;
vỡ 5 là kết quả của subtraction (7,2). Cũn với lệnh
cout << "The third result is " << subtraction (x,y);
Điều mới mẻ duy nhất ở đõy là cỏc tham số của subtraction là cỏc biến thay vỡ cỏc hằng. Điều
này là hoàn toàn hợp lệ. Trong trường hợp này giỏ trị được truyền cho hàm subtraction là giỏ trị của
x and y.
Trường hợp thứ tư cũng hoàn toàn tương tự. Thay vỡ viết
z = 4 + subtraction (x,y);
chỳng ta cú thể viết:
cũng hoàn toàn cho kết quả tương đương. Chỳ ý rằng dấu chấm phẩy được đặt ở cuối biểu thức chứ khụng cần thiết phải đặt ngay sau lời gọi hàm.
6.7.4. Hàm khụng định kiểu
+ Cỏch sử dụng void.
Nếu bạn cũn nhớ cỳ phỏp của một lời khai bỏo hàm:
<Kiểu dữ liệu trả về> <tờn hàm>(<danh sỏch tham số>)
bạn sẽ thấy rừ ràng rằng nú bắt đầu với một tờn kiểu, đú là kiểu dữ liệu sẽ được hàm trả về bởi lệnh
return. Nhưng nếu chỳng ta khụng muốn trả về giỏ trị nào thỡ sao ?
Hóy tưởng tượng rằng chỳng ta muốn tạo ra một hàm chỉ để hiển thị một thụng bỏo lờn màn hỡnh. Nú khụng cần trả về một giỏ trị nào cả, hơn nữa cũng khụng cần nhận tham số nào hết. Vỡ vậy người ta đó nghĩ ra kiểu dữ liệu void trong ngụn ngữ C. Hóy xem xột chương trỡnh sau:
// void function example #include <iostream.h>
void dummyfunction (void){ cout << "I'm a function!"; } int main (){ dummyfunction (); return 0; } I'm a function!
Từ khoỏ void trong phần danh sỏch tham số cú nghĩa là hàm này khụng nhận một tham số nào. Tuy nhiờn trong C++ khụng cần thiết phải sử dụng void để làm điều này. Bạn chỉ đơn giản sử dụng cặp
ngoặc đơn ( ) là xong.
Bởi vỡ hàm của chỳng ta khụng cú một tham số nào, vỡ vậy lời gọi hàm dummyfunction sẽ là :
dummyfunction ();
Hai dấu ngoặc đơn là cần thiết để cho trỡnh dịch hiểu đú là một lời gọi hàm chứ khụng phải là một tờn biến hay bất kỡ dấu hiệu nào khỏc
6.3 Tầm vực của biến
Phạm vi hoạt động của cỏc biến khai bỏo trong một hàm hay bất kỡ một khối lệnh nào khỏc chỉ là hàm đú hay khối lệnh đú và khụng thể sử dụng bờn ngoài chỳng. Vớ dụ, trong chương trỡnh vớ dụ trờn, bạn khụng thể sử dụng trực tiếp cỏc biến a, b hay r trong hàm main vỡ chỳng là cỏc biến cục bộ của hàm addition. Thờm vào đú bạn cũng khụng thể sử dụng biến z trực tiếp bờn trong hàm addition vỡ nú làm biến cục bộ của hàm main.
Tuy nhiờn, cú thể khai bỏo cỏc biến toàn cục để cú thể sử dụng chỳng ở bất kỡ đõu, bờn trong hay bờn ngoài bất kỡ hàm nào. Để làm việc này bạn cần khai bỏo chỳng bờn ngoài mọi hàm hay cỏc khối lệnh, cú nghĩa là ngay trong thõn chương trỡnh.
6.4 Truyền tham số bằng tham trị
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.
6.5 Truyền tham số bằng tham biến
Trong trường hợp này khi 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. Hóy xột trường hợp bạn cần thao tỏc với một biến ngoài ở bờn trong một hàm. Vỡ vậy bạn 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 #include <iostream.h>
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 << "x=" << x << ", y=" << y << ", z=" << z; return 0; } x=2, y=6, z=14
Điều đầu tiờn làm bạn chỳ ý là trong khai bỏo của duplicate theo sau tờn kiểu của mỗi tham số đều là dấu và (&), để bỏo hiệu rằng cỏc tham số này được truyền theo tham số biến chứ khụng phải tham số giỏ trị.
Khi truyền tham số dưới dạng tham số biến chỳng ta đang truyền bản thõn biến đú và bất kỡ sự thay đổi nào mà chỳng ta thực hiện với tham số đú bờn trong hàm sẽ ảnh hưởng trực tiếp đến biến đú.
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ớ dụ, đõy là một hàm trả về số liền trước và liền sau của tham số đầu tiờn.
// more than one returning value #include <iostream.h>
void prevnext (int x, int& prev, int& next) { prev = x-1; next = x+1; } int main () { int x=100, y, z; prevnext (x, y, z);
cout << "Previous=" << y << ", Next=" << z; return 0;
}
Previous=99, Next=101
Giỏ trị mặc định của tham số.
Khi định nghĩa một hàm chỳng ta cú thể chỉ định những giỏ trị mặc định sẽ được truyền cho cỏc đối số trong trường hợp chỳng bị bỏ qua khi hàm được gọi. Để làm việc này đơn giản chỉ cần gỏn một giỏ trị cho đối số khi khai bỏo hàm. Nếu giỏ trị của tham số đú vẫn được chỉ định khi gọi hàm thỡ giỏ trị mặc định sẽ bị bỏ qua.
// default values in functions #include <iostream.h>
int divide (int a, int b=2){ int r; r=a/b; return (r); } int main () { cout << divide (12); cout << endl; cout << divide (20,4); return 0; } 6 5
Nhưng chỳng ta thấy trong thõn chương trỡnh, cú hai lời gọi hàm divide. Trong lệnh đầu tiờn:
divide (12)
chỳng ta chỉ dựng một tham số nhưng hàm divide cho phộp đến hai. Bởi vậy hàm divide sẽ tự cho
tham số thứ hai giỏ trị bằng 2 vỡ đú là giỏ trị mặc định của nú (chỳ ý phần khai bỏo hàm được kết thỳc bởi int b=2). Vỡ vậy kết quả sẽ là 6 (12/2).
Trong lệnh thứ hai: divide (20,4)
cú hai tham số, bởi vậy giỏ trị mặc định sẽ được bỏ qua. Kết quả của hàm sẽ là 5 (20/4).
Quỏ tải cỏc hàm.
Hai hàm cú thể cú cũng tờn nếu khai bỏo tham số của chỳng khỏc nhau, điều này cú nghĩa là bạn cú thể đặt cựng một tờn cho nhiều hàm nếu chỳng cú số tham số khỏc nhau hay kiểu dữ liệu của cỏc tham số khỏc nhau (hay thậm chớ là kiểu dữ liệu trả về khỏc nhau).
Vớ dụ:
// overloaded function #include <iostream.h>
int divide (int a, int b) { return (a/b);
}
float divide (float a, float b)
2 2.5
{ return (a/b); } int main () { int x=5,y=2; float n=5.0,m=2.0; cout << divide (x,y); cout << "\n";
cout << divide (n,m); return 0;
}