01/10/2018, 08:20

Khi realloc cho con trỏ cấp 2 thì có nhất thiết phải dùng vòng lặp duyệt lại từ đầu để cấp phát cho từng con trỏ cấp 1 của nó không?

Giả sử e có 1 đoạn code cấp phát cho level 2-pointer như sau:

int **arr = (int **)calloc(3, sizeof(int *));
for (int i = 0; i < 3; ++i) {
     arr[i] = (int *)calloc(5, sizeof(int));
}
...

thì khi em realloc lại cho con trỏ arr với kích thước lớn hơn thì có nhất thiết phải dùng vòng lặp duyệt lại từ đầu để cấp phát cho mỗi con trỏ cấp 1 trong nó không ạ ? Hay chỉ cấp phát cho con trỏ ở cuối thôi ?

realloc(arr, 4 * sizeof(int *));
for (int i = 0; i < 4; ++i) {
     arr[i] = (int *)calloc(5, sizeof(int));
}
...

hay

realloc(arr, 4 * sizeof(int *));
arr[3] = (int *)calloc(5, sizeof(int));

?

Còn nếu realloc con trỏ arr với kích thước bé hơn thì dữ liệu trong matrix sẽ bị mất đi đúng ko ạ ?

Cảm ơn mọi người nhiều

rogp10 viết 10:30 ngày 01/10/2018

Không, nó bảo toàn nội dung vùng nhớ luôn. http://en.cppreference.com/w/c/memory/realloc

copying memory area with size equal the lesser of the new and the old sizes

Tất nhiên thu hẹp vùng nhớ thì sẽ mất 1 số slot nên bạn phải free trước các con trỏ cấp 1 phía sau.

Long Dragon viết 10:30 ngày 01/10/2018

À anh @rogp10 ơi, sẵn tiện cho e hỏi luôn là:
nếu realloc con trỏ cấp 2 arr như sau: arr = (int **)realloc(arr, 69 * sizeof(...));
thì nó bị lỗi runtime
còn để: realloc(arr, 69 * sizeof(...)); thì nó không bị lỗi.
Anh có thể giải thích cho e ko ?

Long Dragon viết 10:24 ngày 01/10/2018

Tất nhiên thu hẹp vùng nhớ thì sẽ mất 1 số slot nên bạn phải free trước các con trỏ cấp 1 phía sau.

em tưởng khi realloc lesser lại thì mấy con trỏ cấp 1 phía sau nó tự động giải phóng luôn ?

rogp10 viết 10:22 ngày 01/10/2018

Raw pointer của C/C++ không có auto GC

Long Dragon viết 10:21 ngày 01/10/2018

Raw pointer của C/C++ không có auto GC

Tức là nó ko tự giải phóng khi mình realloc ạ ?
Vậy khi em realloc lesser thì mấy con trỏ cấp 1 ở sau cùng nó bị mất ra khỏi mảng thôi chứ vẫn còn trong bộ nhớ ạ ?

Long Dragon viết 10:26 ngày 01/10/2018

Sẵn tiện anh @rogp10 cho em hỏi đoạn code sau dùng để thêm dòng vào ma trận đã đúng chưa ạ:

void SwapRows(int *arr1, int *arr2, int size)
{
    for (int i = 0; i < size; ++i) {
        int Temp = arr1[i];
        arr1[i] = arr2[i];
        arr2[i] = Temp;
    }
}

void AddRows(int ***arr, int *rows, int columns, int *insert_array, int rows_index)
{
    realloc(*arr, (*rows + 1) * sizeof(int *));
    (*arr)[*rows] = (int *)calloc(columns, sizeof(int));
    for (int i = 0; i < columns; ++i)
        *(*(*arr + *rows) + i) = *(insert_array + i);
    for (int i = *rows; i > rows_index; --i) {
        SwapRows((*arr)[i], (*arr)[i - 1], columns);
    }
    (*rows)++;
}

Em run thử thấy cũng ok nhưng về mặt cú pháp, cấu trúc, … đồ ko biết có sai ko ?

rogp10 viết 10:36 ngày 01/10/2018

Vậy khi em realloc lesser thì mấy con trỏ cấp 1 ở sau cùng nó bị mất ra khỏi mảng thôi chứ vẫn còn trong bộ nhớ ạ ?

Những vùng nhớ đó vẫn chưa được free và về nguyên tắc là sau khi thu gọn thì ko dùng được mấy slot đó nữa nên cũng không free được.

À anh @rogp10 ơi, sẵn tiện cho e hỏi luôn là:nếu realloc con trỏ cấp 2 arr như sau: arr = (int **)realloc(arr, 69 * sizeof(…));thì nó bị lỗi runtimecòn để: realloc(arr, 69 * sizeof(…)); thì nó không bị lỗi.Anh có thể giải thích cho e ko ?

Đây là 1 điều khá kỳ quặc của C nếu hàm không có prototype đầy đủ thì coi như nó trả về int. Oái oăm là chỉ khi cast trực tiếp mới bị dính đòn.

Thực ra con trỏ void* đổi trực tiếp qua int* (và bất cứ kiểu con trỏ gì) là hợp lệ (nhưng giữa hai kiểu không void thì sẽ bị lỗi). Vì vậy không cần phải cast với {m|re|c}alloc. Và để cho chính xác thì nên viết ntn:
arr = realloc(arr, sizeof(*arr) * n);

Long Dragon viết 10:31 ngày 01/10/2018

Đây là 1 điều khá kỳ quặc của C nếu hàm không có prototype đầy đủ thì coi như nó trả về int. Oái oăm là chỉ khi cast trực tiếp mới bị dính đòn.

Thực ra con trỏ void* đổi trực tiếp qua int* (và bất cứ kiểu con trỏ gì) là hợp lệ (nhưng giữa hai kiểu không void thì sẽ bị lỗi). Vì vậy không cần phải cast với {m|re|c}alloc. Và để cho chính xác thì nên viết ntn: arr = realloc(arr, sizeof(*arr) * n);

Ko hiểu gì hết anh ơi
Em thấy lâu lâu để arr = (int **)realloc(arr, (rows + 1) * sizeof(int* ));
thì ko có lỗi, tự dưng trong code trên thì lại bị lỗi, phải để:
realloc(arr, (rows + 1) * sizeof(int* ));

Edit: À, nó bị lỗi không phải do arr = (int **)realloc(...) mà do chỗ khác Nhưng em vẫn chưa hiểu lắm câu giải thích của anh @rogp10

rogp10 viết 10:35 ngày 01/10/2018

ANSI C(C89) cho bạn xài hàm mà ko có prototype (trường hợp này nó nằm ở stdlib.h), chỉ cần tới khi build mà mình có là dùng được thôi. Lúc này (khi chưa build) thì compiler vẫn cho rằng realloc trả về int. Vấn đề là realloc trả về con trỏ nên dính undefined => BOOM. Có người cast mới bị lỗi, không cast không lỗi rất là mindscrew (mấy cái undefined này nó vậy). Nên đúng nhất là dùng mấy hàm này phải #include <stdlib.h>

Bài liên quan
0