Có phải là xấu khi tham chiếu các phần tử mảng thông qua số học con trỏ thay vì toán tử [] không?


12

Tôi mới bắt đầu học lập trình bằng C và để nâng cao hiểu biết về con trỏ và mảng, tôi đã cố gắng tham khảo các phần tử của một mảng mà không tạo ra bất kỳ con trỏ nào:

for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}

Toàn bộ mã biên dịch và chạy hoàn hảo.

Tôi tưởng tượng việc phải tạo một con trỏ cho mỗi mảng trong một mã nguồn lớn dường như rất kém hiệu quả.

Vì vậy, thay vì có địa chỉ của một mảng được lưu trữ và truy xuất bằng cách sử dụng một con trỏ, có phải là một thực hành lập trình xấu để sử dụng trực tiếp địa chỉ của mảng, như được hiển thị ở trên không?


Sử dụng printf "[%d][%d] = %d\n", k1, k2, array[k1] [k2]));sẽ tránh các con trỏ arithmic và dễ hiểu hơn.
Kasper van den Berg

1
Haha, bạn đã cho tôi Tôi đã làm điều đó chỉ như một thử nghiệm để hiểu rõ hơn về cách con trỏ và mảng hoạt động.
Niko Gambt

Số học con trỏ thực sự nhanh hơn khoảng 30% so với sử dụng chỉ mục mảng.
Andy

Câu trả lời:


16

Nó "xấu" chỉ đến mức ít đọc được. a[x]là điều tương tự như *(a+x)vậy, vì vậy không có sự khác biệt về hiệu quả hoặc hành vi (trên thực tế, x[a]cũng sẽ hoạt động). Chỉ làa[x] là nó thường trực quan hơn rất nhiều đối với con người chúng ta.

Nhưng điều đó không có nghĩa là khả năng đọc không phải là một vấn đề lớn. Để xem mức độ lớn, hãy nghĩ về cách bạn sẽ "đọc" hai biểu thức này nếu bạn thấy chúng trong mã:

  • *(a+x)= "Điều được chỉ ra bởi tổng của con trỏ avà số nguyên x"
  • a[x]= "Thành xviên thứ của mảng a"

Tương tự, khi bạn cần tham khảo địa chỉ của một phần tử mảng:

  • (a+x)= "Tổng của con trỏ avà số nguyên x"
  • &a[x]= "Địa chỉ của xthành viên thứ của mảng a"

Hầu hết thời gian, các []phiên bản chỉ dễ hiểu hơn khi bạn xem mã không tầm thường hoạt động trên một số mảng khác nhau (đặc biệt là mảng mảng). Đó là lý do tại sao các []nhà điều hành tồn tại ở nơi đầu tiên.

PS Thực hiện những điều này một cách nghiêm túc như một bài tập học tập là một ý tưởng rất tốt. Điều quan trọng là phải hiểu rằng các mảng thực sự chỉ là con trỏ và bù đắp.


Điều này. Cảm ơn bạn. Tôi vừa mới nhận ra sâu sắc những gì tôi thực sự muốn biết là có hay không, khi cần phải tham khảo địa chỉ của bất kỳ phần tử mảng nào, và sau đó tham khảo địa chỉ của một phần tử khác, và sau đó là một phần tử khác, nó vẫn còn tệ KHÔNG sử dụng một con trỏ và thay vào đó, sử dụng mảng trực tiếp theo cách tôi đã làm? Câu hỏi này của tôi rất khó xác định, đó là lý do tại sao tôi không gõ nó trong OP. Dù sao, vì tôi đã không hỏi nó, câu trả lời của bạn là thỏa đáng.
Niko Gambt

1
@NikoGambt Bạn luôn có thể hỏi một câu hỏi khác =)
Ixrec

