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 :blush:

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

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.

1 Like

À 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 ? :slight_smile:

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 ?

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

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ớ ạ ?

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 ? :slight_smile:

Những vùng nhớ đó vẫn chưa được free :slight_smile: 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.

Đây là 1 điều khá kỳ quặc của C :smiley: 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 :cry:
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 :smiley: Nhưng em vẫn chưa hiểu lắm câu giải thích của anh @rogp10 :cry:

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>

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?