1.toán tử lấy địa chỉ
trong lập trình c chúng ta cần xác định được con trỏ của ta đang ở đâu trong ct, với bộ nhớ của biến thì ng lập trình c không cần xác định vì trình biên dịch đã làm sẵn điều rắc rối đó cho chúng ta, chúng ta chỉ việc sử dụng toán tử lấy địa chỉ.
Vào thời điểm mà chúng ta khai báo một biến thì nó phải được lưu trữ trong một vị trí cụ thể trong bộ nhớ. Nói chung chúng ta không quyết định nơi nào biến đó được đặt - thật may mắn rằng điều đó đã được làm tự động bởi trình biên dịch và hệ điều hành, nhưng một khi hệ điều hành đã gán một địa chỉ cho biến thì chúng ta có thể muốn biết biến đó được lưu trữ ở đâu
Điều này có thể được thực hiện bằng cách đặt trước tên biến một dấu và (&), có nghĩa là "địa chỉ của". Ví dụ:
test= &tkt;
lệnh sẽ gán biến test là địa chỉ của bien tkt. vì khi ta đặt trước biến dấu & thì nó đã trở thành địa chỉ của biến trong bộ nhớ mà trình biên dich làm sẵn cho ta. gải sử biến tkt có địa chỉ là 1996 trong bộ nhớ thì biến test của chúng ta sẽ có giá trị là 1996 sau khi thưc hiện lệnh trên.
những biến mà nó lưu trữ địa chỉ của biến như biến test ở trên thì được gọi là con trỏ.tiếp theo chúng ta sẽ rõ biến kiểu này được khai báo như thế nào .
2.toán tử tham chiếu (*)
Bằng cách sử dụng con trỏ chúng ta có thể truy xuất trực tiếp đến giá trị được lưu trữ trong biến được trỏ bởi nó bằng cách đặ trước tên biến con trỏ một dấu sao (*) - ở đây có thể được dịch là "giá trị được trỏ bởi". Vì vậy, nếu chúng ta viết:
beth = *ted;
(chúng ta có thể đọc nó là: "beth bằng giá trị được trỏ bởi ted"
Toán tử lấy địa chỉ (&) Nó được dùng như là một tiền tố của biến và có thể được dịch là "địa chỉ của", vì vậy &variable1 có thể được đọc là "địa chỉ của variable1".
Nó chỉ ra rằng cái cần được tính toán là nội dung được trỏ bởi biểu thức được coi như là một địa chỉ. Nó có thể được dịch là "giá trị được trỏ bởi".. *mypointer được đọc là "giá trị được trỏ bởi mypointer".
3. khai báo biến kiểu con trỏ
vì con trỏ có khả năng tham chiếu trực tiếp đến giá trị mà chúng trỏ tới nên cần thiết phải chỉ rõ kiểu dũ liẹu, nào mà một biến con trỏ trỏ tới khai báo nó. Vì vậy, khai báo của một biến con trỏ sẽ có mẫu sau:
type * pointer_name;
trong đó type là kiểu dữ liệu được trỏ tới, không phải là kiểu của bản thân con trỏ. Ví dụ:
int * number;
char * character;
float * greatnumber;
đó là ba khai báo của con trỏ. Mỗi biến đầu trỏ tới một kiểu dữ liệu khác nhau nhưng cả ba đều là con trỏ và chúng đều chiếm một lượng bộ nhớ như nhau (kích thước của một biến con trỏ tùy thuộc vào hệ điều hành). nhưng dữ liệu mà chúng trỏ tới không chiếm lượng bộ nhớ như nhau, một kiểu int, một kiểu char và cái còn lại kiểu float.
Tôi phải nhấn mạnh lại rằng dấu sao (*) mà chúng ta đặt khi khai báo một con trỏ chỉ có nghĩa rằng: đó là một con trỏ và hoàn toàn không liên quan đến toán tử tham chiếu mà chúng ta đã xem xét trước đó. Đó đơn giản chỉ là hai tác vụ khác nhau được biểu diễn bởi cùng một dấu.ví dụ chương trình cụ thể:
#include<stdio.h>
#include<conio.h>
void main()
{
int * diachi;
int i,n = 10;
diachi = &n;
i = *diachi;
printf(" dia chi:%d i=%d", diachi,i);
_getch();
}
Để bạn có thể thấy rằng một con trỏ có thể mang một vài giá trị trong cùng một chương trình.Đây là một ví dụ phức tạp hơn một chút:
#include<stdio.h>
#include<conio.h>
void main()
{
int * diachi;
int n = 10;
diachi = &n;
*diachi = 20;
printf("ban dau n=10\n lay dia chi cua bien n roi thay doi gia tri cua dia chi bo nho do, no lam cho gia tri cua bien n thay doi theo\n n=%d", n);
_getch();
}
nói rõ hơn, dùng biến con trỏ lấy địa chỉ của biến n, khi đó ta dùng toán tử tham chiếu *diachi thò ta sẽ được giá trị tại địa chỉ bộ nhớ đó, cũng chính là giá trị của biến n, khi ta thay đỏi giá trị chứa trong *diachi thì nó cũng lam thay đổi giá trị của biến n.
4. con trỏ và mảng
Trong thực tế, tên của một mảng tương đương với địa chỉ phần tử đầu tiên của nó, giống như một con trỏ tương đương với địa chỉ của phần tử đầu tiên mà nó trỏ tới, vì vậy thực tế chúng hoàn toàn như nhau. Ví dụ, cho hai khai báo sau:
int numbers [20];
int * p;
lệnh sau sẽ hợp lệ:
p = numbers;
Ở đây p và numbers là tương đương và chúng có cũng thuộc tính, sự khác biệt duy nhất là chúng ta có thể gán một giá trị khác cho con trỏ p trong khi numbers luôn trỏ đến phần tử đầu tiên trong số 20 phần tử kiểu int mà nó được định nghĩa với. Vì vậy, không giống như p - đó là một biến con trỏ bình thường, numbers là một con trỏ hằng. Lệnh gán sau đây là không hợp lệ:
numbers = p;
bởi vì numbers là một mảng (con trỏ hằng) và không có giá trị nào có thể được gán cho các hằng.
Vì con trỏ cũng có mọi tính chất của một biến nên tất cả các biểu thức có con trỏ trong ví dụ dưới đây là hoàn toàn hợp lệ:
#include<stdio.h>
#include<conio.h>
void main()
{
int *p;
int mang[4];
p = mang;
*p = 1;
p++;
*p = 2;
p = &mang[2]; *p = 3;
p += 1;
*p = 4;
for (int i = 0; i < 4; i++)
{
printf("%3d", mang[i]);
}
_getch();
}
5. khởi tạo con trỏ
Khi khai báo con trỏ có thể chúng ta sẽ muốn chỉ định rõ ràng chúng sẽ trỏ tới biến nào,
int number;
int *tommy = &number;
là tương đương với:
int number;
int *tommy;
tommy = &number;
Trong một phép gán con trỏ chúng ta phải luôn luôn gán địa chỉ mà nó trỏ tới chứ không phải là giá trị mà nó trỏ tới. Bạn cần phải nhớ rằng khi khai báo một biến con trỏ, dấu sao (*) được dùng để chỉ ra nó là một con trỏ, và hoàn toàn khác với toán tử tham chiếu. Đó là hai toán tử khác nhau mặc dù chúng được viết với cùng một dấu.
char * terry = "hello";
trong trường hợp này một khối nhớ tĩnh được dành để chứa "hello" và một con trỏ trỏ tới kí tự đầu tiên của khối nhớ này (đó là kí tự h') được gán cho terry. Nếu "hello" được lưu tại địa chỉ 1702, lệnh khai báo trên có thể được hình dung như thế này:
trong lập trình c chúng ta cần xác định được con trỏ của ta đang ở đâu trong ct, với bộ nhớ của biến thì ng lập trình c không cần xác định vì trình biên dịch đã làm sẵn điều rắc rối đó cho chúng ta, chúng ta chỉ việc sử dụng toán tử lấy địa chỉ.
Vào thời điểm mà chúng ta khai báo một biến thì nó phải được lưu trữ trong một vị trí cụ thể trong bộ nhớ. Nói chung chúng ta không quyết định nơi nào biến đó được đặt - thật may mắn rằng điều đó đã được làm tự động bởi trình biên dịch và hệ điều hành, nhưng một khi hệ điều hành đã gán một địa chỉ cho biến thì chúng ta có thể muốn biết biến đó được lưu trữ ở đâu
Điều này có thể được thực hiện bằng cách đặt trước tên biến một dấu và (&), có nghĩa là "địa chỉ của". Ví dụ:
test= &tkt;
lệnh sẽ gán biến test là địa chỉ của bien tkt. vì khi ta đặt trước biến dấu & thì nó đã trở thành địa chỉ của biến trong bộ nhớ mà trình biên dich làm sẵn cho ta. gải sử biến tkt có địa chỉ là 1996 trong bộ nhớ thì biến test của chúng ta sẽ có giá trị là 1996 sau khi thưc hiện lệnh trên.
những biến mà nó lưu trữ địa chỉ của biến như biến test ở trên thì được gọi là con trỏ.tiếp theo chúng ta sẽ rõ biến kiểu này được khai báo như thế nào .
2.toán tử tham chiếu (*)
Bằng cách sử dụng con trỏ chúng ta có thể truy xuất trực tiếp đến giá trị được lưu trữ trong biến được trỏ bởi nó bằng cách đặ trước tên biến con trỏ một dấu sao (*) - ở đây có thể được dịch là "giá trị được trỏ bởi". Vì vậy, nếu chúng ta viết:
beth = *ted;
(chúng ta có thể đọc nó là: "beth bằng giá trị được trỏ bởi ted"
Toán tử lấy địa chỉ (&) Nó được dùng như là một tiền tố của biến và có thể được dịch là "địa chỉ của", vì vậy &variable1 có thể được đọc là "địa chỉ của variable1".
Nó chỉ ra rằng cái cần được tính toán là nội dung được trỏ bởi biểu thức được coi như là một địa chỉ. Nó có thể được dịch là "giá trị được trỏ bởi".. *mypointer được đọc là "giá trị được trỏ bởi mypointer".
3. khai báo biến kiểu con trỏ
vì con trỏ có khả năng tham chiếu trực tiếp đến giá trị mà chúng trỏ tới nên cần thiết phải chỉ rõ kiểu dũ liẹu, nào mà một biến con trỏ trỏ tới khai báo nó. Vì vậy, khai báo của một biến con trỏ sẽ có mẫu sau:
type * pointer_name;
trong đó type là kiểu dữ liệu được trỏ tới, không phải là kiểu của bản thân con trỏ. Ví dụ:
int * number;
char * character;
float * greatnumber;
đó là ba khai báo của con trỏ. Mỗi biến đầu trỏ tới một kiểu dữ liệu khác nhau nhưng cả ba đều là con trỏ và chúng đều chiếm một lượng bộ nhớ như nhau (kích thước của một biến con trỏ tùy thuộc vào hệ điều hành). nhưng dữ liệu mà chúng trỏ tới không chiếm lượng bộ nhớ như nhau, một kiểu int, một kiểu char và cái còn lại kiểu float.
Tôi phải nhấn mạnh lại rằng dấu sao (*) mà chúng ta đặt khi khai báo một con trỏ chỉ có nghĩa rằng: đó là một con trỏ và hoàn toàn không liên quan đến toán tử tham chiếu mà chúng ta đã xem xét trước đó. Đó đơn giản chỉ là hai tác vụ khác nhau được biểu diễn bởi cùng một dấu.ví dụ chương trình cụ thể:
#include<stdio.h>
#include<conio.h>
void main()
{
int * diachi;
int i,n = 10;
diachi = &n;
i = *diachi;
printf(" dia chi:%d i=%d", diachi,i);
_getch();
}
Để bạn có thể thấy rằng một con trỏ có thể mang một vài giá trị trong cùng một chương trình.Đây là một ví dụ phức tạp hơn một chút:
#include<stdio.h>
#include<conio.h>
void main()
{
int * diachi;
int n = 10;
diachi = &n;
*diachi = 20;
printf("ban dau n=10\n lay dia chi cua bien n roi thay doi gia tri cua dia chi bo nho do, no lam cho gia tri cua bien n thay doi theo\n n=%d", n);
_getch();
}
nói rõ hơn, dùng biến con trỏ lấy địa chỉ của biến n, khi đó ta dùng toán tử tham chiếu *diachi thò ta sẽ được giá trị tại địa chỉ bộ nhớ đó, cũng chính là giá trị của biến n, khi ta thay đỏi giá trị chứa trong *diachi thì nó cũng lam thay đổi giá trị của biến n.
4. con trỏ và mảng
Trong thực tế, tên của một mảng tương đương với địa chỉ phần tử đầu tiên của nó, giống như một con trỏ tương đương với địa chỉ của phần tử đầu tiên mà nó trỏ tới, vì vậy thực tế chúng hoàn toàn như nhau. Ví dụ, cho hai khai báo sau:
int numbers [20];
int * p;
lệnh sau sẽ hợp lệ:
p = numbers;
Ở đây p và numbers là tương đương và chúng có cũng thuộc tính, sự khác biệt duy nhất là chúng ta có thể gán một giá trị khác cho con trỏ p trong khi numbers luôn trỏ đến phần tử đầu tiên trong số 20 phần tử kiểu int mà nó được định nghĩa với. Vì vậy, không giống như p - đó là một biến con trỏ bình thường, numbers là một con trỏ hằng. Lệnh gán sau đây là không hợp lệ:
numbers = p;
bởi vì numbers là một mảng (con trỏ hằng) và không có giá trị nào có thể được gán cho các hằng.
Vì con trỏ cũng có mọi tính chất của một biến nên tất cả các biểu thức có con trỏ trong ví dụ dưới đây là hoàn toàn hợp lệ:
#include<stdio.h>
#include<conio.h>
void main()
{
int *p;
int mang[4];
p = mang;
*p = 1;
p++;
*p = 2;
p = &mang[2]; *p = 3;
p += 1;
*p = 4;
for (int i = 0; i < 4; i++)
{
printf("%3d", mang[i]);
}
_getch();
}
5. khởi tạo con trỏ
Khi khai báo con trỏ có thể chúng ta sẽ muốn chỉ định rõ ràng chúng sẽ trỏ tới biến nào,
int number;
int *tommy = &number;
là tương đương với:
int number;
int *tommy;
tommy = &number;
Trong một phép gán con trỏ chúng ta phải luôn luôn gán địa chỉ mà nó trỏ tới chứ không phải là giá trị mà nó trỏ tới. Bạn cần phải nhớ rằng khi khai báo một biến con trỏ, dấu sao (*) được dùng để chỉ ra nó là một con trỏ, và hoàn toàn khác với toán tử tham chiếu. Đó là hai toán tử khác nhau mặc dù chúng được viết với cùng một dấu.
char * terry = "hello";
trong trường hợp này một khối nhớ tĩnh được dành để chứa "hello" và một con trỏ trỏ tới kí tự đầu tiên của khối nhớ này (đó là kí tự h') được gán cho terry. Nếu "hello" được lưu tại địa chỉ 1702, lệnh khai báo trên có thể được hình dung như thế này:
H
|
E
|
L
|
L
|
O
|
1702
|
1703
|
1704
|
1705
|
1706
|
cần phải nhắc lại rằng terry mang giá trị 1702 chứ không phải là 'h' hay "hello".
Biến con trỏ terry trỏ tới một xâu kí tự và nó có thể được sử dụng như là đối với một mảng (hãy nhớ rằng một mảng chỉ đơn thuần là một con trỏ hằng). Ví dụ, nếu chúng ta muốn thay kí tự 'o' bằng một dấu chấm than, chúng ta có thể thực hiện việc đó bằng hai cách:
terry[4] = '!';
*(terry+4) = '!';