2017-07-23 14 views
8

C không thể trả về tham chiếu không giống như C++. Điều đó có nghĩa là nếu bạn truy cập A[i] nó sẽ sao chép phần tử trong việc đánh giá biểu thức?C có sao chép phần tử mỗi khi bạn truy cập mảng không?

Ví dụ nếu A là một mảng của 10 int s, không A[5]+=1; chỉ tăng các bản sao tạm thời được xây dựng khi đánh giá A[5], không giống như vector C++ 's mà sẽ tăng yếu tố thứ sáu thực tế bản thân?

+14

'A [5] 'dereferences phần tử mảng trực tiếp, không có bản sao tạm thời có liên quan. – user0042

+0

'A [5] + = 1' tăng phần tử dựa trên không phù hợp của mảng' A'. Nếu nó không làm điều đó, trình biên dịch có lỗi. Không rõ bạn đang hỏi gì. – EJP

+0

'A [5] + = 1' chỉ giống với' A [5] = A [5] + 1', trình biên dịch tối ưu hóa sẽ tạo thành ít bản sao, nếu có, có thể được biểu thị bằng ngôn ngữ máy. – nos

Trả lời

12

C có khái niệm được gọi là 'lvalue' sắp xếp như một tham chiếu. Nó không phải là một loại (không phải là một phần của hệ thống kiểu), nhưng một số biểu thức C là 'lvalues', và chỉ những biểu thức như vậy có thể là toán hạng bên trái của một phép gán (bao gồm cả op-assign) hoặc increment/decrement.

Vì C không có quá tải toán tử nên không cần phải có sự phân biệt trong hệ thống kiểu vì không bao giờ cần phải khai báo giá trị như giá trị so với giá trị. Đó là mong muốn thêm quá tải toán tử trong C++ dẫn đến việc giới thiệu các kiểu tham chiếu để làm cho sự phân biệt rvalue/lvalue rõ ràng cho các toán tử quá tải.

5

Nếu điều đó đúng, bạn sẽ không thể sửa đổi mảng và biểu thức A[5]+=1; sẽ không có hiệu lực!

Ngược lại, khi bạn chuyển đối số vô hướng cho một hàm, nó hoạt động giống như một bản sao vì nó không bị sửa đổi khi trả về. Nhưng một mảng, trên thực tế được truyền qua như một con trỏ, không được sao chép (điều đó sẽ không thể chịu được tốn kém) và có thể khác nhau khi trả về.

2

C luôn sao chép phần tử khi đọc từ mảng có A[i], tức là khi biểu thức A[i] là “giá trị”. Tuy nhiên, khi xem xét viết, C có một khái niệm về thuật ngữ “giá trị trái”, mà thực chất là một tập hợp con hạn chế của cú pháp biểu thức được phép xuất hiện là điểm đến của một bài tập:

X = Y 
*X = Y 
X[i] = Y 
X.n = Y 

Trong những trường hợp này, "biểu thức" *X, X[i]X.n không thực sự đánh giá giá trị — chúng có cùng cú pháp làm biểu thức, để thuận tiện, nhưng không giống nhau ngữ nghĩa. Bạn có thể nghĩ rằng trong số này là một cái gì đó giống như sau:

memcpy(&X, &Y, sizeof(Y)); 
memcpy(&*X, &Y, sizeof(Y)); 
memcpy(&X[i], &Y, sizeof(Y)); 
memcpy(&X.n, &Y, sizeof(Y)); 

Hoặc cách khác, suy nghĩ của C là có nhiều toán tử gán khác nhau:

_ = _ // direct assignment 
*_ = _ // indirect assignment 
_[_] = _ // special case of indirect assignment 
_._ = _ // special case of indirect assignment 

Dù bằng cách nào, một bài tập như A[5] += 1 sẽ tăng giá trị của phần tử thứ sáu là A tại chỗ, giống như bạn mong đợi, mà bạn có thể xác minh như sau:

int A[1] = { 1 }; 
A[0] += 5; 
printf("%d\n", A[0]); // 6 
4

thực hiện A [5] + = 1; chỉ tăng bản sao tạm thời được xây dựng khi đánh giá A [5]

sẽ làm cho phần tử thứ 6 của A được tăng thêm 1.

Điều đó có khả năng đạt được bằng cách sao chép A[5] vào sổ đăng ký trong CPU, tăng nó và sao chép giá trị trở lại.

Dưới đây là một chương trình:

int main(){ 
    int A[10]; 
    A[5]+=1; 
    return 0; 
} 

Dưới đây là các gcc tạo x86-64 lắp ráp cho A[5]+=1;

mov  eax, DWORD PTR [rbp-28] 
    add  eax, 1 
    mov  DWORD PTR [rbp-28], eax 

Đó di chuyển DWORD PTR [rbp-28] vào 32-bit EAX accumulator, thêm 1 vào nó và di chuyển nó trở lại cùng một chỗ.

DWORD PTR [rbp-28] xác định phần tử thứ 6 của A theo vị trí của nó tương ứng với (cuối) khung ngăn xếp (rbp).

Điểm về tham chiếu là cá trích đỏ. Cả C và C++ đều được biên dịch thành mã máy (có thể thông qua trình biên dịch). Các tính năng khác của ngôn ngữ không ảnh hưởng đến cách A[5]+=1; được diễn giải hoặc biên dịch.

0

không, i chỉ mục mảng chỉ là một con trỏ để chỉ vị trí được chuyển thay vì toàn bộ mảng và giá trị của vị trí bộ nhớ thực bị ảnh hưởng.

thử đoạn mã sau:

#include<stdio.h> 
void function(int[]); 
int main() 
{ 
    int a[] = {0,1,2,3,4,5,6,7,8,9}; 
    int i; 
    for(i = 0; i < 10; i++) 
     printf("%d, ",a[i]);  
    function(a); 
    printf("\n"); 
    for(i = 0; i < 10; i++) 
     printf("%d, ",a[i]); 
    return 0; 
} 

void function(int b[]) 
{ 
    int i; 
    for(i = 0; i < 10; i++) 
     b[i] *= 10; 
} 

OUTPUT

Các vấn đề liên quan