`int (*a)[100]` khác với `int *a` và `int *a[100]` như thế nào?

a xem lịch sử chỉnh sửa và thời gian chỉnh sửa cửa thớt đi ạ

1 Like

Kakaka, hóa ra là vậy :smile:

Sorry @htwap nhé :slight_smile:

1 Like

hí, không có gì đâu ạ.
mà không hiểu sao lại dùng cái (*a)[100] này nhỉ? vì theo a nói thì *a trỏ đến 1 mảng 100 phần tử, thế để mình *a mà không cần [100] có được ko a?

1 Like

Khác nhau về khái niệm

  • Khai báo int (*a)[100] là cho biết a sẽ trỏ tới một mảng kiểu int, mảng này có 100 phần tử kiểu int.
  • Khai báo int *a là để cho biết a sẽ trỏ tới địa chỉ int, địa chỉ đó có thể là mảng.
  • Khai báo int *a[100] là cho biết a là mảng 100 phần tử, mỗi phần tử là một con trỏ kiểu int.

Khác nhau về kích thước giữa int *aint(*a)[100]

  • Khai báo int (*a)[100] là để khai báo rõ ràng rằng a trỏ tới mảng kiểu int với kích thước mỗi phần tử là 400 bytes bởi vì 100 * 4 bytes = 400 bytes. Cho int có kích thước 4 bytes.

  • Khai báo int *a thì a có thể trỏ tới mảng kiểu int với kích thước của mỗi phần tử là 4 bytes.

Ví dụ

#include <stdio.h>

int main() {
    int (*pa100)[100];
    int a100[100];
    pa100 = a100;
    printf("pa100 points to \t\t%p\n", *pa100);
    printf("a100 is on \t\t\t%p\n", a100);

    a100[1] = 3;

    printf("a100[1] = %d \t\t address %p\n", a100[1], &a100[1]);
    printf("pa100[1] = %d \t address %p\n", pa100[1], pa100[1]);

    return 0;
}

Kết quả

pa100 points to                 0028fd8c
a100 is on                      0028fd8c
a100[1] = 3              address 0028fd90
pa100[1] = 2686748       address 0028ff1c

Tại sao a100[1] bằng 3 trong khi pa100[1] = 2686748, trông có vẻ là số rác. Đó là bởi vì địa chỉ mà a100[1]pa100[1] trỏ đến là khác nhau.

Ta thấy:

  • 0028ff1c - 0028fd8c = 4, đúng bằng kích thước của một int
  • 0028ff1c - 0028fd8c = 400, đúng bằng kích thước của 100 int

Vậy có nghĩa theo anh Đạt khai báo:
int (*a)[100]; <=> int *a = new int[100]; phải không a.

Không phải :smile: @quanghuong1991 có thể in địa chỉ của hai khai báo này và địa chỉ sau khi tăng lên 1 để thấy có giống ví dụ của Đạt không.

Đạt không biết khai báo dùng new như thế nào để thể hiện được cái vụ thao tác + lên con trỏ mà tăng 400 địa chỉ. Nên Đạt làm tạm một ví dụ khác sử dụng một struct A100 có chứa int data[100]

#include <iostream>

struct A100{
    int data[100];
};

int main()
{
    int *pa = new int[100];
    std::cout << "address pa: " << pa << std::endl;
    std::cout << "address pa+1: " << pa+1 << std::endl;

    A100 *psa100 = new A100;
    std::cout << "address psa100: " << psa100 << std::endl;
    std::cout << "address psa100+1: " << psa100+1 << std::endl;
    return 0;
}

Output

address pa: 0x7f2580
address pa+1: 0x7f2584
address psa100: 0x7f2718
address psa100+1: 0x7f28a8

Ta chứng minh được là không phải :smile:

pa+1 - pa = 4 bytes

Còn về new một 100 phần tử kiểu int thì Đạt không biết phải new làm sao. Nên Đạt làm tạm cái struct A100.

Cái này gọi là con trỏ mảng đúng không anh?

ví dụ này thiếu *a[100] với *a nữa a ơi…

Rất có thể. Anh không biết thuật ngữ này, tại lúc anh đi học anh chưa học tới phần này.

Ví dụ cho *a dễ mà. Ví dụ cho int *a[100] dở lắm. Anh thấy làm ví dụ cho char *bai_tho_con_coc[100] hay hơn. Em thử nghiên cứu char * s[100] rồi làm ví dụ xem. Đấy cũng là một cách học. Tự đặt câu hỏi: "char *schar *s[100] khác nhau như thế nào, khi nào dùng cái nào?"

1 Like

