Trang 1 trên tổng số 3 123 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 30 kết quả

Đề tài: Mảng 2 chiều , con trỏ đến con trỏ và cấp phát động

  1. #1
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Mặc định [C] Mảng 2 chiều, con trỏ đến con trỏ và cấp phát bộ nhớ động cho mảng 2 chiều

    Theo yêu cầu của kengoaidao, bài viết này sẽ tập chung vào mảng 2 chiều và con trỏ đến con trỏ. Sau đó tôi sẽ trình bày một số phương pháp để cấp phát bộ nhớ động cho mảng 2 chiều.

    1. Mảng 2 chiều

    Cách dễ nhất để hiểu được bản chất của mảng n chiều là ta bắt đầu từ mảng 1 chiều. Theo định nghĩa, mảng là một dãy các phần tử nằm liên tiếp nhau trong bộ nhớ. Các phần tử của mảng có chung 1 kiểu và có cùng 1 tên. Để phần biệt các phần tử với nhau, ta dùng chỉ số. Kiểu các phần tử ở đây có thể là char, int, double, struct, user defined type v.v... Một cách tổng quát, ta có thể viết như sau:

    PHP Code:
    type array[size]; 
    trong bộ nhớ, mảng được biểu diễn thế này:

    PHP Code:
    |sizeof(type)|....|sizeof(type)| 
    Ta có thể định nghĩa một kiểu mới là một mảng như sau:

    PHP Code:
     typedef int ArrayOfInt[10]; 
    sau khi định nghĩa thì ta có thể dùng kiểu của chúng ta như những kiểu khác, ví dụ khai báo 1 biến:

    PHP Code:
    ArrayOfInt my_array
    ở đây my_array sẽ là một mảng có 10 phần tử kiểu int. Để truy cập đến từng phần tử thì ta dùng như với mảng bình thường:

    PHP Code:
    my_array[0] = 0
    Kiểu do chúng ta định nghĩa cũng có thể là phần tử của 1 mảng:

    PHP Code:
    ArrayOfInt array[5]; 
    Trong trường hợp này, mảng array sẽ được biểu diễn trong bộ nhớ như sau:

    PHP Code:
    |sizeof(ArrayOfInt)|...|sizeof(ArrayOfInt)| 
    Chắc bạn cũng đã đoán ra, array ở đây chính là mảng 2 chiều. Compiler có đủ thông minh để tự làm được những bước kể trên, vì thế để khai báo 1 mảng 2 chiều thì chúng ta chỉ việc khai báo thế này là đủ:

    PHP Code:
    int array[5][10]; 
    Khi ta muốn truy cập đến 1 phần tử của mảng 2 chiều thì ta dùng cú pháp quen thuộc:

    PHP Code:
    el = array[2][3]; 
    Khi gặp những biểu thức như vậy thì đầu tiên, trình dịch sẽ tính xem array[2] là gì:

    PHP Code:
    el = *(array + 2)[3]; 
    Như tôi đã nói trong bài trước, biểu thức *(array + 2) có nghĩa là ta muốn truy cập đến phần tử thứ 3 của array. Mặt khác, phần tử của array là mảng có 10 phần tử kiểu int, nên chỉ số 3 tiếp theo sẽ được tính theo cú pháp của mảng. Kết quả ta sẽ có:

    PHP Code:
    el = *(*(array + 2) + 3); 
    để tính được biểu thức *(array + 2) thì trình dịch cần phải biết rõ kiểu ArrayOfInt có bao nhiêu bytes, nói cách khác là ta cần phải cung cấp rõ là ArrayOfInt là mảng có bao nhiêu phần tử. Chính vì lý do đó mà khi khai báo 1 mảng nhiều chiều, thì ta chỉ có thể bỏ qua kích thước thứ nhất, những kích thước còn lại ta cần phải chỉ rõ. Khi truyền mảng nhiều chiều cho hàm thì cũng có yêu cầu tương tự:

    PHP Code:
    void func(int arr[][10])
       {
           ...
       }
       
    func(array); 
    ở đây, nhờ vào số 10 ta cung cấp, trình dịch có thể tìm được phần tử ta muốn truy cập arr[m][n] dựa theo công thức trên. Cũng từ công thức trên, ta suy ra một điều là với mảng:

    PHP Code:
     int array[5][10]; 
    thì array có thể coi như là:

    PHP Code:
    int (*array)[10]; 
    Tức là, có thể coi array là mảng mà các phần tử của nó là con trỏ đến mảng có 10 phần tử kiểu int. Và nếu ta muốn gán array cho 1 con trỏ thì ta cũng phải khai báo con trỏ đó theo cú pháp tương tự:

    PHP Code:
    int array[5][10];
       
    int (*pointer)[10];
       
    pointer = array; 
    Dấu ngoặc ở đây không được phép thiếu, nếu không thì ta sẽ thu được kết quả khác:

    PHP Code:
    int *pointer[10]; 
    trường hợp này, trình dịch sẽ hiểu là pointer là mảng có 10 phần tử là con trỏ đến kiểu int. Nếu ta khai báo con trỏ khác đi thì sao?

    PHP Code:
    int (*pointer)[11]; 
    khi đó phép gán pointer=array không còn hợp lệ nữa và trình dịch sẽ báo lỗi ngay.

    2. Con trỏ đến con trỏ

    Tương tự như mảng 2 chiều, để hiểu được con trỏ đến con trỏ thì tốt nhất là ta băt đầu với con trỏ. Trước hết, con trỏ là một biến mà giá trị của nó là 1 đia chỉ trong bộ nhớ. Để có thể thực hiện được các phép tính số học với con trỏ thì ta cần phải chỉ rõ là con trỏ đó trỏ đên kiểu gì. Dạng tỗng quát là:

    PHP Code:
    type *pointer
    Trường hợp type là một con trỏ thì sao? khi đó ta có con trỏ đến con trỏ. Điều đó hoàn toàn hợp lệ, vì con trỏ là 1 biến nên nó cũng có địa chỉ trong bộ nhớ, giống như 1 biến kiểu char, int v.v... Khi ta dùng toán tử lấy giá trị của biến do con trỏ đến con trỏ đang chỉ tới thì ta thu được type, tức là con trỏ. Ví dụ:

    PHP Code:
    int i;
       
    int *pi=&i;
       
    int **ppi = &pi
    khi đó *ppi sẽ cho ta con trỏ đến kiểu int. Trường hợp ta muốn lấy giá trị của biến do con trỏ int đang trỏ tới thì ta phải dùng 2 dấu *. Tức là:

    PHP Code:
     int value = **ppi
    Biểu thức này mới nhìn có vẻ khó hiểu, nhưng nếu ta cứ suy luận từng bước sẽ thấy ngay. Trước hết *ppi là con trỏ kiểu int. Để lấy giá trị do con trỏ đến int chỉ tới thì ta dung dấu *. Như vậy ta phải cần *(*ppi), cũng tức là **ppi.

    Nếu bạn để ý thì với con trỏ đến int, tôi dùng tên pi, còn con trỏ đến con trỏ đến int, tôi dùng ppi. Đó là tôi đã áp dụng Hungarian Notation. Cách viết này nhiều lúc sẽ giúp chúng ta dễ hiểu hơn. Cụ thể là với cách viết này, mỗi dấu * sẽ trung hoà 1 chữ 'p'. Như thế:

    PHP Code:
      *ppi <==> pi (tức là con trỏ đến int)
       **
    ppi <==> (tức là kiểu int
    nhờ đó mỗi khi mà ta nghi hoăc không biết *ppi có kiểu gì thì chỉ cần quan sát kỹ là sẽ thấy ngay. Nói chung cách viết này cũng có nhiều người ủng hộ và nhiều người chống đối. Bạn đầu khi bạn mới làm quen với con trỏ thì nên áp dụng kiểu viết do. Nó sẽ giúp bạn dễ hiểu hơn đó.

    Cũng giống như con trỏ đến int khác con trỏ đến char, con trỏ đến con trỏ đến int sẽ khác con trỏ đến con trỏ đến char. Và nếu ta tìm cách gán địa chỉ của 1 con trỏ cho một con trỏ đến con trỏ thì ta phải bảo đảm là kiểu của chúng giống nhau. Nếu không thì trình dịch sẽ báo lỗi.

    3. Cấp phát bộ nhớ động cho mảng 2 chiều

    Vấn đề này được khá nhiều người quan tâm tới. Như ta đã biết, trong C muốn cấp phát bộ nhớ động thì gọi hàm malloc(). Nhưng mà hàm này thì chỉ nhận tống số bytes cần cấp phát và trả lại kiểu void *. Vậy thì làm thế nào để cấp phát 1 vùng bộ nhớ, sau đó ta có thể dùng cú pháp của mảng 2 chiều để truy cập? Giả sư ta cần cấp phát mảng 2 chiều 5 x 10 có kiểu int. Có 1 số cách như sau:

    - dùng con trỏ đến con trỏ:

    PHP Code:
     int **pp = (int **)malloc(sizeof(int *));
       for (
    int i 05i++)
          
    pp[i] = (int *)malloc(10 sizeof(int)); 
    cách này quá phức tạp. Thêm nữa là các phần tư của mảng sẽ không nằm liền nhau bởi vì ta phải gọi nhiều lần malloc() để cấp phát.

    - cải tiến cách trên một chút:

    PHP Code:
       int **pp = (int **)malloc(sizeof(int *));
       
    int *= (int *)malloc(10 sizeof(int));
       for (
    int i 05i++)
           
    pp[i] = 10
    bây giờ thì các phần tử của mảng đã nằm liền nhau, nhưng cách này cũng chưa phải là tối ưu. Vừa tốn bộ nhớ (thêm 5 con trỏ kiểu int), vừa phải code nhiều hơn. Khi phải giải phóng bộ nhớ thì ta cũng phải giải phóng 2 lần.

    - dựa vào điều ta đã biết là:

    PHP Code:
    type array[M][N] ==> type (*array)[M
    ta có thể khai báo 1 con trỏ như vậy và cấp phát bộ nhớ động cho nó. Đại khái nó sẽ thế này:

    PHP Code:
     int (*p)[10] = (int (*)[10])malloc(sizeof (int [10])); 
    cách này bảo đảm là các phần tử nằm liền nhau, và ta cũng không tốn thêm bộ nhớ. Khi giải phóng thì chỉ cần 1 lần. Và nó cũng gần giống mảng tĩnh nhất so với 2 cách trước. Tuy nhiên nó rắc rối quá, dễ gây nhầm lẫn, và làm cho người khác nhìn vào thấy khó hiểu.

    - dùng typedef để đơn giản hoá vấn đề

    cách này theo đánh giá chủ quan của cá nhân tôi là hay nhất. Ngắn gọn, dễ hiểu và hiệu quả. Cách làm như sau:

    PHP Code:
    typedef int MYARR[10];
       
    MYARR *= (MYARR *)malloc(sizeof (MYARR)); 
    Trường hợp muốn cho mã nguồn portable thì có thể làm thế này:

    PHP Code:
    const int M 5;
       const 
    int N 10;

       
    typedef int MYTYPE;

       
    typedef MYTYPE MYARR[N];
       
    MYARR *= (MYARR *)malloc(sizeof (MYARR)); 
    Khi đó, muốn thay đổi kích thước của mảng, ta chỉ việc thay giá trị cho 2 hằng M và N. Muốn thay kiểu phần tử của mảng thì chỉ cần thay kiểu của MYTYPE.

    Sưu tầm từ diendantinhoc.net
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  2. #2
    Ngày gia nhập
    07 2006
    Bài viết
    121

    Vậy mình làm như sau:
    "Hello" Đây có phải là con trỏ hay không?
    Bạn xem đọan code sau:
    Code:
    #include<stdio.h>
    int main()
    {
       char c="Hello"[0];
       printf("%c",c);
    }
    đọan code này là sao ?
    và tôi có một đọan code như sau:
    Code:
    #include<stdio.h>
    int main()
    {
       int i=0;
       char s[]="Hello";
       char *pch;
       pch=s;
       for(i=0;i<=5;i++)
          printf("%c",i[pch]);
       return 0;
    }
    sao đọan code này vẫn chạy đúng vậy ?

  3. #3
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Dreaminess xin đính chính lại: Chúng ta không nên gọi là con trỏ nhiều chiều, mà Dreaminess tạm thế nó bằng con trỏ cấp n(Tạm nhé)

    Bây giờ trở lại với vấn đề tiếp theo bạn đưa ra:
    #include<stdio.h>
    int main()
    {
    char c="Hello"[0];
    printf("%c",c);
    }
    Cái code này chẳng liên quan gì đến con trỏ cả, nhưng trông thì khá ngộ, nhưng nhìn kỹ thì chẳng có gì cả (Điều hiển nhiên). Bây giờ Dreaminess đi phân tích cho bạn hiểu:
    Xét câu lệnh: char c="Hello"[0];
    - Ở đây bạn khai báo biến c có kiểu char và khởi gán nó bằng một ký tự trong chuỗi "Hello". Tại sao bạn lại phải dùng [0]?, đơn giản là [0] thể hiện vị trí thứ 0 của ký tự trong chuỗi "Hello", trong C conpiler hiểu vậy. Bạn nên nhớ: Chuỗi "Hello" trước hết nó phải được lưu vào vùng nhớ trước khi nó được xử lý, và thực tế trên máy một chuỗi sẽ được lưu trên nhiều vùng nhớ, mỗi vùng nhớ là một byte. Trình dịch đủ thông minh để bố trí và lấy ra các ký tự trong chuỗi đó.Lưu ý rằng một chuỗi(mảng) khi có khởi gán sẽ bắt đầu bằng chỉ số 0 chứ không phải 1.
    Dựa trên những điều nói trên, chương trình của bạn tương đương với:
    Code:
    #include<stdio.h>
    int main()
    {
       char c[]={'H','e','l','l','o'};
       printf("%c",c[0]);
    return 0;
    }
    Đối với vấn đề thứ 2 bạn đưa ra:
    Trước hết xét đoạn code này:
    Code:
    #include<stdio.h>
    int main()
    {
       char c[]={'H','e','l','l','o'};
       printf("%c",1[c]);
    return 0;
    }
    Bạn thấy nó chạy thế nào? Có thể bạn đã hình dung ra vấn đề rồi phải không nào? Bạn chỉ cần hình dung là một mảng được đặt trong bộ nhớ giống như một bảng(hàng và cột), vậy thôi. Ở ví dụ tiếp theo của bạn chẳng khác gì cả. Chỉ có thêm một vòng lặp for mà thôi.
    Con trỏ ở đây bạn dùng chỉ để thay thế s (Tại sao? vui lòng xem lại kiến thức cơ bản về mảng).

    Chúc may mắn.
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  4. #4
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    "Hello" cũng là con trỏ thôi, bạn thử viết là
    char *pch = "Hello" + "World";
    sẽ thấy được trình biên dịch báo lỗi: không thể cộng 2 con trỏ

    thay vì viết:
    char c[]={'H','e','l','l','o'};
    viết là :
    char c[]="Hello";
    ngắn gọn hơn


    viết là
    char c="Hello"[0];
    chẳng qua là viết tắt, chứ không có gì lắt léo ở đây cả

    còn giữa 2 cách viết dưới đây có gì khác nhau:
    char s1[]="Hello"; //s1 tương đương với char[6];
    char *s2="Hello"; // s2 là char*

    char[CONST - hằng số] khác hoàn toàn với char*

    có thể gán
    s2 = s1;
    mà không thể gán s1 = s2
    khác trong phát biểu sizeof()
    sizeof(s1) = 6 //bằng kích thước của mảng
    sizeof(s4) = 4 //luôn bằng 4 cho mọi kiểu con trỏ

  5. #5
    Ngày gia nhập
    07 2006
    Bài viết
    121

    Code:
    #include<stdio.h>
    int main()
    {
       int i=0;
       char s[]="Hello";
       char *pch;
       pch=s;
       for(i=0;i<=5;i++)
          printf("%c",i[pch]);
       return 0;
    }
    bạn chú ý i[pch] có sử ở đây tại sao không sai?

  6. #6
    No Avatar
    lqkhoi Khách

    Mặc định Mảng 2 chiều , con trỏ đến con trỏ và cấp phát động

    Chương trình tiếp theo của bạn là hoàn toàn vô nghĩa. Nếu bạn bỏ cái này vào máy và chạy. Nếu 1 compiler tốt nó sẽ cho bạn vô số error : error lớn nhất là i đâu phải là cái array, tiếp theo pch là pointer ko phải là số.

    Ưu điểm lớn nhất và cũng là nhược điểm lớn nhất của C. Đó chính là sự linh hoạt trong việc quản lý bộ nhớ. Việc check data/memory compliancy trong C compiler là rất hạn chế. Hầu như nó chỉ check syntax là đa số. Và có compiler thêm tính năng này compiler thêm tính năng khác mà việc kiểm tra trong khi compile được strict nhiều hay ít.

    Viết C hay bất cứ 1 ngôn ngữ cấp thấp nào sẽ có 1 chuyện thường ngày ở huyện là : tại sao tao dịch được mà đến lúc run lại tiêu. Ngôn ngữ càng cao , khả năng check ở compiler càng cao, nó giảm thiểu những sai lầm trong việc cấp phát bộ nhớ nhưng nó lại làm giảm sự uyển chuyển. Bằng chứng rõ nhất là sự so sánh giữa C và Java.

    Khi viết C dù compiler có strict hay không strict, cũng phải luôn nắm vững những gì mình viết, đừng trông mong vào chuyện compiler sẽ kiếm lỗi giùm mình.

  7. #7
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Ấy vậy mà đoạn code của bạn shinichi_haha compile và run được mới hay chứ. Tui đã test trên VC++ 6, VC++ 2005, warning level 4 luôn, không có 1 error hay warning gì ráo cả, run tốt, in ra kết quả đàng hoàng. Suy nghĩ 1 hồi mới ra. Các bạn thử tìm xem tại sao.
    Thậm chí có thể sữa code lại cho ngắn là:
    for (i = 0;i < strlen(s); i++)
    printf("%c", i[s]);

  8. #8
    Ngày gia nhập
    07 2006
    Bài viết
    121

    Độc chiêu này muốn hiểu bạn phải biết rõ ít nhất 3 thứ:
    1 con trỏ.
    2 mảng.
    3 các phép toán trên con trỏ.
    Rất ít sách tiếng việt đề cập vấn đề này.

  9. #9
    Ngày gia nhập
    05 2007
    Bài viết
    64

    3. Cấp phát bộ nhớ động cho mảng 2 chiều

    Vấn đề này được khá nhiều người quan tâm tới. Như ta đã biết, trong C muốn cấp phát bộ nhớ động thì gọi hàm malloc(). Nhưng mà hàm này thì chỉ nhận tống số bytes cần cấp phát và trả lại kiểu void *. Vậy thì làm thế nào để cấp phát 1 vùng bộ nhớ, sau đó ta có thể dùng cú pháp của mảng 2 chiều để truy cập? Giả sư ta cần cấp phát mảng 2 chiều 5 x 10 có kiểu int. Có 1 số cách như sau:

    - dùng con trỏ đến con trỏ:


    Code:
    int **pp = (int **)malloc(5 * sizeof(int *));
    for (int i = 0; i < 5; i++)
    pp[i] = (int *)malloc(10 * sizeof(int));

    cách này quá phức tạp. Thêm nữa là các phần tư của mảng sẽ không nằm liền nhau bởi vì ta phải gọi nhiều lần malloc() để cấp phát.

    - cải tiến cách trên một chút:


    Code:
    int **pp = (int **)malloc(5 * sizeof(int *));
    int *p = (int *)malloc(5 * 10 * sizeof(int));
    for (int i = 0; i < 5; i++)
    pp[i] = p + i * 10;

    bây giờ thì các phần tử của mảng đã nằm liền nhau, nhưng cách này cũng chưa phải là tối ưu. Vừa tốn bộ nhớ (thêm 5 con trỏ kiểu int), vừa phải code nhiều hơn. Khi phải giải phóng bộ nhớ thì ta cũng phải giải phóng 2 lần.
    Đúng là cái này đang làm mình đau đầu thật. Cảm ơn admin nhiều nha !!!
    I know... nothing

  10. #10
    Ngày gia nhập
    05 2007
    Bài viết
    14

    Trích dẫn Nguyên bản được gửi bởi Dreaminess Xem bài viết

    Tương tự như mảng 2 chiều, để hiểu được con trỏ đến con trỏ thì tốt nhất là ta băt đầu với con trỏ. Trước hết, con trỏ là một biến mà giá trị của nó là 1 đia chỉ trong bộ nhớ. Để có thể thực hiện được các phép tính số học với con trỏ thì ta cần phải chỉ rõ là con trỏ đó trỏ đên kiểu gì. Dạng tỗng quát là:

    PHP Code:
    type *pointer
    Trường hợp type là một con trỏ thì sao? khi đó ta có con trỏ đến con trỏ. Điều đó hoàn toàn hợp lệ, vì con trỏ là 1 biến nên nó cũng có địa chỉ trong bộ nhớ, giống như 1 biến kiểu char, int v.v... Khi ta dùng toán tử lấy giá trị của biến do con trỏ đến con trỏ đang chỉ tới thì ta thu được type, tức là con trỏ. Ví dụ:

    PHP Code:
    int i;
       
    int *pi=&i;
       
    int **ppi = &pi
    khi đó *ppi sẽ cho ta con trỏ đến kiểu int. Trường hợp ta muốn lấy giá trị của biến do con trỏ int đang trỏ tới thì ta phải dùng 2 dấu *. Tức là:

    PHP Code:
     int value = **ppi
    Biểu thức này mới nhìn có vẻ khó hiểu, nhưng nếu ta cứ suy luận từng bước sẽ thấy ngay. Trước hết *ppi là con trỏ kiểu int. Để lấy giá trị do con trỏ đến int chỉ tới thì ta dung dấu *. Như vậy ta phải cần *(*ppi), cũng tức là **ppi.

    Nếu bạn để ý thì với con trỏ đến int, tôi dùng tên pi, còn con trỏ đến con trỏ đến int, tôi dùng ppi. Đó là tôi đã áp dụng Hungarian Notation. Cách viết này nhiều lúc sẽ giúp chúng ta dễ hiểu hơn. Cụ thể là với cách viết này, mỗi dấu * sẽ trung hoà 1 chữ 'p'. Như thế:

    PHP Code:
      *ppi <==> pi (tức là con trỏ đến int)
       **
    ppi <==> (tức là kiểu int
    nhờ đó mỗi khi mà ta nghi hoăc không biết *ppi có kiểu gì thì chỉ cần quan sát kỹ là sẽ thấy ngay. Nói chung cách viết này cũng có nhiều người ủng hộ và nhiều người chống đối. Bạn đầu khi bạn mới làm quen với con trỏ thì nên áp dụng kiểu viết do. Nó sẽ giúp bạn dễ hiểu hơn đó.

    Cũng giống như con trỏ đến int khác con trỏ đến char, con trỏ đến con trỏ đến int sẽ khác con trỏ đến con trỏ đến char. Và nếu ta tìm cách gán địa chỉ của 1 con trỏ cho một con trỏ đến con trỏ thì ta phải bảo đảm là kiểu của chúng giống nhau. Nếu không thì trình dịch sẽ báo lỗi.
    Chào bác Dreaminess.Em đọc qua của bác đoạn này thực sự thì hơi rối mù.
    Theo cách nghĩ đơn giản của em về vấn đề con trỏ cấp n thế này.
    PHP Code:
    int i;
       
    int *pi=&i;
       
    int **ppi = &pi
    đầu tiên là khai báo biến i kiểu int .Nó sẽ được cấp phát vùng nhớ kích thước kiểu int và có địa chỉ.
    sau đó một con trỏ tên là pi sẽ lấy địa chỉ của biến i đó (lấy địa chỉ).
    Vậy con trỏ đó có địa chỉ biến i.Sau đó một con trỏ lại lấy tiếp địa chỉ con trỏ pi ở đây ta gọi là ppi bởi vì nó lấy địa chỉ của con trỏ cho nên có kiểu là int **ppi(chắc là vậy vì em không hiểu chỗ này).
    nếu có con trỏ nào đó lại lấy tiếp địa chỉ ppi thì có thể khai báo là int ***pppi ko?.

    Còn vấn đề thứ 2.
    PHP Code:
    #include<stdio.h>
    int main()
    {
       
    char c[]={'H','e','l','l','o'};
       
    printf("%c",1[c]);
    return 
    0;

    Em không thực sự hiểu 1[c] ở đây là gì? [c] ở đây mang hàm ý nghĩa gì.

    Đây là bài của bác shinichi haha
    PHP Code:
    #include<stdio.h>
    int main()
    {
       
    int i=0;
       
    char s[]="Hello";
       
    char *pch;
       
    pch=s;
       for(
    i=0;i<=5;i++)
          
    printf("%c",i[pch]);
       return 
    0;

    Em có thể viết lại bài của bác như sau.

    PHP Code:
    #include<stdio.h>
    int main()
    {
       
    int i=0;
       
    char s[]="Hello";
       
    char *pch;
       
    pch=s;
       
          
    printf("%s",pch);
       return 
    0;

    pch=s //lấy địa chỉ của s vì %s nên in ra hết chuỗi
    vậy khi bác lặp từ 1 đến 5
    cho in ra
    printf("%c",i[pch]);
    vì %c chỉ in ra 1 character thôi nên giống như in printf("%c",pch[i]);

    Đây vài ý kiến của em có gì sai sót mong các bác góp ý.Chucs mừng Cồng đòng C trở lại.
    .....oooo0.............
    .....(.....)....0oooo..
    ......\...(......(.....)....
    .......\._).......).../.....
    ..................(_./......
    Bước chậm mà chắc.

Các đề tài tương tự

  1. Trả lời: 2
    Bài viết cuối: 21-04-2013, 09:46 AM
  2. Lỗi: bố cục trang web tự tăng theo chiều ngang khi chiều cao thay đổi
    Gửi bởi tuanngocpt trong diễn đàn Nhập môn lập trình C#, ASP.NET
    Trả lời: 2
    Bài viết cuối: 16-03-2013, 11:25 PM
  3. Trả lời: 1
    Bài viết cuối: 28-04-2012, 09:43 PM
  4. Cách truyền mang 1 chiều cho hàm bài con trỏ và mảng một chiều ai có thể giải thích giúp mình
    Gửi bởi biencute trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 8
    Bài viết cuối: 21-03-2012, 09:00 AM
  5. Lời giải bài tập: Chuỗi Ký tự, mảng số nguyên 1 chiều, mảng 2 chiều, tạo Menu
    Gửi bởi xuanngoc trong diễn đàn Thủ thuật, Tutorials và Mã nguồn C/C++/C++0x
    Trả lời: 0
    Bài viết cuối: 15-10-2011, 01:17 AM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn