Trang 2 trên tổng số 3 Đầu tiênĐầu tiên 123 Cuối cùngCuối cùng
Từ 11 tới 20 trên tổng số 21 kết quả

Đề tài: Hàm trả về con trỏ sau có đúng không?

  1. #11
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Mặc định Hàm trả về con trỏ sau có đúng không?

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    Ý mình nói là ngoài hàm func(), i và j không tồn tại, nên a[0] bất định hay nói cách khác, nó trỏ vào rác. Dùng số (2, 3) chỉ để thấy rõ hơn là i, j không tồn tại trong hàm main() mà thôi.
    Bạn hãy đọc kỹ đoạn viết này của tác giả topic:
    Trích dẫn Nguyên bản được gửi bởi khoaph Xem bài viết
    Mình thấy biến i và j sau khi thoát khỏi hàm thì không tồn tại nữa nên con trỏ trả về sẽ trỏ tới giá trị rác nào đó
    Sao mà sau khi thoát khỏi hàm func() thì biến i và j không tồn tại nữa được? Làm sao mà con trỏ a trỏ đến giá trị rác được? Nó sẽ vẫn trỏ đến giá trị ban đầu của nó - nơi mà trước khi hàm func() được thực hiện. Còn trong quá trình thực hiện nó trỏ "tạm thời" vào một trong hai biến i hoặc j; và sau khi kết thúc lời gọi hàm thì nó sẽ trỏ lại giá trị ban đầu. Chứ nó hoàn toàn không phụ thuộc vào chuyện i hoặc j có rút ra khỏi stack hay không (vì i và j không phải là biến cục bộ đối với func() - và mình khẳng định rằng không có chuyện i và j "không tồn tại" như tác giả nói. Nó bắt buộc phải tồn tại trong hàm mẹ).
    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    Đoạn code của bạn cũng thế. Sau vòng for() ở dòng 8, mọi phần tử của mảng a xác định, kể cả a[0]. Nhưng sau lời gọi func(), a[0] trở thành bất định. Nó trỏ vào rác. Nên lệnh delete[] a[0] ở dòng 16 là bất định. Không thể biết chuyện gì sẽ xảy ra.
    Sao mà trỏ vào rác được? Nó vẫn chứa địa chỉ sau khi cấp phát (trước lời gọi func()). Có vẻ bạn hiểu sai về bộ nhớ rồi !
    C++ Code:
    1. #include <iostream>
    2. void func(int** pptr, int i, int j)
    3. {
    4.     if (i < j) *pptr = &i;
    5.     else *pptr = &j;
    6. }
    7. int main() {
    8.     int** a = new int* [4];
    9.     for (int k = 0; k < 4; k++)
    10.         a[k] = new int[6];
    11.     std::cout << "Dia chi a[0] truoc khi goi ham = " << &a[0] << std::endl;
    12.     int i = 8, j = 5;
    13.     func(a, i, j);
    14.     std::cout << "Dia chi a[0] sau khi goi ham = " << &a[0] << std::endl;
    15.     //.....
    16.     return 0;
    17. }
    Bạn xem, làm gì trỏ vào rác?

    Trích dẫn Nguyên bản được gửi bởi khoaph Xem bài viết
    Hàm trả về con trỏ sau có đúng không?
    Mình hỏi hai bạn: Thế nào là hàm trả về con trỏ? Ở trong bài này thì hàm trả về con trỏ được thể hiện chỗ nào?
    Đã được chỉnh sửa lần cuối bởi Moscow : 21-09-2021 lúc 01:49 AM.
    A good beginning and a good ending !

  2. #12
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất đông người
    Bài viết
    742

    Trích dẫn Nguyên bản được gửi bởi Moscow Xem bài viết
    ...
    Sao mà trỏ vào rác được? Nó vẫn chứa địa chỉ sau khi cấp phát (trước lời gọi func()). Có vẻ bạn hiểu sai về bộ nhớ rồi !
    C++ Code:
    1. #include <iostream>
    2. void func(int** pptr, int i, int j)
    3. {
    4.     if (i < j) *pptr = &i;
    5.     else *pptr = &j;
    6. }
    7. int main() {
    8.     int** a = new int* [4];
    9.     for (int k = 0; k < 4; k++)
    10.         a[k] = new int[6];
    11.     std::cout << "Dia chi a[0] truoc khi goi ham = " << &a[0] << std::endl;
    12.     int i = 8, j = 5;
    13.     func(a, i, j);
    14.     std::cout << "Dia chi a[0] sau khi goi ham = " << &a[0] << std::endl;
    15.     for (int k = 0; k < 4; k++)
    16.         delete[] a[k];
    17.     delete[] a;
    18.     return 0;
    19. }
    Bạn xem, làm gì trỏ vào rác?
    Muốn biết a[0] trỏ vào đâu thì không viết thế được. Phải viết thế này cơ:
    C++ Code:
    1.     #include <iostream>
    2.     void func(int** pptr, int i, int j)
    3.     {
    4.         if (i < j) *pptr = &i;
    5.         else *pptr = &j;
    6.     }
    7.     int main() {
    8.         int** a = new int* [4];
    9.         for (int k = 0; k < 4; k++)
    10.             a[k] = new int[6];
    11.         std::cout << "Gia tri a[0] truoc khi goi ham = " << a[0] << std::endl;
    12.         int i = 8, j = 5;
    13.         func(a, i, j);
    14.         std::cout << "Gia tri a[0] sau khi goi ham = " << a[0] << std::endl;
    15.         for (int k = 0; k < 4; k++)
    16.             delete[] a[k];
    17.         delete[] a;
    18.         return 0;
    19.     }

    Kết quả
    Code:
    Gia tri a[0] truoc khi goi ham = 0x656cc0
    Gia tri a[0] sau khi goi ham = 0x2afbd0
    0x656cc0 là địa chỉ vùng nhớ đã được cấp phát bằng new. Còn 0x2afbd0 là rác.

    new một đàng, delete một nẻo. Bạn nghĩ xem, thế có ổn không?
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  3. #13
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    Muốn biết a[0] trỏ vào đâu thì không viết thế được. Phải viết thế này cơ:
    C++ Code:
    1.     #include <iostream>
    2.     void func(int** pptr, int i, int j)
    3.     {
    4.         if (i < j) *pptr = &i;
    5.         else *pptr = &j;
    6.     }
    7.     int main() {
    8.         int** a = new int* [4];
    9.         for (int k = 0; k < 4; k++)
    10.             a[k] = new int[6];
    11.         std::cout << "Gia tri a[0] truoc khi goi ham = " << a[0] << std::endl;
    12.         int i = 8, j = 5;
    13.         func(a, i, j);
    14.         std::cout << "Gia tri a[0] sau khi goi ham = " << a[0] << std::endl;
    15.         for (int k = 0; k < 4; k++)
    16.             delete[] a[k];
    17.         delete[] a;
    18.         return 0;
    19.     }

    Kết quả
    Code:
    Gia tri a[0] truoc khi goi ham = 0x656cc0
    Gia tri a[0] sau khi goi ham = 0x2afbd0
    0x656cc0 là địa chỉ vùng nhớ đã được cấp phát bằng new. Còn 0x2afbd0 là rác.

    new một đàng, delete một nẻo. Bạn nghĩ xem, thế có ổn không?
    Mình đồng ý với bạn, mình nhầm không để ý chuyện con trỏ cấp hai và nó bị "lia" đi chỗ khác (trỏ vào bản sao của hai biến cục bộ i và j trên stack của hàm main() - mà mình đi delete[] vùng nhớ đó là sai).

    Tuy nhiên, cái mình hướng đến là: tác giả bảo rằng biến i và j sẽ không tồn tại sau khi gọi hàm func(), và hàm func() trả về con trỏ ! Bạn thấy sao? Nãy giờ chẳng lẽ mọi người không hiểu mình nói ư?
    Đã được chỉnh sửa lần cuối bởi Moscow : 21-09-2021 lúc 02:17 AM.
    A good beginning and a good ending !

  4. #14
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất đông người
    Bài viết
    742

    Trích dẫn Nguyên bản được gửi bởi Moscow Xem bài viết
    Mình đồng ý với bạn, mình nhầm không để ý chuyện con trỏ cấp hai và nó bị "lia" đi chỗ khác (trỏ vào hai biến cục bộ i và j trên stack của hàm main() - mà mình đi delete[] vùng nhớ stack đó là sai). Mình đính chính lại cho bạn rằng 0x2afbd0 không phải là rác nhé. Nó chính là địa chỉ của biến j trong hàm main(), mà biến này đang nằm trên stack của main().
    Thế à?

    Thử xem bạn nói có đúng không nhé:
    C++ Code:
    1.     #include <iostream>
    2.     void func(int** pptr, int i, int j)
    3.     {
    4.         if (i < j) *pptr = &i;
    5.         else *pptr = &j;
    6.     }
    7.     int main() {
    8.         int** a = new int* [4];
    9.         for (int k = 0; k < 4; k++)
    10.             a[k] = new int[6];
    11.         std::cout << "Gia tri a[0] truoc khi goi ham = " << a[0] << std::endl;
    12.         int i = 8, j = 5;
    13.         func(a, i, j);
    14.         std::cout << "Gia tri a[0] sau khi goi ham = " << a[0] << std::endl;
    15.         std::cout << "Dia chi bien i = " << &i << std::endl;
    16.         std::cout << "Dia chi bien j = " << &j << std::endl;
    17.         for (int k = 0; k < 4; k++)
    18.             delete[] a[k];
    19.         delete[] a;
    20.         return 0;
    21.     }

    Kết quả (lần thứ nhất)
    Code:
    Gia tri a[0] truoc khi goi ham = 0x76cc0
    Gia tri a[0] sau khi goi ham = 0x3bf640
    Dia chi bien i = 0x3bf65c
    Dia chi bien j = 0x3bf658
    Kết quả (lần nữa)
    Code:
    Gia tri a[0] truoc khi goi ham = 0xe6cc0
    Gia tri a[0] sau khi goi ham = 0x2ef940
    Dia chi bien i = 0x2ef95c
    Dia chi bien j = 0x2ef958
    Trích dẫn Nguyên bản được gửi bởi Moscow Xem bài viết
    Tuy nhiên, cái mình hướng đến là: tác giả bảo rằng biến i và j sẽ không tồn tại sau khi gọi hàm func(), và hàm func() trả về con trỏ ! Bạn thấy sao? Nãy giờ chẳng lẽ mọi người không hiểu mình nói ư?
    Mình hiểu là bạn nhầm lẫn giữa tham trị và tham biến. Con trỏ a[0], do lệnh gán trong hàm func(), được trỏ vào tham số i hoặc j của hàm func(). Và chúng không phải là biến i hay j của hàm main(). Vì chúng là tham trị.

    Xem lại chương trình đầu tiên mà mình đã gửi, với i, j được cấp giá trị 2, 3.
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  5. #15
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Có lẽ mình nên dừng tại đây. Nó quá phức tạp để nói. Thật phức tạp cả vốn tiếng Việt nữa. Xin lỗi tất cả nhé. Làm rối tung lên rồi.
    A good beginning and a good ending !

  6. #16
    Ngày gia nhập
    12 2015
    Nơi ở
    Đà Nẵng
    Bài viết
    610

    Mặc định Hàm trả về con trỏ sau có đúng không?

    @Moscow ý của tôi về return value có nghĩa rộng, không chỉ là return value của function, là như trong bài viết này
    How can we return multiple values from a function in C/C++?
    Trong đó có đoạn
    In C or C++, we cannot return multiple values from a function directly. In this section, we will see how to use some trick to return more than one value from a function.

    We can return more than one values from a function by using the method called “call by address”, or “call by reference”. In the invoker function, we will use two variables to store the results, and the function will take pointer type data. So we have to pass the address of the data.

    In this example, we will see how to define a function that can return quotient and remainder after dividing two numbers from one single function.

    Example Code
    #include<stdio.h>
    void div(int a, int b, int *quotient, int *remainder) {
    *quotient = a / b;
    *remainder = a % b;
    }
    main() {
    int a = 76, b = 10;
    int q, r;
    div(a, b, &q, &r);
    printf("Quotient is: %d\nRemainder is: %d\n", q, r);
    }
    Output
    Quotient is: 7
    Remainder is: 6
    Trong trường hợp trên, giá trị trả về là quotient, remainder. Trong ví dụ trong câu hỏi của tôi, giá trị trả về chính là pptr

    - - - Nội dung đã được cập nhật ngày 21-09-2021 lúc 08:46 AM - - -

    C++ Code:
    1. void func(int** pptr, int i, int j)
    2. {
    3.     if (i < j) *pptr = &i;
    4.     else *pptr = &j;
    5. }
    6. int main() {
    7.     int** a = new int*[4];
    8.     for (int k = 0; k < 4; k++)
    9.         a[k] = new int[6];
    10.     int i = 8, j = 5;
    11.     func(a, i, j);
    12.    
    13.  
    14.     return 0;
    15. }
    Vấn đề là các tham số cục bộ i, j trong hàm func không phải là i, j định nghĩa ở dòng 10, chúng là các biến hoàn toàn khác nhau. Và khi kết thúc hàm func 2 biến cục bộ i, j trong func sẽ không tồn tại nữa, còn i , j ở dòng 10 vẫn tồn tại. Và trong hàm func, *pptr được gán địa chỉ của i, j cục bộ (chứ không phải i, j ở dòng 10), như thế không phải *pptr sẽ trỏ giá trị rác sau khi kết thúc func sao.
    Đã được chỉnh sửa lần cuối bởi khoaph : 22-09-2021 lúc 05:18 PM.

  7. #17
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất đông người
    Bài viết
    742

    Để làm cho chủ đề này có nghĩa một tý, sau đây là phiên bản C++ của chương trình đầu tiên mà mình đã gửi [bài #8]. Với các lệnh in ra địa chỉ của mọi đối tượng liên quan.

    C++ Code:
    1. #include <iostream>
    2. void func(int** pptr, int i, int j)
    3. {
    4.   std::cout << "Dia chi tham i = " << &i << std::endl;
    5.   std::cout << "Dia chi tham j = " << &j << std::endl;
    6.  
    7.   std::cout << "Gia tri pptr[0] khi goi ham =    " << pptr[0] << std::endl;
    8.   if (i < j) *pptr = &i;
    9.   else *pptr = &j;
    10.   std::cout << "Gia tri pptr[0] ham tra lai =    " << pptr[0] << std::endl;
    11. }
    12.  
    13. int main()
    14. {
    15.   int *a[10];
    16.   int x = 8, y = 5;
    17.   std::cout << "Dia chi bien x = " << &x << std::endl;
    18.   std::cout << "Dia chi bien y = " << &y << std::endl;
    19.  
    20.   std::cout << "Gia tri a[0] truoc khi goi ham = " << a[0] << std::endl;
    21.   func(a, 2, 3);
    22.   std::cout << "Gia tri a[0] sau khi goi ham =   " << a[0] << std::endl;
    23.   return 0;
    24. }

    Kết quả hiển thị trên màn hình. Màu đỏ đánh dấu các giá trị bất định (địa chỉ của rác).
    Kết quả (lần đầu)
    Code:
    Dia chi bien x = 0x2ef94c
    Dia chi bien y = 0x2ef948
    Gia tri a[0] truoc khi goi ham = 0x376c10
    Dia chi tham i = 0x2ef928
    Dia chi tham j = 0x2ef930
    Gia tri pptr[0] khi goi ham =    0x376c10
    Gia tri pptr[0] ham tra lai =    0x2ef928
    Gia tri a[0] sau khi goi ham =   0x2ef928
    Kết quả (lần nữa)
    Code:
    Dia chi bien x = 0x25fdec
    Dia chi bien y = 0x25fde8
    Gia tri a[0] truoc khi goi ham = 0x4f6c10
    Dia chi tham i = 0x25fdc8
    Dia chi tham j = 0x25fdd0
    Gia tri pptr[0] khi goi ham =    0x4f6c10
    Gia tri pptr[0] ham tra lai =    0x25fdc8
    Gia tri a[0] sau khi goi ham =   0x25fdc8
    Kết quả (và bản chất vấn đề) vẫn thế nếu thay trị (2,3) trong lời gọi hàm bằng bất cứ biểu thức nào khác, như (8,5), (8+5, 8*5), (x+y, x*y), (x,y). Hay thậm chí (i,j) và đổi tên biến x, y thành i, j.

    Con trỏ a[0], do lệnh gán *pptr = &... trong hàm func(), được trỏ vào tham số i hoặc j của hàm func(). Với k bất kỳ, pptr[k] chính là a[k]. Vì nó là tham biến.

    Còn i, j không phải là x hay y ngay cả khi lời gọi hàm có dạng func(.,x,y). Vì chúng là tham trị.

    Có thể biến chương trình này thành một thí dụ minh họa sự khác nhau giữa tham trị với tham biến bằng cách viết thêm vào func() lệnh thay đổi các tham i, j và in ra trị của chúng trước và sau khi thay đổi và, đồng thời, viết thêm vào main() lệnh in ra các trị của biến x, y trước và sau khi gọi hàm.
    Đã được chỉnh sửa lần cuối bởi Ada : 25-09-2021 lúc 06:55 AM.
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  8. #18
    Ngày gia nhập
    12 2015
    Nơi ở
    Đà Nẵng
    Bài viết
    610

    Chuyện ngoài lề, lại một lỗi ngớ ngẩn trong ebook trên
    (An Introduction to the C Programming Language and Software Design-Tim Bailey)
    Nhân số ảo như vậy thì chịu(trang 94)
    Không đọc nữa
    C Code:
    1. typedef struct {
    2. double real;
    3. double imag;
    4. } Complex;
    5. void multequal_complex(Complex* a, const Complex* b)
    6. /* Multiply two complex numbers and store the result in a. */
    7. {
    8.     a−>real = a−>real*b−>real − a−>imag*b−>imag;
    9.     a−>imag = a−>real*b−>imag + a−>imag*b−>real;
    10. }

  9. #19
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất đông người
    Bài viết
    742

    Lỗi sinh viên.

    Thời sinh viên, bạn học nhờ mình tìm lỗi giúp. Đó là 1 chương trình vẽ minh họa 1 đường thẳng trong không gian quay quanh trục tọa độ z. Tọa độ điểm (x,y,z) chuyển động được cập nhật theo công thức (x,y) = (x,y)*M, với Mma trận quay. Chương trình đáng lẽ phải vẽ ra mặt hyperbol, nhưng thực tế nó lại vẽ ra một mặt xoắn ốc: đường thẳng càng quay thì càng rời xa trục z.

    Mình không tìm được lỗi ngay tức khắc. Cũng phải mất 1 đêm nghĩ mới ra. Code của bạn ấy giống hệt như code trên.

    - - - Nội dung đã được cập nhật ngày 22-09-2021 lúc 01:46 PM - - -

    Trên C Việt mình cũng đã từng tham gia giải 1 bài tập không mẫu mực về chủ đề cập nhật mảng mà không dùng mảng phụ.
    Đã được chỉnh sửa lần cuối bởi Ada : 22-09-2021 lúc 01:19 PM.
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  10. #20
    Ngày gia nhập
    12 2015
    Nơi ở
    Đà Nẵng
    Bài viết
    610

    C Code:
    1. void func(int** pptr, int i, int j)
    2. {
    3.     if (i < j) *pptr = &i;
    4.     else *pptr = &j;
    5. }
    6. int main() {
    7.     int** a = new int*[4];
    8.     for (int k = 0; k < 4; k++)
    9.         a[k] = new int[6];
    10.     int i = 8, j = 5;
    11.     func(a, i, j);
    12.    
    13.  
    14.     return 0;
    15. }
    Vấn đề là các tham số cục bộ i, j trong hàm func không phải là i, j định nghĩa ở dòng 10, chúng là các biến hoàn toàn khác nhau. Và khi kết thúc hàm func 2 biến cục bộ i, j trong func sẽ không tồn tại nữa, còn i , j ở dòng 10 vẫn tồn tại. Và trong hàm func, *pptr được gán địa chỉ của i, j cục bộ (chứ không phải i, j ở dòng 10), như thế không phải *pptr sẽ trỏ giá trị rác sau khi kết thúc func sao.
    Nói thêm chỗ "hoàn toàn khác nhau", tuy nhiên, không hẳn là chúng không liên quan đến nhau. i, j trong func được khởi tạo bằng với i, j trên dòng 10, nhưng chỉ vậy thôi, sau đó trong func, i, j có thể gán giá trị tùy ý mà không ảnh hưởng đến i, j ở dòng 10, bởi vì chúng khác nhau, đó chính là ý nghĩa của tham trị, đúng không?

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