30/09/2018, 21:07

Lỗi cấp phát động

#include <stdio.h>
#include <conio.h>
#include <malloc.h>

void capphat(int *xPtr, int &n);
void nhap(int *xPtr, int n);


int main()
{
	int * xPtr, n;
	capphat( xPtr, n);
	printf("%d",n);
	nhap(xPtr, n);
	getch();
	return 0;
}

void capphat( int * xPtr, int &n)
{
	printf("Nhap vao so phan tu cua mang : ");
	scanf("%d",&n);
	xPtr = (int *) calloc(n , sizeof(int));
}

void nhap(int * xPtr, int n)
{
	for(int i =1 ; i<= n; i++)
	{
		printf("Nhap vap phan tu thu %d : ",i);
		scanf("%d",xPtr+ i);
	}
}
Gió viết 23:11 ngày 30/09/2018

Coi int * là một kiểu thì muốn thay đổi nó bạn có thể truyền qua con trỏ int* *xPtr hoặc tham chiếu int* &xPtr

I Black I Hacker viết 23:19 ngày 30/09/2018

cậu nó rõ lại đi. cậu ơi. t mới học. hic

viết 23:12 ngày 30/09/2018

Ý Gió là xPtr có kiểu dữ liệu int* lưu giá trị địa chỉ, khi truyền tham số vào hàm capphat() thì nó sẽ tạo ra một ô nhớ có kiểu dữ liệu giống xPtr và thực hiện cấp phát với ô nhớ đó, chứ thực chất ô nhớ xPtr sẽ không thay đổi gì, muốn thay đổi giá trị của xPtr thì phải dùng con trỏ hoặc reference tới xPtr, tức là hàm capphat() sửa lại thành capphat(int**xPtr, int&n) hoặc capphat(int* &xPtr, int &n).

I Black I Hacker viết 23:17 ngày 30/09/2018

mình tưởng goi hàm truyền con trỏ thì con trỏ nó được thay đổi chứ nhỉ >??? giải thích giúp mình với.

I Black I Hacker viết 23:08 ngày 30/09/2018

sao hàm nhap voi hàm xuất của t lại không phải chuyền địa chỉ nhỉ >??/ hoi ngu hic.\

cescnghia viết 23:12 ngày 30/09/2018

cái này là lỗi cơ bản, mình cho bạn 1 ví dụ sai này nè:

void f(int n){
     n = 9;
}

int main(void){
     int x = 0;
     f(x);
     printf("%d\n", x); //in ra 0 
}

Bạn sửa code lại thành:

int* pt capphat(int n){
     int* pt = calloc(n, sizeof(int));
     return pt; //trong main kiểm tra xem pt này có null hay ko !
}
viết 23:17 ngày 30/09/2018

nôm na là bạn muốn thay đổi giá trị của một vùng nhớ (biến) thông qua hàm thì truyền bằng con trỏ hoặc tham chiếu (reference), muốn thay đổi giá trị chứa trong vùng nhớ kiểu int thì dùng một con trỏ int* trỏ tới vùn nhớ đó. tương tự, muốn thay đổi giá trị trong vùng nhớ kiểu int* thì dùng con trỏ int**, cái khó hiểu ở đây là kiểu dữ liệu mà vùng nhớ đó chứa thôi, nên Gió mới nói là coi int* là một kiểu dữ liệu. Hoặc bạn dùng typedef để định nghĩa lại kiểu int* thành một kiểu tên khác để dễ hiểu

I Black I Hacker viết 23:13 ngày 30/09/2018

moi người cho t hỏi. t cấp phát bên ngoài rồi , bên trong mà cấp phát lại thì chì cần chuyền con trỏ.

#include <stdio.h>
#include <conio.h>
#include <malloc.h>

void capphat(int *xPtr, int &n);
void nhap(int * xPtr, int n);
void xuat(int * xPtr, int n);

int main()
{
	int * xPtr, n;
	xPtr = (int *)calloc(2, sizeof(int));
	capphat(xPtr, n);
	nhap(xPtr, n);
	xuat(xPtr, n);
	return 0;
}