Em cũng không biết thuật ngữ này, cái này do em tự dịch từ cái “point to array” trong sách ra :smile: không biết đúng không, tại trong sách cũng chỉ đề cập sơ qua nó thôi.

1 Like

E thấy theo định nghĩa thì khai báo:
int *pa = new int[100];(1)
là khai báo mảng gồm 100 phần tử kiểu int, giống với bên trên anh nói với khai báo int (*pa)[100];(2)
Hay nó khác nhau ở chỗ (1) la pa trỏ đến đầu mảng. Còn (2) trỏ đến nguyên cả mảng. Như vậy theo (2) thì e thấy không đúng lắm.

Em đọc định nghĩa bị nhầm rồi. new không phải là “khai báo mảng”, new là cấp phát vùng nhớ. Ở đây lệnh new chỉ cấp 400 bytes of RAM cho *pa thôi. Không liên quan gì khai báo kiểu dữ liệu *pa cả.

Về bản chất, *pa vẫn chỉ là int *pa, new không làm thay đổi nó. Anh có thể tách ra làm hai dòng lệnh khác nhau.

int *pa;
pa = new int[100];

Trong khi đó ta thấy khai báo này int (*pa)[100] hoàn toàn khác với khai báo int *pa. Đừng để ý tới vế sau dấu =. Để ý phần khai báo biến.

như vậy có phải
int (*pa)[100] chỉ là một con trỏ , và nó chỉ chứa địa chỉ của một mảng, mảng đó bắt buộc có 100 phần tử.
Vậy thì dùng cái này để làm gì ta. Dùng int *p vẫn linh động hơn nhiều .
ví dụ :
p thì có thể gán địa chỉ một biến int, một mảng một chiêu int bat kì só phần tử.
pa thì bi giới hạn rất nhiều

1 Like

Đúng

Sai

int (*pa)[100] là một con trỏ, nó trỏ tới một vùng nhớ có độ dài 100 phần tử kiểu int.

int *p là một con trỏ, trỏ tới một vùng nhớ có độ dài 1 phần tử kiểu int


Mảng, bản chất là một vùng nhớ liên tiếp. Ví dụ: int mang[100] là một vùng nhớ 400 bytes liên tiếp nhau. Nếu ta viết int *p = mang hoặc int *p = mang[0] tức là ta trỏ p tới vùng nhớ có độ dài 1 phần tử kiểu int.

Nếu ta viết p[1] hoặc (p+1), về bản chất ta trỏ tới phần tử kế tiếp của mang[0], phần tử này cũng là một vùng nhớ 4 bytes. Vùng nhớ này nằm trong int mang[100]

Nhưng nếu ta viết int (*p)[100] = mang hoặc int *p = mang[0] tức là ta trỏ tới vùng nhớ có độ dài 100 phần tử kiểu int. Lúc này p bao trùm toàn bộ mang[100], tức mang[1].

Nếu ta viết p[1] hoặc (p+1, về bản chất ta trỏ tới vùng nhớ cách xa vị trí mang[0] 400 bytes và nằm ngoài int mang[100].


Xem lại ví dụ ở trên: `int (*a)[100]` khác với `int *a` và `int *a[100]` như thế nào?

Hai công cụ khác nhau, dùng cho hai mục đích khác nhau.

1 Like

anh Đạt ơi em chưa hiểu int a[100]; thì là 1 con trỏ hằng chỉ vào 1 mảng ô nhớ phía sau mà mỗi phần tử trong a[100] cũng coi như là 1 con trỏ, cho em hỏi nó khác gì với int*a[100] ạ :slight_smile:

Đây không phải là con trỏ hằng, khi nào có const mới gọi là hằng. Đây gọi là mảng. Chỉ có điều mảng không gán được sang địa chỉ khác, nên người ta mới nói à, mảng giống như con trỏ hằng. Nhưng nó không phải. Mảng về bản chất nó không phải là con trỏ. Mảng là một địa chỉ.

em thử cái này xem

printf("%p %p\n", mang, &mang);
printf("%p %p\n", a, &a);

Nhưng cái này thuộc về câu hỏi khác rồi.

1 Like

thank a, em sẽ coi lại ^^

1 Like

Anh xem e làm bảng này có đúng không ạ? e làm dựa vào những gì đọc được ở các bình luận trên
1.*pa

2.(*pa)[8]

3.*pa[8]

:smile:

1 Like

Cái 1 và 2 chính xác

cái 3 anh không hiểu lắm.

nghĩa là mảng con trỏ e viết tất cả các dấu * ở các phần tử ấy
pa[0] là con trỏ 1, vậy pa[0] + 5 ( cọng 1 số bất kì ) thì pa trỏ về đâu vậy anh?

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