1
Bạn có ý nghĩa gì chỉ trong phạm vi ...? Toàn bộ quan điểm của ngôn ngữ lập trình là làm cho mã dễ đọc hơn đối với con người. Nếu chúng ta không quan tâm đến điều đó, thì tất cả chúng ta sẽ viết mã op theo hệ thập lục phân.
Solomon chậm

2
Mảng không phải là con trỏ, chỉ phân rã thành con trỏ ngầm.
CodeInChaos

4

Vâng, đó là thực tế xấu, nhưng không phải vì lý do không hiệu quả.

Toán tử mảng sử dụng con trỏ đối xứng dưới mui xe, vì vậy chúng có hiệu quả tương đương.

Vấn đề với con trỏ đối xứng là nó rất dễ bị lỗi và khó đọc hơn.

Nguyên tắc nhỏ: Không sử dụng con trỏ đối xứng trừ khi bạn phải.


1
Vì dù sao nó cũng sử dụng số học con trỏ, nên điều đó không có nghĩa là con trỏ cũng dễ bị lỗi và khó đọc như nhau?
Niko Gambt

1
Trình biên dịch @NikoGambt khá giỏi trong việc thực hiện con trỏ trong phần mềm và hiếm khi mắc 'lỗi'; Hậu quả là các lập trình viên sẽ mắc lỗi với các lỗi khó chịu.
Kasper van den Berg

@KaspervandenBerg Vâng, tôi đồng ý. Tuy nhiên, tôi quan tâm đến các lỗi do lập trình viên gây ra và tôi không chắc liệu đó có phải là một thực hành lập trình tồi để làm những gì tôi đã làm ở trên không, trong trường hợp cần phải tham khảo địa chỉ của một mảng , nếu trường hợp như vậy tồn tại.
Niko Gambt

1
@NikoGambt Viết cái gì đó là ít có thể đọc cho mục đích hoạt động là hầu như luôn luôn thực hành xấu, nhưng viết một cái gì đó là ít có thể đọc cho không đạt được là rõ ràng thực tế xấu.
Neil

@Neil Thí nghiệm nhỏ của tôi không phải là vô nghĩa. Bằng cách đó, tôi đã học được rằng trình biên dịch dường như tạo ra một mảng các con trỏ để chỉ một mảng đa chiều. Tuy nhiên, vì bạn nói khả năng đọc quan trọng hơn hiệu suất, tôi đoán nó vẫn là một thực hành lập trình tồi.
Niko Gambt

0

Làm mát việc học của bạn c, bạn vừa phát hiện ra một trong những ca dao lưỡi nhỏ. Bạn không thực hiện số học con trỏ trên một mảng, mà là một mảng các con trỏ. Làm số học con trỏ trên mảng là không thể. Một mảng phân rã thành một con trỏ nhưng không phải là một con trỏ tự nó. Những gì bạn có (xem bình luận của cmaster) là

int *array[]; //This is a array to pointers of type *int. 

array[k1] + k2; //This is pointer arithmetic on one pointer stored in the array  

Dereferences con trỏ này cung cấp giá trị con trỏ vừa tính của bạn, trỏ đến. Nhìn chung không có điểm nào trong việc làm những gì bạn đang làm. Nhưng bạn có thể tuyến tính hóa mảng và sau đó là một bước tiến trong nó, như thế này.

int array[y_dim*x_dim]; 
int index = x_dim*y + x; 
array[index]; //Gives you the element in x, y!

Sải bước của cô ấy là x_dim. Hy vọng câu trả lời của tôi được làm rõ!


Nó không phải rõ ràng ngay từ OP dù nó sử dụng một int* array[ROW];một int array[ROW][COLUMN];, hoặc một int (*array)[COLUMN];. Một trong ba định nghĩa này có thể được sử dụng với mã trong OP.
cmaster - phục hồi monica

vâng tôi biết điều đó, câu trả lời của tôi hơi vụng về ở điểm đó. Tôi sửa nó, cảm ơn!
fhtuft
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.