Lập trình C: Bài 11 – Con trỏ trong c
Nội dung
1. GIới thiệu con trỏ trong C
Các biến chúng ta đã biết và sử dụng trước đây đều là biến có kích thước và kiểu dữ liệu xác định. Người ta gọi các biến kiểu này là biến tĩnh. Khi khai báo biến tĩnh, một lượng ô nhớ cho các biến này sẽ được cấp phát mà không cần biết trong quá trình thực thi chương trình có sử dụng hết lượng ô nhớ này hay không. Mặt khác, các biến tĩnh dạng này sẽ tồn tại trong suốt thời gian thực thi chương trình dù có những biến mà chương trình chỉ sử dụng 1 lần rồi bỏ.
Một số hạn chế có thể gặp phải khi sử dụng các biến tĩnh:
- Cấp phát ô nhớ dư, gây ra lãng phí ô nhớ.
- Cấp phát ô nhớ thiếu, chương trình thực thi bị lỗi.
Để tránh những hạn chế trên, ngôn ngữ C cung cấp cho ta một loại biến đặc biệt gọi là biến động với các đặc điểm sau:
- Chỉ phát sinh trong quá trình thực hiện chương trình chứ không phát sinh lúc bắt đầu chương trình.
- Khi chạy chương trình, kích thước của biến, vùng nhớ và địa chỉ vùng nhớ được cấp phát cho biến có thể thay đổi.
- Sau khi sử dụng xong có thể giải phóng để tiết kiệm chỗ trong bộ nhớ. Tuy nhiên các biến động không có địa chỉ nhất định nên ta không thể truy cập đến chúng được. Vì thế, ngôn ngữ C lại cung cấp cho ta một loại biến đặc biệt nữa để khắc phục tình trạng này, đó là biến con trỏ (pointer) với các đặc điểm:
- Biến con trỏ không chứa dữ liệu mà chỉ chứa địa chỉ của dữ liệu hay chứa địa chỉ của ô nhớ chứa dữ liệu.
- Kích thước của biến con trỏ không phụ thuộc vào kiểu dữ liệu.
2. Biến con trỏ
Mỗi biến khi được khai báo đều được cấp phát cho 1 vùng nhớ nhất định ở những nơi (địa chỉ) khác nhau. Biến con trỏ là biến dùng để lưu trữ địa chỉ của các biến đó.
2.1 Ví dụ
// e.g about pointer - code by nguyenvanquan7826 #include <stdio.h> int main() { /* khai bao bien x va bien con tro px */ int x, *px; px = &x; /* &x : tra ve dia chi cua bien x * px = &x : gan dia chi cua bien x cho px hay px tro den x */ x = 42; printf("Vi tri cua bien x la %p \n", &x); printf("Noi dung cua bien x la %d \n", x); printf("Vi tri cua bien x la %p \n", px); printf("Noi dung cua bien x la %d \n", *px); *px = 7826; printf("\n -------- \n\n"); printf("Noi dung cua bien x la %d \n", x); printf("Noi dung cua bien x la %d \n", *px); return 0; }
Kết quả:
Kết quả:
Noi dung cua bien x la 42
Vi tri cua bien x la 0x7ffe064348fc
Noi dung cua bien x la 42
--------
Noi dung cua bien x la 7826
Noi dung cua bien x la 7826
Qua ví dụ mở đầu này ta có thể rút ra một số điểm sau:
a. Khai báo biến con trỏ
Với mỗi kiểu dữ liệu ta có tương ứng một biến con trỏ có kiểu đó.
Kiểu * Tên biến con trỏ;
Trong VD trên ta khai báo 1 biến con trỏ px thuộc kiểu int.
b. Quy định vùng trỏ tới của con trỏ
Ta dùng toán tử & để lấy địa chỉ của 1 biến và sau đó gán địa chỉ đó cho biến con trỏ.
Tên con trỏ = &biến;
c. Cách truy xuất
Với con trỏ px bên trên ta có 2 phép tuy xuất là:
- px : Lấy địa chỉ mà nó lưu giữ (trỏ tới)
- *px : Lấy giá trị trong vùng nhớ mà nó trỏ tới.
Trong VD trên ta có thể thấy sau phép gán px = &x; thì việc ta viết:
- px sẽ tương đương với &x
- *px sẽ tương đương với x. và ta có thể sử dụng *px trong các phép toán, biểu thức.
d. Một số phép toán trên biến con trỏ
// e.g about pointer - code by nguyenvanquan7826 #include <stdio.h> int main() { /* khai bao bien x va 2 bien con tro px, qx */ int x, *px, *qx; px = &x; printf("Nhap gia tri cho vung nho px tro toi: "); scanf("%d", px); /* px la con tro nen khong viet scanf("%d", &px); */ qx = px; /* gan gia tri cua px cho qx, qx cun tro toi x*/ printf("Vi tri cua bien x la %p \n", &x); printf("Vi tri cua bien x la %p \n", px); printf("Vi tri cua bien x la %p \n", qx); printf("Noi dung cua bien x la %d \n", x); printf("Noi dung cua bien x la %d \n", *px); printf("Noi dung cua bien x la %d \n", *qx); // tang gia tri cua o nho len, <=> x = x + 7826 *px += 7826; printf("Noi dung cua bien x la %d \n", x); px++; /* cong them mot don vi cho px * => px tro toi vung nho tiep theo */ printf("Vi tri px tro toi la %p \n", px); return 0; }
Kết quả:
Nhap gia tri cho vung nho px tro toi: 42
Vi tri cua bien x la 0xbfba58a0
Vi tri cua bien x la 0xbfba58a0
Vi tri cua bien x la 0xbfba58a0
Noi dung cua bien x la 42
Noi dung cua bien x la 42
Noi dung cua bien x la 42
Noi dung cua bien x la 7868
Vi tri px tro toi la 0xbfba58a4
Trong vd trên ta thấy có một số phép toán trên con trỏ hay gặp sau: (ngoài ra còn nhiều phép toán khác).
- 2 biến con trỏ cùng kiểu có thể được gán cho nhau hoặc thực hiện các phép toán cộng cho một số nguyên, trừ 2 con trỏ cho nhau. Ở VD trên ta thực hiện các phép toán:
- Gán: qx = px; Khi này qx nhận giá trị của px hiện có là địa chỉ của biến x, tức là qx và px cùng trỏ đến x. ngoài ra ta có thể gán như sau: qx = px + 2; với qx, px là các biến con trỏ cùng kiểu. Phép trừ 2 con trỏ cùng kiểu sẽ trả về 1 giá trị nguyên (int). Đây chính là khoảng cách (số phần tử) giữa 2 con trỏ đó
- Tăng: Các phép tăng giảm, cộng trừ được thực hiện trên biến con trỏ tương tự như với các biến số học. Điểm khác biệt duy nhất là nó tăng giảm, cộng trừ theo đơn byte mà kiểu của nó có.
VD. Trong VD trên ta có phép tăng: px++; Khi này giả sử px đang trỏ đến địa chỉ: 0xbfba58a0 thì sau phép tăng nó có giá trị là (trỏ đến vị trí) 0xbfba58a4 (tăng lên 4) vì px là con trỏ kiểu int mà mỗi biến kiểu int chiếm 4 byte trong bộ nhớ. - Ngoài ra chúng ta để ý còn phép thay đổi giá trị của biến x bằng phép toán *px += 3; Ở phép toán này thực chất là ta đã thay đổi giá trị ở ô nhớ (địa chỉ) mà px trỏ tới, từ đó dẫn đến giá trị của biến x cũng thay đổi theo.
Các bạn chú ý:
- Tùy theo trình dịch hoặc hệ điều hanh mà dung lượng của các kiểu là khác nhau. (trong trình dịch này thì kiểu int chiếm 4 byte nhưng trong trình dịch khác thì nó lại chiếm 2 byte). Để biết dung lượng từng kiểu bạn dùng toán tử sizeof() mà trong bài 2 đã đề cập.
- Cũng tùy theo hệ điều hành Mỗi biến con trỏ, dù là con trỏ thuộc kiểu nào (int, float, double,…) cũng chỉ chiếm số lượng byte giống nhau. Hệ điều hành 32 bit thì biến con trỏ chiếm 4 byte, hệ điều hành 64 bit thì biến con trỏ chiếm 8 byte.
3. Cấp phát và thu hồi vùng nhớ
a. Cấp phát:
Trước khi vào phần này ta làm ví dụ nho nhỏ.
// e.g about pointer - code by nguyenvanquan7826 #include <stdio.h> int main() { int *px; *px = 42; printf("Vi tri con tro px la %p \n", px); printf("Gia tri con tro px tro toi la %d \n", *px); return 0; }
Khi biên dịch thì sẽ không co lỗi (có cảnh báo), khi chạy sẽ không thể chạy được mà chương trình sẽ thoát ra luôn.
Nguyên nhân là khi khai báo biến con trỏ px thì máy mới chỉ cung cấp 2 byte để lưu địa chỉ của biến con trỏ mà chưa cấp phát vùng nhớ để con trỏ px lưu trữ dữ liệu. (tương tự như hợp tác xã cung cấp 2 Kg thóc cho bạn để làm giống nhưng lại không cung cấp cho bạn ruộng đất để bạn reo mạ vậy ).
Lưu ý: Có một số trình dịch sẽ không báo lỗi mà vẫn chạy bình thường nhưng tốt nhất là ta nên cấp phát trước khi sử dụng. Lỗi này sẽ xuất hiện rõ nhất khi bạn sử dụng con trỏ với mảng mà lát nữa ta sẽ đề cập.
Thôi ta đi vào vấn đề chính, làm sao để cấp phát vùng nhớ cho con trỏ.
Để cấp phát vùng nhớ cho con trỏ ta dùng các hàm sau trong thư viện stdlib.h.
- malloc : tên con trỏ = (kiểu con trỏ *) malloc (sizeof(kiểu con trỏ));
- calloc : tên con trỏ = (kiểu con trỏ *) malloc (n, sizeof(kiểu con trỏ));
Trong đó sizeof(kiểu con trỏ) là kích thước của kiểu; n là số lần của sizeof(kiểu con trỏ) được cấp.
// e.g about pointer - code by nguyenvanquan7826 #include <stdio.h> #include <stdlib.h> int main() { int *px, *qx; px = (int *) malloc(sizeof(int)); qx = (int *) calloc(1, sizeof(int)); printf("Vi tri con tro px la %p \n", px); printf("Gia tri con tro px tro toi la %d \n", *px); printf("Vi tri con tro qx la %p \n", qx); printf("Gia tri con tro qx tro toi la %d \n", *qx); return 0; }
Ở đây các bạn chú ý: sự khác nhau duy nhất giữa malloc và calloc mà các bạn hiểu đơn giản là với malloc thì khi cấp phát máy sẽ cấp phát cho px 1 ô bất kỳ mà không cần biết ô đó có dữ liệu là gì hay không có dữ liệu (do đó *px có giá trị như trên) còn calloc cũng vậy nhưng khác 1 điểm là sau khi cấp phát thì máy sẽ tự động gán luôn giá trị 0 cho ô nhớ mà biến qx trỏ tới, tức qx có giá trị mặc định là 0.
Khi cấp phát cho biến con trỏ 1 số lượng ô nhớ nào đó mà trong quá trình làm việc ta thiếu và cần cấp phát thêm thì ta sử dụng lệnh realloc:
tên con trỏ = (kiểu con trỏ *) realloc (tên con trỏ, số lượng cần cấp phát * sizeof(kiểu con trỏ));
Trong đó: số lượng cần cấp phát = cũ + mới.
VD: Ban đầu ta cấp phát cho con trỏ px là 10 ô nhớ.
Sau đó muốn cấp phát thêm cho nó 5 ô nhớ nữa thì số lượng cấp phát = 15.
b. Thu hồi và kiểm tra vùng nhớ còn lại
Để thu hổi bộ nhớ đã cấp phát ta dùng hàm free(tên con trỏ);
3. Hàm có đối là con trỏ
Như trong bài Hàm hoán vị trong C chúng ta đã biết cách truyền các tham số a,b trong hàm HoanVi là cách truyền bằng tham trị chứ không phải truyền bằng địa chỉ (hay tham biến) nên mặc dù trong hàm thì giá trị các biến đã được thay đổi nhưng sau khi hàm thực hiện xong thì các giá trị vẫn chưa thể thay đổi được. Và ta sẽ phải sửa lại bằng cách truyền tham số hình thức là con trỏ a và con trỏ b để khi thực hiện hoán đổi có thể hoán đổi tại địa chỉ của các ô nhớ đó. Khi đó ta mới có được kết quả mong muốn.
// e.g about pointer - code by nguyenvanquan7826 #include <stdio.h> void hoanVi(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main() { int a = 42, b = 7826; printf("Truoc khi goi ham hoan vi: a = %d, b = %d \n", a, b); hoanVi(&a, &b); printf("Sau khi goi ham hoan vi: a = %d, b = %d \n", a, b); return 0; }
bạn cho mình hỏi . bạn có tài liệu hay ví dụ gì về con trỏ và mảng không. ví dụ một mảng có 10 con trỏ hay con trỏ trỏ đến mảng có 10 phần tử!
cảm ơn bạn
Cai do no giong nhu mang 2 chiêu vây. Ngay truoc minh co viết nhung su co bi xoa mat roi. Ban tim trên mang xem nhe
việt cấp phát vùng nhớ ,có thể dùng lệnh : biến con trỏ = new kiểu dữ liệu dc ko anh
Có nhưng nó là của C++ bạn ah
cái %p đó nghĩ là gì vậy anh
Nghĩa là in ra địa chỉ của biến
nếu em đổi int * px thành int &px thì có khác nhau không anh. nếu khác thì anh giải thích giup em đc ko ạ
em cam ơn!
khi khai báo int *px thì nó là 1 cấu trúc để khai báo biến con trỏ, chứ không có khai báo int &px.
vậy sao. em thấy khi khởi tạo danh sách có người họ cũng khai báo như vậy
void khoitao(DS A,int &n)
{
n=0;
}
là đúng hay sai anh
Ah đó là sử dụng trong hàm. Khi khai báo như vậy thì nó giống như khai báo *px là cho phép biến này thay đổi giá trị khi ra khỏi hàm. Tuy nhiên nó là của C++ và khi gọi hàm này thì không phải truyền địa chỉ vào hàm mà chỉ cần truyền biến vào thôi.
Bạn có thể xem vd này để hiểu thêm:
https://www.cachhoc.net/2014/12/12/lap-trinh-c-bai-6-ham/#VD3_Ham_hoan_vi
tại sao lại quy định vùng trỏ tới của con trỏ vậy anh.
Cái này để con trỏ kiểm soát giá trị của một ô nhớ bấy kỳ mà nó trỏ tới…
Cám ơn a
Nếu là y=*z trog đó
y là biến
z la con trỏ
Au biết giúp e với
Khong hieu ban hoi gi @@
#define PA_ODR *(unsigned char*)0x5000
các bạn cho hỏi nghĩa của câu lệnh trên là gì vậy ?
Lệnh định nghĩa một hằng số
vậy mục đích mình dùng tham chiếu (vd: float tong(float &a ) khi định nghĩa hàm để làm gì anh
Để sau khi ra khỏi hàm, giá trị của a có thể thay đổi. Ví dụ trước khi vào a là 5, sau khi vào hàm thì a là 9. Sau khi ra khỏi hàm a vẫn có giá trị là 9 chứ ko trở về 5.
dùng hàm trả về là 1 tham chiếu( vd : int & myfunc() )để làm gì vậy anh.!!! .em tks . em thấy mấy sách khai báo như vậy nhưng ko hiểu nó dùng làm gì ?
Cái này mình cũng chịu. Chưa dùng thử bao giờ 😉
có thể cho e vd về sử dung con trỏ kết hợp vs struct ko 🙂
Bạn thử xem 2 bài này xem
https://www.cachhoc.net/2014/12/21/lap-trinh-c-bai-13-danh-sach-lien-ket-don-cai-bang-con-tro/
https://www.cachhoc.net/2014/12/19/lap-trinh-c-bai-11-kieu-cau-truc-struct/
A Quân học trường nào thế? a Sn bao nhiêu nhỉ?
Dòng thứ 6 trong ví dụ 2 bạn đưa ra:
printf(“Nhap gia tri cho vung nho px tro toi: “);
scanf(“%d”, px);
hình như phải như thế này:
printf(“Nhap gia tri cho vung nho px tro toi: “);
scanf(“%d”, *px);
Bạn có thể giải thích cho minh chỗ này được không????
Vì px là con trỏ nên gọi px luôn đk, nó giống như &a. Còn *px là gọi đến giá trị của nó giống như gọi a.
Anh cho em hỏi là kiểm tra kích thước của biến con trỏ là 2 bite như thế nào ạ.
Ví dụ kiểm tra kích thước của int em dùng sizeof() . nhưng khi e dùng sizeof(p) hoặc sizeof(*p) thì không ra 2 bite.
Chào Anh.
Trong bài viết e thấy a có đề cập đến việc con trỏ thiếu ô nhớ trong quá trình làm việc. A có thể cho em trường hợp mà con trỏ thiếu ô nhớ trong quá trình làm việc được không ạ ? Với lại anh có thể nói rõ hơn về vai trò của n trong hàm calloc giúp em được ko ạ ?
Ví dụ như ban đầu chúng ta cấp phát cho 100 ô nhớ, nhưng do số lượng cần lưu sau này vượt quá 100 thì bị thiếu.
n là số lượng ô nhớ cần cấp phát.
tại sao ở ví dụ đầu tiên không cần cấp phát bộ nhớ mà ví dụ thứ 3 lại cần cấp phát bộ nhớ ạ.
Vì ở các ví dụ trước nó được gán thẳng rồi bạn.
Sao không có nút like vậy bạn
pdest = strstr( string, str );
result = (int)(pdest – string + 1);
anh nguyenvanquan7826 giai thich ho em cau lenh thu 2 sao lai tra ve dc vi tri str trong chuoi string vay
psest la vi tri o nho ma string la chuoi sao tru dc cho nhau vay
anh cho e hỏi. E cũng muốn tạo một trang blog giống như a vậy mà e kh bít làm sao soạn bài như a vừa có hướng dẫn vừa có code trong đó. a có thể chỉ cho e với được kh… e đã biết php , css, html , e muốn soạn các bài ra rồi lưu xuống db xong sau đó chỉ cần load lên thui mà kh biết làm như thế nào mà a có thể vừa viết bài mà vừa có code minh họa như vậy được…
Bạn tìm hiểu wordpress nhé. Mình đang dùng nó.
Bạn có thể cho mình hỏi là biến con trỏ chiếm 2byte bộ nhớ để lưu trữ địa chỉ, mà như ví dụ mở đầu thì vị trí của biến x là 0xbff327e4, số này lớn hơn 2byte. Mình chưa hiểu chỗ này lắm, mong bạn giải đáp giùm mình với
anh ơi anh có thể giải thích cho em int *p1=&x , int **p2 =&p1. nó có ý nghĩa như thế nào ko ạ? và cái int *p1=&x nó có giống vs int *p1; p1=&x không ạ? Em cảm ơn
Nó là gán địa chỉ của x vào con trỏ p1, gán địa chỉ con trỏ p1 vào p2. Cái cuối thì nó giống nhau nhé.
Anh ơi, ở ví dụ 2 của phần 2a cấp phát í ạ, hình như anh chưa gán giá trị cho *px, phần chú ý phía dưới anh có ghi *px có giá trị như trên. Cho e hỏi kết quả của chương trình đó nó xuất ra gì vậy anh? Và n trong calloc mình chọn ngẫu nhiên đúng hông anh, và nó có ảnh hưởng gì nếu như mình chạy chương trình với kích thước lớn hơn n hông anh. E cảm ơn ạ
Mình nói là chương trình sẽ lỗi mà. Còn n là số lượng mình muốn, với 1 biến như px kia thì n là 1. Nếu với mảng có n phần thử thì n chính là số lượng phần tử của mảng.
Anh cho em hỏi, bản thân con trỏ cũng là một biến, nên nó sẽ có địa chỉ và ô nhớ riêng trong bộ nhớ. Vậy có thể dùng một con trỏ khác để trỏ tới địa chỉ của con trỏ kia được ko anh?
😀 Xin lỗi em chưa đọc kĩ mấy câu hỏi bên trên. Vậy cho em hỏi, khác nhau giữa con trỏ kiểu char với con trỏ của những kiểu kia là gì ạ. Như e thấy có thể khai báo: char *s={“abc xyz”}
nhưng không thể int *i={“1,2,3”} . Cảm ơn anh.
Con trỏ kiểu char cũng giống các con trỏ khác thôi. Nhưng nếu bạn đọc bài con trỏ và mảng thì nó sẽ có mối liên hệ, con trỏ kiểu char sẽ có thể coi là 1 mảng các ký tự nên có thể coi là chuỗi.
Được nhé.
Anh cho em hỏi Địa chỉ của biến mà con trỏ trỏ đến và Địa chỉ của con trỏ có khác nhau không ạ ?
Vi dụ như
int a = 5;
int *p;
p=&a;
printf(“Dia chi cua a la : %p”,&a);
printf(“\nDia chi cua bien mà p tro den %p”,p);
printf(“\nDia chi cua p %p”,&p);
2 Dòng đầu giống nhau nhưng dòng thứ 3 thì ra giá trị khác ạ ?? Mong anh trả lời câu hỏi của em (((: .
Khác chứ em, p lưu địa chỉ của a chứ nó có lưu địa chỉ của nó đâu.
Anh ơi cho em hỏi là em đọc trong sách thì giả sử khi ta khai báo 1 mảng là a[2][3] thì:
a là địa chỉ của a[0][0];
a+1 là địa chỉ của a[1][0];
a+2 là địa chỉ của a[2][0];
Nhưng khi em dùng %p để kiểm tra như bài của anh thì nó lại ra a+1 trỏ đến địa chỉ của phần từ ngay sau a[2][3] luôn anh ạ. Anh giải thích hộ em với, Em cảm ơn
Ngay sau a[2][3] là phần tử nào?.
E thử in %p của a + 1
và %p của &a[0][1] xem.
#include “stdio.h”
#include “conio.h”
#include “math.h”
#include “string.h”
int main()
{
int x=5;
int *p=&x;
printf(“%d\n”,*p);
p=(int*)calloc(5,sizeof(int));
for(int i=0;i<5;i++)
*(p+i)=i+1;
for(int i=0;i<5;i++)
printf("%4d",*(p+i));
getch();
}
anh cho em hỏi là code này bị sai gì ạ ???
Sai gì thì bạn chạy lên là biết mà.
include thì dùng kí tự not “” va dùng hàm calloc thì phải khai báo hàm stdlib.h. vì hàm này hỗ trợ nó.
Em chào anh, em đang có một vấn đề khó hiểu, em mong a dành ít thời gian giải đáp giúp em.
#include
void func1(int a) {
int x;
x = a;
printf(“Address of x: %p, x = %d\n”, &x, x);
}
void func2(int a) {
int y;
printf(“Address of y: %p, y = %d”, &y, y);
}
int main() {
func1(5);
func2(8);
return 0;
}
Em chạy chương trình này thì nhận được kết quả:
Address of x: 0x7ffeefc1a31c, x = 5
Address of y: 0x7ffeefc1a31c, y = 5
Em muốn hỏi là tại sao địa chỉ và giá trị của biến y lại giống địa chỉ và giá trị của biến x mặc dù ạ?
Mình cũng đã thử nhưng hiện tại chưa hiểu tại sao…
Địa chỉ của x, với y đều trả về a mà.
Bạn xem có thể đính chính lại điểm này nhé, mình thấy chưa hợp lý:
“Kích thước của biến con trỏ không phụ thuộc vào kiểu dữ liệu, luôn có kích thước cố định là 2 byte.”
Theo mình nghỉ, bạn đang nói biến con trỏ kiểu void *. biến này phụ thuộc vào kiến trúc vi điều khiển, vi xử lý.
Biến có trỏ phụ thuộc vào kiểu dữ liệu nó trỏ đến, kích thước của con trỏ tương ứng với địa chỉ của các ô nhớ.
Thân!
Cảm ơn bạn, mình đã sửa lại nhé. tuy nhiên kích thước của con trỏ thì dù kiểu nào cũng giống nhau nhé.
Cũng tùy theo hệ điều hành Mỗi biến con trỏ, dù là con trỏ thuộc kiểu nào (int, float, double,…) cũng chỉ chiếm số lượng byte giống nhau. Hệ điều hành 32 bit thì biến con trỏ chiếm 4 byte, hệ điều hành 64 bit thì biến con trỏ chiếm 8 byte.
anh cho em hỏi, bên trên anh khai báo 2 biến a , b rồi trong hàm anh lại biến nó thành 2 con trỏ *a, *b. Em vẫn chưa hiểu chỗ đó ạ, anh giải thích cho em được không ạ, em cảm ơn
Dùng con trỏ để lưu lại giá trị của biến sau khi ra khỏi hàm ấy bạn. Nếu bạn không dùng con trỏ trong hàm thì sẽ không lưu được giá trị của biến đâu.
Chào các bạn, mình tự học lập trình được 1 tháng nay rồi. Bài học về con trỏ trên trang cachhoc.net khá là mơ hồ dành cho người học, không thể hiện được bản chất giữa con trỏ, biến TRÊN BỘ NHỚ.
Mình có tham khảo thêm một tài liệu ở trang daynhauhoc.com, các bạn có thể search google “Tài liệu lập trình C for newbie” để tìm bộ tài liệu đó. Rất dễ hiểu, bạn học sẽ nắm rõ được bản chất và cũng rất hài hước khi học nữa 😀
Cảm ơn bạn đã chia sẻ.