Professional Documents
Culture Documents
LẬP TRÌNH C
LÊ NHẬT THANH
1
Chương 2 – Tại sao lại là C Chinh phục ngôn ngữ C
2
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Và vì nội dung của biến pAge lại chính là địa chỉ của biến age . Nên ta gọi pAge là một pointer hay con
trỏ. Chúng ta có thể nói rằng: aAge đang trỏ tới age . Bạn đã hiểu pointer là gì chưa?
3
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Bây giờ chúng ta sẽ tiếp tục khám phá thêm về bộ nhớ thông qua hình 2.
Hình 2 – Biếm họa về bộ nhớ máy tính 2 (nguồn ảnh – head first C)
Nhìn vào hình 2 và ta sẽ giải thích như sau:
Khi chúng ta khai báo một biến, máy tính sẽ tạo ra một vùng nhớ để lưu giá trị cho biến đó
(hay còn gọi là cấp phát bộ nhớ).
Nếu biến được khai báo biến bình thường (không phải cấp phát động) trong hàm main() , thì
những ô nhớ được cấp phát sẽ nằm trong vùng stack (như trong hình là biến x ). Lưu ý, chúng
ta chưa bàn tới khái niệm vùng heap trong phần này.
Nếu biến được khai báo ngoài hàm main() và ngoài tất cả các hàm, thì những ô nhớ được
cấp phát sẽ nằm trong vùng global của bộ nhớ (trong hình là biến y ).
Trong ví dụ trên, máy tính cấp phát cho biến x một “vị trí” (vị trí này chính là địa chỉ – địa chỉ của vùng
nhớ, tại sao mình không nói là ô nhớ, bởi vì tùy vào CPU mà kiểu int có thể được chứa ở nhiều ô nhớ) là
4,100,000 . Chúng ta đã gán 4 vào x thì “vị trí” 4,100,000 sẽ lưu giá trị là 4 .
Và…con trỏ là biến chứ địa chỉ 4,100,000 như ví dụ ở trên! Nếu muốn trỏ tới x , thì phải dùng con trỏ
kiểu int , bởi vì giá trị của x là integer.
Qua 2 ví dụ, bạn đã hiểu được khái niệm về con trỏ, hình dung là nó đã hoạt động như thế nào. Chúng ta
tiếp tục các phần tiếp theo. Nên nhớ, nếu đi tới đây, bạn vẫn chưa hiểu về con trỏ, thì bạn hãy tiếp tục đọc
lại hoặc nghiền ngẫm cho đến khi nào hiểu thì mới đi tiếp.
4
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
int *p;
p ở đây là con trỏ, và con trỏ p này trỏ đến vùng nhớ kiểu int . Lưu ý *p không phải là con trỏ
mà là giá trị của vùng nhớ mà con trỏ p trỏ tới (giả sử p trỏ tới x trong hình 2 thì *p = 4 ).
Tiếp ví dụ:
Toán tử lấy địa chỉ: toán tử & 1 ngôi (unary operator), toán tử này hoàn toàn khác với toán tử & 2
ngôi (bitwise).
Ví dụ:
5
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Lúc này *conTro tương đương với bienInteger , mọi thao tác với *conTro cũng chính là
thao tác với bienInteger , hay mọi thao tác với bienInteger cũng chính là thao tác với
*conTro .
Câu lệnh bienInteger = 5; hoàn toàn tương đương với *conTro = 5; .
bienInteger++; hoàn toàn tương đương với (*conTro)++; (Khác với *conTro++ nhé!).
Bạn hãy thử test các ví dụ này xem. Test bằng cách dùng lệnh printf để in giá trị ra và chúng ta sẽ kiểm
tra được tính đúng đắn của nó.
Thêm một ví dụ nữa là bạn sẽ hiểu tường tận từ con trỏ, biến, địa chỉ.
#include <stdio.h>
int main () {
pTh = &thanhVar; /* gán địa chỉ của biến thanhVar vào pTh */
/* hay pTh đang trỏ vào biến thanhVar */
/* truy cập giá trị biến thanhVar thông qua con trỏ pTh */
printf("Value of *ip variable: %d\n", *ip );
return 0;
}
Hiểu kiểu dữ liệu của con trỏ chưa nào? quá dễ hiểu! Vậy xem ví dụ sau:
Ngôn ngữ c có rất nhiều kiểu dữ liệu dành cho con trỏ, phần này đã được nói phần 3. trong chương này.
Trong phần này, mình muốn giới thiệu một chút về con trỏ kiểu void và con trỏ trỏ tới NULL .
Chúng ta đã có con trỏ kiểu int, nghĩa là con trỏ này sẽ trỏ tới vùng nhớ kiều int, hay tương tự cho doube,
float,... Vậy con trỏ kiểu void nghĩa là con trỏ chưa xác định được kiểu dữ liệu nó sẽ trỏ vào. Và điều
quan trọng, nó có thể trỏ tất bất kì vùng nhớ có kiểu dữ liệu gì.
6
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Ví dụ:
int a = 10;
char b = 'x';
Bây giờ chúng ta tìm hiểu tiếp về con trỏ mà trỏ tới NULL . Chúng ta hay gọi nó là NULL pointer.
Chúng ta cùng xem ví dụ:
#include <stdio.h>
int main () {
return 0;
}
Bạn dễ dàng nhìn thấy được kết quả in ra: Giá trị của ptr là : 0 . Null pointer chính là một
hằng số 0 , và điều này được quy định ở các thư viện chuẩn của C. Và bạn có thể hiểu một cách đơn giản,
NULL pointer là một con trỏ chưa trỏ đến vùng nhớ nào hết. Giá trị của nó là 0 , không có nghĩa là nó trỏ
tới địa chỉ 0 (các chương trình sẽ bị cấm trỏ vào địa chỉ 0, vì đây là vùng nhớ của hệ thống).
int a = 100;
int *p;
p = (int*)0x0060FF08; // 0x0060FF08 giả sử là địa chỉ biến a,
// đây là ép kiểu,
// vì 0x0060FF08 chỉ là một số nguyên,
// phải ép sang kiểu int* mới gán được cho con trỏ
printf("*p: %d\n", *p); // kết quả của *p là 100, vì p trỏ tới a
7
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
int a=100,*p=&a;
double *x;
printf(p == &a); // kết quả bằng 1 (true)
printf(main == 0); // kết quả bằng 0 (false)
printf(p == 0); // kết quả bằng 0 (false)
printf(x == 0); // kết quả bằng 0 (false)
Lưu ý: chúng ta sẽ đi sâu về phép so sáng này sau, vì nâng cao khá khó!
6.3 Phép cộng trừ và phép tăng giảm
Bản chất của việc tăng giảm con trỏ là di chuyển con trỏ đi lên hoặc đi xuống. Hãy nhớ lại hình 1, khi
chúng ta tăng giảm nội dung của con trỏ, thì con trỏ sẽ trỏ tới vùng nhớ khác.
Đương nhiên không phải di chuyển sang ô nhớ kế tiếp (byte kế tiếp), mà phụ thuộc vào kiểu dữ liệu của
vùng nhớ con trỏ trỏ tới.
Ví dụ:
int a = 100, *p = &a; // giả sử lúc này p đang trỏ tới địa chỉ 0x0060FF08 (địa
chỉ của a)
p++; // p lúc này sẽ trỏ tới địa chỉ 0x0060FF0C (tăng lên 4 ô nhớ)
// bởi vì kiểu int lúc này có 4 byte
p -= 2; // p sẽ trỏ tới địa chỉ 0x0060FF04
Chú ý:
Không có phép tăng giảm con trỏ void và con trỏ hàm.
Không có phép cộng 2 con trỏ với nhau.
Phép trừ 2 con trỏ trả về độ lệch giữa 2 con trỏ
8
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
int main()
{
char xau[100];
char *p = &xau;
/* while-loop style */
while(*p)
{
printf("%c",toupper(*p));
p++;
}
return 0;
}
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
int main()
{
char xau[100];
char *p;
printf("Nhap xau: ");
scanf("%[a-zA-Z]",xau);
/* for-loop style */
for(; p >= xau; p--)
printf("%c", *p);
return 0;
}
Chương trình con lấy độ dài một chuỗi (khi học nhúng thì bạn nên viết chương trình con ra như vậy thay
vì dùng hàm có sẵn, bạn phải khai báo thư viện, tốn bộ nhớ).
9
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
while(*p) // chừng nào gặp kí tự kết thúc chuỗi thì dừng (mã ASCII = 0)
{
temp++;
p++;
}
return temp;
}
8. Constant pointer
Constant pointer tạm dịch là hằng con trỏ. Hằng con trỏ là một con trỏ, nhưng khi đã trỏ tới một vùng
nhớ nào rồi, thì chúng ta không thể cho nó trỏ tới vùng nhớ khác được. Nhưng chúng ta vẫn có thể thay
đổi data của vùng nhớ đó. Xem ví dụ sau nhé:
#include <stdio.h>
int main()
{
int a = 10;
int *const ptr = &a;
*ptr = 5; // right
ptr++; // báo lỗi
return 0;
}
9. Pointer to constant
Pointer to constant tạm dịch là con trỏ trỏ tới một vùng nhớ hằng. Nghĩa là vùng nhớ con trỏ trỏ tới sẽ
không thể nào thay đổi được, còn con trỏ thì muốn trỏ đi đâu thì tùy.
Xém ví dụ sau:
10
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
#include <stdio.h>
int main()
{
const int a = 10; // hoặc int a = 10;
const int *ptr = &a;
*ptr = 5; // báo lỗi
ptr++; // right
}
Rất khó nhớ phải không? Bây giờ chúng ta sẽ có một cách rất dễ nhớ:
11
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Xem ví dụ để hiểu:
#include <stdio.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200}; /* khai báo một mảng có 3 phần tử */
int i, *ptr[MAX]; /* khai báo một mảng 3 con trỏ */
return 0;
}
Bạn đã hiểu về mảng rồi thì mảng các con trỏ cũng tương tự như vậy – mỗi phần tử trong mảng là một
con trỏ.
Theo hình trên, con trỏ đầu tiên sẽ chứa địa chỉ của con trỏ thứ 2, và con trỏ thứ 2 lại chứa địa chỉ của
biến Variable .
12
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Theo hình trên, con trỏ ptr2 sẽ chứ địa chỉ của con trỏ ptr1 , và con trỏ ptr1 sẽ chứa địa chỉ của biến
num . Ta gọi ptr2 là con trỏ trỏ tới con trỏ (pointer to pointer). Đây là cách hiểu đơn giản của pointer to
pointer.
Chúng ta cùng xem một ví dụ về code:
#include <stdio.h>
int main () {
int var;
int *ptr;
int **pptr;
var = 3000;
return 0;
}
Bạn sẽ nhận được 3 kết quả in ra giống nhau: 3000 . Hãy ráng tập trung và hiểu ví dụ này. Nếu bạn thật
sự hiểu được ví dụ này, thì kiến thức về con trỏ của bạn đã cực kì tốt rồi.
13
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
#include <stdio.h>
int* doubleValue(int x)
{
int value = x * 2;
return &value; // hàm này trả về một địa chỉ
} // giá trị value sẽ bị phá hủy khi ra khỏi hàm này. Hãy xem lại phần scope
int main () {
return 0;
}
Ví dụ trên là một function trả về một con trỏ. Điều này hoàn toàn không có gì phức tạp, con trỏ thì chứa
địa chỉ, cho nên return một con trỏ đồng nghĩa với return một địa chỉ. Bạn hãy để ý là biến value (biến
local trong hàm) sẽ bị phá hủy (destroy) ngay khi ra khỏi hàm, cho nên khi con trỏ ptr “lấy” địa chỉ trả về
của hàm doubleValue, địa chỉ này đã bị phá hủy rồi, nên chương trình sẽ gây ra lỗi vì con trỏ không biết
đang trỏ đến đâu, có thể là một địa chỉ rác.
Cho nên khi chúng ta sử dụng hàm để trả về con trỏ thì phải đặc biệt lưu ý điều này. Thông thường chúng
ta sử dụng hàm để trả về con trỏ trong 2 trường hợp là biến static hoặc cấp phát động.
Ví dụ về static :
#include <stdio.h>
int* doubleValue(int x)
{
static int;
value = x * 2;
return &value; // hàm này trả về một địa chỉ
}
int main () {
return 0;
}
14
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
#include <stdio.h>
int* doubleValue(int x)
{
int *value = (int *) malloc(sizeof( int ));
*value = x * 2;
return value; // hàm này vẫn trả về địa chỉ
}
int main () {
return 0;
}
#include <stdio.h>
// đây là một hàm rất bình thường
// và có kiểu trả về là void
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr là một con trỏ trỏ tới hàm fun()
void (*fun_ptr)(int) = &fun;
/* dòng phía trên thì hoàn toàn tương đương với hai dòng dưới:
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
return 0;
}
Giải thích một chút nếu các bạn thấy hơi khó hiểu: Bạn hãy nhìn hàm fun(), hàm này có kiểu trả về là
void, hàm này cũng có một tham số đầu vào là int.
15
Chương 3 – Con trỏ (pointer) Chinh phục ngôn ngữ C
Đó là lý do tại sao con trỏ hàm lại được khai báo void (*fun_ptr)(int) . Hãy ghi nhớ cách khai báo
này và đừng quên dấu ngoặc nào hết. Có thể cú pháp nó hơi khác so với những gì bạn đã học về con trỏ.
16
Chương 4 – Digital Chinh phục ngôn ngữ C
CHƯƠNG 4 - DIGITAL
Một chương rất hay, giúp cho các bạn một cái nhìn tổng quan về digital trong C/C++. Bởi vì khi các bạn
đã học C rồi, thông thạo con trỏ (pointer) rồi, thì vấn đề về digital hay quản lý bộ nhớ (memory
management) các bạn phải biết thì mới thấy “vui” khi học C/C++ được, mới trở thành một dev chất
được.
Tất cả các mã nhị phân đều được lưu vào các ô nhớ máy tính. Bit bên trái ngoài cùng chính là bit cao
nhất (MSB) và bit bên phải ngoài cùng là bit có trọng số thấp nhất (LSB).
1.2 Số bù một (one’s complement)
Là một số trong hệ nhị phân mà nó chính là bù cơ số trừ 1 (radix-minus-1 complement) của một số khác.
Khái niệm này có thể khó hiểu cho một số bạn. Nhưng bạn hãy xem ví dụ để hiểu về số bù 1.
Một số bù 1 có thể có được do đảo tất cả các bit có trong số nhị phân (đổi 1 thành 0 và ngược lại).
17
Chương 4 – Digital Chinh phục ngôn ngữ C
#include <stdio.h>
int main()
{
unsigned char a = 0xC0; // 1100 000
signed char b = 0xC0;
return 0;
}
18
Chương 4 – Digital Chinh phục ngôn ngữ C
int main()
{
unsigned char a = 0x58; // 0101 1000
unsigned char b = 0xA4; // 1010 0100
printf("%x", a | b);
/* Kết quả sẽ in ra:
0101 1000
OR 1010 0100
= 1111 1100 <=> 0xFC
*/
return 0;
}
/* Đây là ví dụ thực hiện phép AND giữa 2 số 0101 1000 và 1010 0100 */
#include <stdio.h>
int main()
{
unsigned char a = 0x58; // 0101 1000
unsigned char b = 0xA4; // 1010 0100
return 0;
}
19
Chương 4 – Digital Chinh phục ngôn ngữ C
/* Đây là ví dụ thực hiện phép XOR giữa 2 số 0101 1001 và 1010 0101 */
#include <stdio.h>
int main()
{
unsigned char a = 0x59; // 0101 1001
unsigned char b = 0xA5; // 1010 0101
printf("%x", a ^ b);
/* Kết quả sẽ in ra:
0101 1001
XOR 1010 0101
= 1111 1100 <=> 0xFC
*/
return 0;
}
int main()
{
unsigned char a = 0x59; // 0101 1001
printf("%x", ~a);
/* Kết quả sẽ in ra:
NOT 0101 1001
= 1010 0110 <=> 0xA6 (chính xác sẽ là 0xFFFFFFA6 nhé)
Nếu các bạn thắc mắc về chuyện này thì để lại comment bên dưới nhé.
*/
return 0;
}
20
Chương 4 – Digital Chinh phục ngôn ngữ C
Chúng ta đi vào một đoạn code để chúng minh cho điều vừa nói.
int main()
{
int a = (9 > 5) || (1 == 0);
/*
(9 > 5), cái này đúng sẽ cho ra True
(1 == 0), cái này bậy nên sẽ cho ra False
True || False = True
Nên kết quả sẻ in ra 1.
*/
return 0;
}
int main()
{
int a = (9 > 5) && (1 == 0);
/*
(9 > 5), cái này đúng sẽ cho ra True
(1 == 0), cái này bậy nên sẽ cho ra False
True && False = False
Nên kết quả sẻ in ra 0.
*/
return 0;
}
21
Chương 4 – Digital Chinh phục ngôn ngữ C
!False = True
int main()
{
int a = (9 > 5) && (1 == 0);
int b = 100;
/*
(9 > 5), cái này đúng sẽ cho ra True
(1 == 0), cái này bậy nên sẽ cho ra False
True && False = False
*/
return 0;
}
Để ý thằng b trên đoạn code, nó là một số integer ban đầu được gán 100 , vậy mà đưa cho nó 2 cái dấu
!! nó câm lặng về 1 liền. :)))
Điều này giải thích khá dễ, ngoài 1 là true ra (đương nhiên 0 là false rồi) thì tất cả các số còn lại máy
tính hiểu nó là true hết.
Cho nên !b = !True = False
!(!b) = !False = True . Thì sẽ in ra một. True thì máy tính sẽ in ra 1 , tất cả các số còn lại trừ số 0
máy tính sẽ hiểu là True .
22
Chương 4 – Digital Chinh phục ngôn ngữ C
Một ví dụ trong C:
#include <stdio.h>
int main()
{
int a = 2;
printf("%d", a << 1); // Kết quả in ra 4
// 2 = ... 0000 0010
// 2 << 1 = ... 0000 0100 <=> 0x4 = 4
return 0;
}
Nhưng khi chúng ta khai báo signed (nghĩa là số có dấu) thì mọi chuyện sẽ khác.
Cho A = 1000 0000 (với khai báo: signed char a = 0x80; )
A >> 1 = 1100 0000
Các bạn có hiểu vấn đề chưa? Khi một số có dấu thì cái bit được thêm vào trong khi dịch chính là bit dấu
(MSB ).
Lấy ví dụ thực tế
23
Chương 4 – Digital Chinh phục ngôn ngữ C
#include <stdio.h>
int main()
{
unsigned char a = -128; // 0x80
char b = -128; // 0x80 <=> 1000 0000
return 0;
}
Tại sao kết quả in ra -64 thì mời các bạn đọc lại bài trước ở phần số bù 2.
Chúng ta có một số công thức về phép dịch: a << n = a * 2^N và a >> n = a / 2^N
Các bạn không cần phải nhớ mấy cái công thức này (mình chẳng bao giờ nhớ), mà các bạn cần phải hiểu
rõ bản chất thật sự của vấn đề. Vì mục đích học C là để thấu hiểu hơn về phần cứng.
int main()
{
int a = 10, b = 10;
if (a = 5)
b--;
printf("%d, %d", a, b--);
return 0;
}
Bạn sẽ trả lời như thế nào? Dừng lại và thử suy nghĩ để trả lời cho mình trước khi đọc tiếp!
Câu trả lời: 5, 9
Giải thích cho bài toán trên: trong dòng if ở phía trên, có vẻ như chúng ta đã thiếu 1 dấu = .
Thay vì if (a == 5) thì đây lại là if (a = 5) . Tình cờ đây là một phép gán, và trong C chấp nhận
điều này. Và lúc này biến a đã mang giá trị 5 . Bởi vì điều kiện trong if là một phép gán (thành công),
cho nên nó luôn luôn trả về true , và lệnh b--; trong if sẽ được thực hiện. Suy ra b sẽ là 9 trước khi in
ra màn hình.
Một bài toán khác, đây là bài mình đánh giá khá hay và rất dễ xuất hiện trong các bài toán tuyển dụng.
24
Chương 4 – Digital Chinh phục ngôn ngữ C
int main()
{
int i = 10, j = 0;
if (i || (j = i + 10))
printf("%d", j);
return 0;
}
Các bạn dừng lại và suy nghĩ một chút về câu trả lời nhé. Đáp án rất bất ngờ…
Câu trả lời: 0
Giải thích: Trong câu điều kiện if , vế bên trái của phép “|| ” là i (mà i ở đây đang = 10 nghĩa là
true ). True nó có OR với thằng nào thì cũng là true cả, nên vế bên phải sẽ không được thực hiện, và
đương nhiên j vẫn dữ giá trị 0 . Hay đúng không?
6. Dấu ngoặc chết chóc và “đừng bao giờ thử thách trí nhớ của mình với ngôn
ngữ C”
Trong ngôn ngữ C/C++, có một cái bảng gọi là… thứ tự ưu tiên của các phép toán. Mà đa số lập trình
viên C/C++ đều không thể nhớ nó (kể cả mình), nhưng oái ăm một điều, mấy anh phỏng vấn thì lại thích
mấy cái đó mới hay.
Đại loại như ví dụ sau:
#include <stdio.h>
int main()
{
int a = 10, b = 5, c = 5;
int d;
d = b + c == a;
printf("%d", d); // Kết quả in ra 1
return 0;
}
Kết quả in ra d = 1 . Vì phép “+ ” ưu tiên đầu tiên, nên b + c thực hiện trước cho ra 10 . Sau đó phép
“== ” ưu tiên tiếp theo (10 == 10 đúng (true )) nên cuối cùng d = 1 .
Khổ nổi là mấy người trong anh em chúng ta nhớ nó. Vậy mà đi phỏng vấn người tahỏi vậy để thử trí nhớ
siêu phàm của ứng viên.
Lời khuyên chân thành: Nếu đi phỏng vấn mình khuyến khích các bạn học những thứ này để hoàn thành
được bài phỏng vấn tốt và ghi điểm trong mắt người tuyền dụng. Còn khi đã trở thành developer, tuyệt
đối không được thử trí thông minh của bản thân bằng những dòng code như thế này. Vì nó chỉ làm cho
bạn và đồng nghiệp thêm nhức đầu thôi, khó hiểu và đặc biệt là khó bảo trì (maintenance). Đó là ý kiến
của mình, các bạn ai có ý kiến khác thì hãy để lại comment bên dưới.
Các bạn dev chất hãy sửa lại đoạn code như sau để dễ đọc và dễ hiểu:
25
Chương 4 – Digital Chinh phục ngôn ngữ C
#include <stdio.h>
int main()
{
int a = 10, b = 5, c = 5;
int d;
d = ((b + c) == a);
printf("%d", d); // Kết quả in ra 1
}
Có một bài toán rất hay, đề bài thì mình đã ghi trong phần comment rồi nha.
/*
Bài toán hoán đổi các bit trong một biến 8 bit
a7a6a5a4 a3a2a1a0 =====> a0a1a2a3 a4a5a6a7
int main()
{
unsigned char a = 0xA3; // <=> 1010 0011
unsigned char result = 0;
int i = 0;
for(i; i < 8; ++i)
{
result = result | (((a >> (7 - i)) & 0x01) << i);
}
26
Chương 5 – Kết Chinh phục ngôn ngữ C
CHƯƠNG 5 – KẾT
Chúng ta đã đi qua hai phần thuộc dạng khó nhất của lập trình C: pointer và digital. Khi bạn đã thật sự
nắm được 2 phần này, bạn gần như đã chinh phục được lập trình C rồi. Mặc dù vẫn còn nhiều phần khó
khác trong C như: struct, union, debug, ... nhưng sẽ dễ dàng cho bạn khi đã chinh phục được pointer và
digital.
Trong giới hạn ebook này, mình khổng thể đi hết được toàn bộ những thứ có trong pointer hay digital,
nhưng có thể nói mình đã đi được gần như 80, 90% rồi. Có chăng là những thứ phối hợp phức tạp với
nhau khi bạn thực hiện một project lớn nào đó. Khi đó bạn sẽ phối hợp rất nhiều thứ phức tạp với nhau.
Đòi hỏi kĩ năng lập trình bạn phải rất cao.
Thật sự để chinh phục 2 phần này không phải là chuyện dễ dàng, có nhiều bạn mặc dù đã học pointer
nhiều lần, nhưng vẫn không thể nào hiểu vào chinh phục được nó. Mình cũng xin nhắc lại, hãy kiên trì
theo đuổi đam mê, thành công sẽ đến với bạn.
Nếu bạn cảm thấy ebook này đem lại giá trị cho bạn, bạn có thể cám ơn mình bằng cách chia sẻ ebook
này đến nhiều người hơn nhé.
27
Tài liệu tham khảo Chinh phục ngôn ngữ C
28