Exercise 15 Lập Trình C – Learn C The Hard Way


Exercise 15: Pointers Dreaded Pointers

Bài hôm nay các bạn phải học theo mình đánh giá, đây là bài quan trọng nhất trong series này. Rộng hơn thì có thể nói Pointer (con trỏ) là một trong những kiến thức quan trọng bậc nhất trong ngôn ngữ C, đặt biệt là trong lập trình nhúng.
Vì những lý do đó cho nên các bạn phải học kĩ bài này và mình sẽ viết thật kĩ.
Các bạn nên học bài này trước để hiểu con trỏ là gì:
Cơ bản về con trỏ phần 1
Có thể học luôn phần 2 cũng được.
Khi các bạn hiểu con trỏ là gì thì chúng ta tiếp tục.
Tạo Makefile và file ex15.c như sau:

#include <stdio.h>

int main(int argc, char *argv[])
{
    // create two arrays we care about
    int ages[] = {23, 43, 12, 89, 2};
    char *names[] = {
        "Alan", "Frank",
        "Mary", "John", "Lisa"
    };
    // safely get the size of ages
    int count = sizeof(ages) / sizeof(int);
    int i = 0;

    // first way using indexing
    for(i = 0; i < count; i++)
    {
        printf("%s has %d years alive.\n",
                names[i], ages[i]);
    }

    printf "---\n");

    // setup the pointers to the start of the arrays
    int *cur_age = ages;
    char **cur_name = names;

    // second way using pointers
    for(i = 0; i < count; i++)
    {
         printf("%s is %d years old.\n",
                 *(cur_name+i), *(cur_age+i));                 
    }

    printf("---\n");

    // third way, pointers are just arrays
    for(i = 0; i < count; i++)
    {
        printf("%s is %d years old again.\n",
                cur_name[i], cur_age[i]);
    }

    printf("---\n");

    //fourth way with pointers in a stupid complex way
    for(cur_name = names, cur_age = ages;
            (cur_age - ages) < count;
            cur_name++, cur_age++)
    {
        printf("%s lived %d years so far.\n",
                *cur_name, *cur_age);
    }
    
    return 0;
}

Lưu ý: Có thể khi các bạn viết xong sẽ không hiểu code, lúc này các bạn hãy đọc lại từng dòng để nghiên cứu. Sau đó mới xuống phần giải thích code.
Bởi vì từ bài này trở đi thì kiến thức nó khá là khó rồi, cho nên các bạn phải tập trung học cho đáng nhé!

Giải thích code

1. Dòng 6 – 10: Tạo 2 mảng, ages dùng để chứa một vài biến kiểu int, và names là mãng chứa các chuỗi (nghĩa là 1 phần tử trong mảng sẽ là một chuỗi kí tự).
2. Dòng 12 – 13: Tạo 2 biến cho for-loops phía sau nó.
3. Dòng 16 – 20: Vòng lặp thông qua biến i để trỏ tới từng phần tử trong mảng để in ra tên và số tuổi của mỗi người.
4. Dòng 25: Tạo một con trỏ trỏ tới ages (nghĩa là con trỏ này sẽ trỏ tới mảng, chúng ta bây giờ chỉ cần thực hiện các thao tác trên con trỏ nghĩa là đã thực hiện thao tác trên mảng). Chú ý rằng int * là kiểu dữ liệu của con trỏ (con trỏ kiểu int hay con trỏ trỏ tới dữ liệu kiểu int). Nó giống như là char *, nghĩa là con trỏ trỏ tới vùng dữ kiểu char. Các bạn đã hiểu chưa?
5. Dòng 26: Tương tự như dòng 25. Đây là con trỏ cấp 2. Chúng ta phân tích thế này char * trỏ tới vùng nhớ kiểu char (con trỏ này sẽ điều khiển 1 chuỗi), char ** là con trỏ trỏ tới con trỏ char * (con trỏ này sẽ trỏ tới 1 mảng, mà các phần tử trong mảng là chuỗi kí tự).
6. Dòng 29 – 33: VÒng lặp for để xuất tên và tuổi của từng người ra, chức năng y chang vòng lặp for hồi nãy nhưng ở đây truy xuất dữ liệu mảng bằng con trỏ. *(cur_name+i) cùng chức năng names[i]. Chúng ta sẽ đọc *(cur_name+i) là “giá trị của (con trỏ cur_name cộng i)”.
7. Dòng 38 – 42: Lệnh for này cũng y chang lệnh for hồi nãy. Chúng ta có thể sử dụng con trỏ giống như mảng.
8. Vòng for cuối cùng và cũng hay nhất: Hãy nhớ lại cấu trúc của for.
– Dòng 47: Khởi tạo for-loop bằng cách gán cur_namecur_age trỏ tới phần tử đầu của mảng namesages.
– Dòng 48: Điều kiện để kết thúc vòng lặp for. Khi nào mà cur_ages trỏ tới phần tử cuối thì khi trừ với ages sẽ bằng count và kết thúc.
– Dòng 49: tăng 2 biến cur_namcur_age lên thôi.
Lưu ý: Các con trỏ trên chứa địa chỉ, và khi tăng con trỏ lên 1, nghĩa là đưa con trỏ trỏ tới phần tử tiếp theo của mảng.

Các bạn phải chạy ra kết quả như sau:

$ make ex15 
cc -Wall -g ex15.c -o ex15 
$ ./ex15 
Alan has 23 years alive. 
Frank has 43 years alive. 
Mary has 12 years alive. 
John has 89 years alive. 
Lisa has 2 years alive. 
---
Alan is 23 years old. 
Frank is 43 years old. 
Mary is 12 years old. 
John is 89 years old. 
Lisa is 2 years old. 
---
Alan is 23 years old again. 
Frank is 43 years old again. 
Mary is 12 years old again. 
John is 89 years old again. 
Lisa is 2 years old again. 
---
Alan lived 23 years so far. 
Frank lived 43 years so far. 
Mary lived 12 years so far. 
John lived 89 years so far. 
Lisa lived 2 years so far. 
$

Chúng ta tạm thời kết thúc ở đây và bài này sẽ còn tiếp tục. Các bạn hãy tham khảo thêm 2 bài về con trỏ mà mình để phía trên để hiểu hơn về con trỏ.

Advertisements

3 thoughts on “Exercise 15 Lập Trình C – Learn C The Hard Way

  1. int ages[] = {23, 43, 12, 89, 2};
    char *names[] = {“Alan”, “Frank”, “Mary”, “John”, “Lisa” };
    ages[] = {23, 43, 12, 89, 2} có nghĩa là ages[0]=23, …., ages[4]=2,
    tương tự như vậy thì names[0]=”Alan”…, nhưng sao lại cần con trỏ?
    khai báo int *ages[] = {23, 43, 12, 89, 2}; thì bị báo lỗi.
    vì sao int thì không được con trỏ, mà string phải có con trỏ?

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s