void capphat( int * xPtr, int &n)
{
	printf("Nhap vao so phan tu cua mang : ");
	scanf("%d",&n);
	xPtr = (int *) realloc(xPtr , n * sizeof(int));
}

void nhap(int * xPtr, int n)
{
	for(int i =1 ; i<= n; i++)
	{
		printf("Nhap vap phan tu thu %d : ",i);
		scanf("%d",xPtr+ i);
	}
}

void xuat(int *xPtr, int n)
{
	for(int i =1 ; i<= n ; i++)
	{
		printf("%d\t",*(xPtr+ i));
	}
}

thế thì không cần chuyền địa chỉ con trỏ. tại sao nhỉ

ht194 viết 23:10 ngày 30/09/2018

Lỗi này nhiều bạn mới học hay gặp phải. Mình giải thích rõ 1 tí nhé
Tại hàm Main(), bạn tạo 1 con trỏ xPtr và nó không trỏ vào đâu cả.
Bạn gọi hàm capphat(xPtr, n) thì 1 con trỏ mới được tạo ra trong vùng nhớ stack, tạm goi là P’. Con trỏ P’copy nội dụng từ con trỏ xPtr mà bạn truyền vào nên P’ cũng không trỏ vào đâu cả.
Bạn xin cấp phát 1 vùng nhớ động và gán địa chỉ đầu tiên của vùng nhớ cho con trỏ P’. Con trỏ xPtr vẫn chưa trỏ vào đâu cả.
Khi thoát khỏi hàm capphat(), con trỏ P’ bị xóa. Bộ nhớ của bạn bị rò, hay bị leak memory đó.
Tiếp theo bạn yêu cầu nhập dữ liệu vào. Tuy nhiên con trỏ xPtr chưa trỏ vào đâu cả . Runtime sẽ có lỗi segment fault đó.
Sai lầm ở đây là bạn cấp phát bộ nhớ cho 1 con trỏ khác(P’) trong khi bạn vẫn nghĩ là đang dùng xPtr.
Cách khắc phục thì các bạn trên kia đã giải thích, mình k nhắc lại nữa.

viết 23:21 ngày 30/09/2018

Bạn nên markdown code lại cho mọi người dễ theo dõi nha.

xPtr = (int *)calloc(2, sizeof(int));

sau dòng này, xPtr (giả sử có địa chỉ là 0x111111) trỏ tới ô nhớ đầu tiên của một vùng nhớ nằm trên Heap, giả sử địa chỉ này là 0x123456, lưu ý là địa chỉ này là của phần tử đầu tiên của mảng cấp phát được, địa chỉ của phần tử tiếp theo của mảng sẽ là 0x123456+4

void capphat( int * xPtr, int &n)

sau khi khai báo hàm capphat() compiler sẽ tạo ra một biến là xPtr giống hệt biến xPtr trong hàm main() (giả sử biến này có địa chỉ là 0x222222) nhưng không phải là biến xPtr trong main() (địa chỉ là 0x111111) tạm gọi là copyxPtr cho dễ phân biệt cả copyxPtrxPtr đều trỏ tới cùng 1 địa chỉ 0x123456.
Bây giờ sẽ xét trong thân hàm capphat()

xPtr = (int *) realloc(xPtr , n * sizeof(int));

hàm realloc() sẽ thay đổi kích thước vùng nhớ được trỏ tới bởi copyxPtr. Tức là lúc này vùng nhớ mà bắt đầu bằng 0x123456 sẽ có kích thước là n chứ không phải là 2.
Trở lại hàm main(), sau khi gọi capphat() thì vùng nhớ 0x123456 trên Heap sẽ không còn là 2 như ban đầu mà là n phần tử, biến xPtr trong cấp phát thì bị hủy.Nhưng xPtr vẫn trỏ tới vùng nhớ bắt đầu bằng ô nhớ 0x123456 nên ở dưới sẽ truy xuất vùng nhớ này bằng xPtr một cách bình thường.

I Black I Hacker viết 23:10 ngày 30/09/2018

cảm ơn bạn nhiều , hì . bạn nói chi tiết quá. mong được bạn giúp nhiều hơn

Bài liên quan
0