• Task 9 [ Lập trình C cơ bản ]


    1. học và tóm tắt nội dung session 13 trong sách tiếng Anh


    1. Con trỏ là gì?
    -con trỏ  là một biến, nó chứa địa chỉ vùng nhớ của một biến khác, chứ không lưu trữ giá trị của biến đó. Nếu một biến chứa địa chỉ của một biến khác, thì biến này được gọi là con trỏ đến biến thứ hai kia. Một con trỏ cung cấp phương thức gián tiếp để truy xuất giá trị của các phần tử dữ liệu.

    2.Khi nào thì sử dụng con trỏ?
    - Để trả về nhiều hơn một giá trị từ một hàm
     Thuận tiện hơn trong việc truyền các mảng và chuỗi từ một hàm đến một hàm khác
      Sử dụng con trỏ để làm việc với các phần tử của mảng thay vì truy xuất trực tiếp vào các phần tử này
     Để cấp phát bộ nhớ động và truy xuất vào vùng nhớ được cấp phát này (dynamic memory allocation)

    3.Con trỏ có phải là biến không? cách khai báo con trỏ?
    - Con trỏ cũng là một biến nhưng nó không chứa giá trị giống như các biến khác mà giá trị của con trỏ là địa chỉ vùng nhớ của một biến khác.
    Nếu một biến được sử dụng như một con trỏ, nó phải được khai báo trước. Câu lệnh khai báo con trỏ bao gồm một kiểu dữ liệu cơ bản, một dấu *, và một tên biến. Cú pháp tổng quát để khai báo một biến con trỏ như sau:
    type *name
    trong đó type là kiểu dữ liệu của biến mà con chỏ chỉ đến.

    4.Có mấy toán tử đặc biết với con trỏ?
    - chỉ có hai toán tử đặc biết đối với con trỏ la * và &:
    -var2 = &var1;
    lấy địa chỉ vùng nhớ của biến var1 gán cho var2. Địa chỉ này là vị trí ô nhớ bên trong máy tính của biến var1 và nó không làm gì với giá trị của var1. Toán tử & có thể hiểu là trả về “địa chỉ của”. Vì vậy, phép gán trên có nghĩa là “var2 nhận địa chỉ của var1”. 
    -Toán tử thứ hai, toán tử *, được dùng với con trỏ là phần bổ xung của toán tử &, toán tử *. Nó là một toán tử một ngôi và trả về giá trị chứa trong vùng nhớ được trỏ bởi giá trị của biến con trỏ.
    Xem ví dụ trước, ở đó var1 có giá trị 500 và được lưu trong vùng nhớ 1000, sau câu lệnh 
              var2 = &var1; 
    var12 chứa giá trị 1000, và sau lệnh gán
              temp = *var2;

    5. Gán giá trị cho con trỏ?
    Các giá trị có thể được gán cho biến con trỏ thông qua toán tử &. Câu lệnh gán sẽ là:
              ptr_var = &var;
    Lúc này địa chỉ của var được lưu trong biến ptr_var. Cũng có thể gán giá trị cho con trỏ thông qua một biến con trỏ khác trỏ đến một phần tử dữ liệu có cùng kiểu.
              ptr_var = &var;
        ptr_var2 = ptr_var;
    Giá trị NULL cũng có thể được gán đến một con trỏ bằng số 0 như sau:
              ptr_var = 0;
    Các biến cũng có thể được gán giá trị thông qua con trỏ của chúng.
              *ptr_var  =  10;
    sẽ gán 10 cho biến var nếu ptr_var trỏ đến var.

    6. Những phép toán số học nào được thực hiện với con trỏ?
    -chỉ có phép cộng và trừ được thực hiện, bản chất là tiến và lùi con trỏ đi một số địa chỉ tương ứng.
    -ngoài ra còn có phép so sánh cho vị trí mà các con trỏ chỉ đến

    ptr_a < ptr_b
    Trả về giá trị true nếu a được lưu trữ ở vị trí trước b
    ptr_a > ptr_b
    Trả về giá trị true nếu a được lưu trữ ở vị trí sau b
    ptr_a <= ptr_b
    Trả về giá trị true nếu a được lưu trữ ở vị trí trước b hoặc ptr_a và ptr_b trỏ đến cùng một vị trí
    ptr_a >= ptr_b
    Trả về giá trị true nếu a được lưu trữ ở vị trí sau b hoặc ptr_a và ptr_b trỏ đến cùng một vị trí
    ptr_a == ptr_b
    Trả về giá trị true nếu cả hai con trỏ ptr_a và ptr_b trỏ đến cùng một phần tử dữ liệu.
    ptr_a != ptr_b
    Trả về giá trị true nếu cả hai con trỏ ptr_a và ptr_b trỏ đến các phần tử dữ liệu khác nhau nhưng có cùng kiểu dữ liệu.
    ptr_a == NULL
    Trả về giá trị true nếu ptr_a được gán giá trị NULL (0)

    7. Con trỏ và mảng một Chiều?
    Tên của một mảng thật ra là một con trỏ trỏ đến phần tử đầu tiên của mảng đó. Vì vậy, nếu ary là một mảng một chiều, thì địa chỉ của phần tử đầu tiên trong mảng có thể được biểu diễn là &ary[0] hoặc đơn giản chỉ là ary. Tương tự, địa chỉ của phần tử mảng thứ hai có thể được viết như &ary[1] hoặc ary+1,... Tổng quát, địa chỉ của phần tử mảng thứ (i + 1) có thể được biểu diễn là &ary[i] hay (ary+i). Như vậy, địa chỉ của một phần tử mảng bất kỳ có thể được biểu diễn theo hai cách:
    Sử dụng ký hiệu & trước một phần tử mảng
    -Sử dụng một biểu thức trong đó chỉ số được cộng vào tên của mảng.
    Khi gán một giá trị cho một phần tử mảng như ary[i], vế trái của lệnh gán có thể được viết là ary[i] hoặc *(ary + i). Vì vậy, một giá trị có thể được gán trực tiếp đến một phần tử mảng hoặc nó có thể được gán đến vùng nhớ  mà địa chỉ của nó là phần tử mảng. Đôi khi cần thiết phải gán một địa chỉ đến một định danh. Trong những trường hợp như vậy, một con trỏ phải xuất hiện trong vế trái của câu lệnh gán. Không thể gán một địa chỉ tùy ý cho một tên mảng hoặc một phần tử của mảng. Vì vậy, các biểu thức như ary, (ary + i) và &ary[i] không thể xuất hiện trong vế trái của một câu lệnh gán. Hơn thế nữa, địa chỉ của một mảng không thể thay đổi một cách tùy ý, vì thế các biểu thức như ary++ là không được phép. Lý do là vì: ary là địa chỉ của mảng ary. Khi mảng được khai báo, bộ liên kết đã quyết định mảng được bắt đầu ở đâu, ví dụ, bắt đầu ở địa chỉ 1002. Một khi địa chỉ này được đưa ra, mảng sẽ ở đó. Việc cố gắng tăng địa chỉ này lên là điều vô nghĩa

    8. Con trỏ với mảng nhiều chiều?
    Một mảng nhiều chiều cũng có thể được biểu diễn dưới dạng con trỏ của mảng một chiều (tên của mảng) và một độ dời (chỉ số). Thực hiện được điều này là bởi vì một mảng nhiều chiều là một tập hợp của các mảng một chiều.Ví dụ, một mảng hai chiều có thể được định nghĩa như là một con trỏ đến một nhóm các mảng một chiều kế tiếp nhau. Cú pháp báo mảng hai chiều có thể viết như sau:

        data_type (*ptr_var)[expr 2];

    thay vì

        data_type array[expr 1][expr 2];

    Khái niệm này có thể được tổng quát hóa cho các mảng nhiều chiều, đó là,

        data_type (*ptr_var)[exp 2] .... [exp N];

    thay vì

        data_type array[exp 1][exp 2] ... [exp N];

    Trong các khai báo trên, data_type là kiểu dữ liệu của mảng, ptr_var là tên của biến con trỏ, array là tên mảng, vàexp 1, exp 2, exp 3, ... exp N là các giá trị nguyên dương xác định số lượng tối đa các phần tử mảng được kết hợp với mỗi chỉ số.

    Chú ý dấu ngoặc () bao quanh tên mảng và dấu * phía trước tên mảng trong cách khai báo theo dạng con trỏ. Cặp dấu ngoặc () là không thể thiếu, ngược lại cú pháp khai báo sẽ khai báo một mảng của các con trỏ chứ không phải một con trỏ của một nhóm các mảng.

    9. Con trỏ và chuỗi?
    Chuỗi đơn giản chỉ là một mảng một chiều có kiểu ký tự. Mảng và con trỏ có mối liên hệ mật thiết, và như vậy, một cách tự nhiên chuỗi cũng sẽ có mối liên hệ mật thiết với con trỏ. Xem trường hợp hàm strchr(). Hàm này nhận các tham số là một chuỗi và một ký tự để tìm kiếm ký tự đó trong mảng, nghĩa là,

        ptr_str = strchr(strl, ‘a’);

    biến con trỏ ptr_str sẽ được gán địa chỉ của ký tự ‘a’ đầu tiên xuất hiện trong chuỗi str. Đây không phải là vị trí trong chuỗi, từ 0 đến cuối chuỗi, mà là địa chỉ, từ địa chỉ bắt đầu chuỗi đến địa chỉ kết thúc của chuỗi.

    Chương trình sau sử dụng hàm strchr(), đây là chương trình cho phép  người dùng nhập vào một chuỗi và một ký tự để tìm kiếm. Chương trình in ra địa chỉ bắt đầu của chuỗi, địa chỉ của ký tự, và vị  trí tương đối của ký tự trong chuỗi (0 là vị trí của ký tự đầu tiên, 1 là vị trí của ký tự thứ hai,...). Vị trí tương đối này là hiệu số giữa hai địa chỉ, địa chỉ bắt đầu của chuỗi và địa chỉ nơi mà ký tự cần tìm đầu tiên xuất hiện.

    10. cấp phát bộ nhớ?
    -Nếu một mảng được khai báo một cách bình thường, kết quả là một khối bộ nhớ cố định được dành sẵn tại thời điểm bắt đầu thực thi chương trình, trong khi điều này không xảy ra nếu mảng được khai báo như là một biến con trỏ. Sử dụng một biến con trỏ để biểu diễn một mảng đòi hỏi việc gán một vài ô nhớ khởi tạo trước khi các phần tử mảng được xử lý. Sự cấp phát bộ nhớ như vậy thông thường được thực hiện bằng cách sử dụng hàm thư viện malloc().
    -Xem ví dụ sau. Một mảng số nguyên một chiều ary có 20 phần tử có thể được khai báo như sau:

    int *ary;

    thay vì

    int ary[20];

    Tuy nhiên, ary sẽ không được tự động gán một khối bộ nhớ khi nó được khai báo như là một biến con trỏ, trong khi một khối ô nhớ đủ để chứa 10 số nguyên sẽ được dành sẵn nếu ary được khai báo như là một mảng. Nếu ary được khai báo như là một con trỏ, số lượng bộ nhớ có thể được gán như sau:

              ary = malloc(20 *sizeof(int));



    Sẽ dành một khối bộ nhớ có kích thước (tính theo bytes) tương đương với kích thước của một số nguyên. Ở đây, một khối bộ nhớ cho 20 số nguyên được cấp phát. 20 con số gán với 20 bytes (một byte cho một số nguyên) và được nhân với sizeof(int), sizeof(int) sẽ trả về kết quả 2, nếu máy tính dùng 2 bytes để lưu trữ một số nguyên. Nếu một máy tính sử dụng 1 byte để lưu một số nguyên, hàm sizeof() không đòi hỏi ở đây. Tuy nhiên, sử dụng nó sẽ tạo khả năng uyển chuyển cho mã lệnh. Hàm malloc() trả về một con trỏ chứa địa chỉ vị trí bắt đầu của vùng nhớ được cấp phát. Nếu không gian bộ nhớ yêu cầu không có, malloc() trả về giá trị NULL. Sự cấp phát bộ nhớ theo cách này, nghĩa là, khi được yêu cầu trong một chương trình được gọi là Cấp phát bộ nhớ động.

    Tóm tắt Session 13 ( Xmind )


    2. gõ lại toàn bộ ví dụ của session 13, giải thích code




    4.hoàn thiện bài tập trên lớp về việc đếm số lần xuất hiện, tính % xuất hiện, của các ký tự nguyên âm aiueo.
  • 0 nhận xét:

    Đăng nhận xét

    QUOTE & QUOTE

    Without requirements or design, programming is just the art of adding bugs to a blank text file.

    ADDRESS

    100000, My Dinh, Ha Noi, VN

    EMAIL

    minhbu883@mail.com
    minhnn17@fsoft.com.vn

    TELEPHONE

    +84964 214 883

    MOBILE

    +8438 5689 888