30/09/2018, 23:28
Gặp lỗi khi thêm dòng vào ma trận trong C/C++
Hi mọi người.
Mình có làm 1 bài tập sau nhưng không hiểu vì sao gặp lỗi !
Đề bài: Thực hiện thao tác thêm 1 dòng vào ma trận cho trước bằng con trỏ cấp 2.
Source code: http://codepad.org/9dqCpkTH
void NhapMaTran(int **a, int dong, int cot)
{
for (int i = 0; i < dong * cot; i++)
{
printf("
Nhap a[%d][%d] = ", i / cot, i % cot);
scanf("%d", *(a + i / cot) + i % cot);
}
}
void XuatMaTran(int **a, int dong, int cot)
{
for (int i = 0; i < dong * cot; i++)
{
printf("%5d", *(*(a + i / cot) + i % cot));
if ((i + 1) % cot == 0)
printf("
");
}
}
void HoanVi(int &a, int &b)
{
int Temp = a;
a = b;
b = Temp;
}
void SwapLine(int **a, int cot, int kdong1, int kdong2)
{
for (int i = 0; i < cot; i++)
{
HoanVi(a[kdong1][i], a[kdong2][i]);
}
}
void ThemDong(int **a, int &dong, int cot, int kdong, int *b)
{
a[dong] = (int *)malloc(cot * sizeof(int));
for (int i = dong; i > kdong; i--)
{
SwapLine(a, cot, i - 1, i);
}
dong++;
int idx = 0;
for (int i = 0; i < cot; i++)
a[kdong][i] = b[i];
}
int main()
{
int dong, cot;
do
{
printf("
Nhap so luong dong: ");
scanf("%d", &dong);
printf("
Nhap so luong cot: ");
scanf("%d", &cot);
if (dong < 1 || cot < 1)
printf("
So luong dong hoac cot khong hop le
");
} while (dong < 1 || cot < 1);
int **a = (int **)malloc(dong * sizeof(int));
for (int i = 0; i < dong; i++)
a[i] = (int *)malloc(cot * sizeof(int));
NhapMaTran(a, dong, cot);
XuatMaTran(a, dong, cot);
int kdong;
do
{
printf("
Nhap chi so dong can them: ");
scanf("%d", &kdong);
if (kdong < 0 || kdong > dong)
printf("
Chi so dong can them khong hop le
");
} while (kdong < 0 || kdong > dong);
int *b = (int *)malloc(cot * sizeof(int));
for (int i = 0; i < cot; i++)
{
printf("
Nhap a[%d][%d] = ", kdong, i);
scanf("%d", &b[i]);
}
printf("
Ma tran sau khi them dong %d:
", kdong);
ThemDong(a, dong, cot, kdong, b);
XuatMaTran(a, dong, cot);
for (int i = 0; i < dong; i++)
free(a[i]);
free(a);
getch();
return 0;
}
Vấn đề là mình ĐÃ thêm được thành công, nhưng khi thêm thì nó kèm theo 1 bảng xuất hiện với dòng chữ khá đẹp đẽ như bức hình sau:
Mọi người ai biết lỗi giúp mình nhé, xin cảm ơn
Bài liên quan
phải là sizeof(int*) mới đúng. May mắn ở đây là size của con trỏ = size của int nên dòng này ko gây lỗi.
a
là con trỏ tới con trỏ nêndong * sizeof...
thì...
phải là kiểu màa
trỏ tới, ở đây là kiểu con trỏ nên phải viết làdong * sizeof(int*)
sau dòng malloc này thì đã tạo được 1 mảng 1 chiều chứa con trỏ, tại địa chỉ nào đó, ví dụ là 0x100, và
a
có giá trị là địa chỉ 0x100 này:sau đó gọi malloc cho từng
a[i]
:sau khi nhập giá trị ma trận:
khi thêm dòng, vì tại 0x100 chỉ đủ chỗ cho 2 con trỏ nên ko thể thêm dòng thứ 3 (con trỏ thứ 3) được, hay viết
a[dong]
với dong = 2 là sai. Phải cấp phát chỗ khác đủ chỗ cho 3 dòng/3 con trỏ:copy giá trị mảng cũ sang mảng mới:
xóa mảng cũ:
cho
a
trỏ vào mảng mớirồi thêm dòng mới vào:
a[2] = (int*)malloc(cot * sizeof(int));
rồi nhập giá trị cho dòng mới…
vì ở đây giá trị của
a
thay đổi khi gọi dònga = NULL
haya = new_a
nên phải truyền tham chiếu choa
:void ThemDong(int **&a, ...
vì 1 con trỏ có thể đại diện cho 1 dòng ở đây, nên khi swap 1 dòng thì ko phải mất công copy từng phần tử, chỉ cần swap giá trị 2 con trỏ là được. Ví dụ
Vậy cái chỗ này em làm bằng cách khác, đó làm thêm dòng:
realloc(a, (dong + 1) * sizeof(int *));
vào đầu hàm Thêm Dòng là hoàn toàn được chứ ạ ?Em thử Build thì ok rồi, ý anh @tntxtnt như thế nào ?
P/S: Sao em
#include <algorithm>
rồi mà nó vẫn không có hàmswap
để dùng nhỉ, phải tự gõ hàm Hoán Vị mệt quá @@ghi đầy đủ
std::swap
xemrealloc
cũng được, thậm chí còn có thể tốt hơn, nhưng vẫn phải truyền tham chiếu choa
(int**& a)
. (viết**&
nhiều*
hoa mắt quá )thêm cái nữa:
*(*(a + i / cot) + i % cot))
trong hàm XuatMaTran thì viết làa[i/cot][i%cot]
cho nó dễ đọc… scanf trong NhapMaTran cũng vậy:&a[i/cot][i%cot]
(thêm dấu&
để lấy địa chỉ vô phía trước)Anh @tntxtnt ơi,
Sau khi em thêm dòng:
realloc(a, (dong + 1) * sizeof(int *));
vào đầu hàmThemDong
thì code chạy bình thường, không có vấn đề gì cả !Nhưng khi nhập ma trận 3 x 4 và thêm vào dòng 1 thì nó lỗi như sau, em không hiểu luôn @@
Update Source Code: http://codepad.org/9zDNmyPn
phải là
a = (int**) realloc(a, (dong + 1) * sizeof(int *));
…Yeah được rồi !!!
Hồi em học bên con trỏ cấp 1 thì nó chỉ cần mỗi dòng
realloc(a, (some_thing + 1) * sizeof(some_thing));
là được, mà ở đây sao mình lại phải để thêm a đằng trước nữa nhỉ (giống anh ý) ?void* realloc(void* ptr, ..._
với tham số kiểu này thì giá trị củaptr
truyền vào đâu có thay đổi được.realloc nó kiểm tra xem phía sau
ptr
còn đủ chỗ trống ko, nếu còn thì vẫn giữ nguyên mảng ở địa chỉ cũ, chỉ cần tăng kích cỡ của mảng cũ lên, nên giá trịptr
ko thay đổi vẫn chạy đúng (trường hợp này giả về địa chỉ mảng cũ nên gána = realloc...
chả khác gì ko gánrealloc...)
.còn nếu ko đủ chỗ trống thì phải dời mảng cũ sang địa chỉ mới, copy giá trị mảng cũ sang mảng mới, rồi xóa mảng cũ, rồi trả về con trỏ tới mảng mới. Vì
ptr
truyền tham số nên giá trị nó ko thay đổi được, phải gán giá trị mới lại cho nóa = realloc...
Ừm, hiểu được xíu :))
Anh Trí xem giúp em luôn 2 cái hàm Thêm Cột và Xóa Cột à, nó cũng bị lỗi
chỗ thêm cột phải dời mấy phần tử cũ đi trước khi copy phần tử mới vào:
vd dòng x có các phần tử là 1 2 3 4 5, cần chèn số 9 vào sau cột thứ 3:
lôi cái swap lên trước cái gán.
À, fix được rồi, thanks anh nhiều
dồn chỗ trước rồi mới gán sau
Great
Anh Trí có cách nào để cải thiện code cho em không ?
P/S: Còn hàm Xóa Cột là ổn rồi chứ nhỉ @tntxtnt
cải thiện thì chắc phải viết lại từ đầu =))
bắt đầu viết với mảng 1 chiều, thêm/xóa 1 phần tử, viết ra nhiều hàm nhỏ. Rồi đi lên mảng 2 chiều, reuse mấy hàm nhỏ này.
Anh @tntxtnt xem giùm em đoạn code sau nhé
Đề bài: Thêm / Xóa Dòng / Cột trong ma trận cho trước (có kiểu dữ liệu bất kì)
Em làm hàm Thêm Dòng trước nhưng bị lỗi
Source code: http://codepad.org/fazrK5NG
Còn đây là lỗi nó thông báo ! Điều đặc biệt là cái lỗi này nó này ở file khác chứ không phải ở file source.cpp
a là con trỏ trỏ tới con trỏ. a trỏ tới mảng con trỏ. a ko phải là mảng 2 chiều. Đừng nghĩ a là mảng 2 chiều khi cấp phát động cho nó. Nghĩ nó là mảng con trỏ. Cấp phát 10 con trỏ cho nó. Cấp phát 20 con trỏ cho nó.
a là mảng con trỏ sao lại đi realloc cho nó
sizeof(minh)
? a có phải là mảngminh
đâu?còn nữa, phải dời mấy dòng cũ đi để có chỗ cho dòng mới, rồi mới cấp phát dòng mới cho
a[dong]
được.phía trước int main() ko cần thêm
template <...>
à khi xài new/delete thì đừng nên xài chung với realloc…
EDIT: phải là a[kdong] = new… mới đúng ~.~
http://rextester.com/KPDT35345
Hình như cái chỗ này em đâu có sai ?
Chỉ sai ở chỗ
template
trong hàm Main và chỗa = (minh **)realloc(...)
thôi !Về vấn đề này, em xóa cái
template
trong hàm Main đi và tự tạo 1 hàm realloc cho mình rồi sửa lại => CODE chạy ok rồiFINALLY
Còn mỗi chỗ này em chưa hiểu ? Anh Trí có thể “thông não” giúp em đoạn này không ? Đại khái là nói sâu và dài + dễ hiểu hơn xíu nữa
a là mảng con trỏ
a -> [địa chỉ dòng 1][địa chỉ dòng 2][địa chỉ dòng 3]
mà địa chỉ mỗi dòng có kích cỡ bằng với kích cỡ con trỏ
sizeof(T*)
chứ ko phảisizeof(T)
. Kích thước 1 con trỏ có thể là 4 hoặc 8 bytes, còn kích thước củaT
thì bất kì, có thể 1 byte, 2 bytes, 3 bytes, hoặc 1000 bytes. Nhân chosizeof(T)
thì sai rồi.vd
char** a = new char*[4];
thì a -> […][…][…][…] (1 dấu chấm là 1 byte)nhưng
char** a = new char[4];
thì a -> [.][.][.][.]hoặc
SinhVien** a = new SinhVien[4];
, 1 SinhVien có kích cỡ 24 bytes, thì a -> […][…][…][…]còn
SinhVien** a = new SinhVien*[4];
, thì a -> […][…][…][…]