2015-02-11 2 views
0

Это вопрос из теста, который у меня был вчера.
Учитывая этот код:Struct имеет два поля, каждый из которых является 1-м массивом. Передача объекта struct в функцию без указателя изменила бы объект struct?

#include <stdio.h> 
#define ARR_SIZE 5 

typedef struct _A { 
    int _arr1[ARR_SIZE]; 
    int* _arr2; } A; 

void foo(A a) { 
    int i; 
    for (i=0;i< ARR_SIZE;++i) 
     a._arr1[i] = 5*i; 
} 

void bar(A a) { 
    int i; 
    for (i=0;i< ARR_SIZE;++i) 
    a._arr2[i] = 10*i; 
} 

void printA(A* a,char* str) 
{ 
    int i; 
    printf("%s:\n_arr1:\t",str); 
    for (i=0;i< ARR_SIZE;++i) 
     printf("%d\t",a->_arr1[i]); 
     printf("\n_arr2:\t"); 
    for (i=0;i< ARR_SIZE;++i) 
     printf("%d\t",a->_arr2[i]); 
     printf("\n"); 
} 

int main() { 
    A a1 = {{1,2,3,4,5},0}; 
    A a2 = a1; 
    a1._arr2 = a1._arr1; 
    a2._arr2 = a2._arr1; 
    foo(a1); 
    bar(a2); 
    printA(&a1,"a1"); 
    printA(&a2,"a2"); 
    return 0; 
} 

Теперь, распечатать это: a1:
_arr1: 1 2 3 4 5
_arr2: 1 2 3 4 5
a2:
_arr1: 0 10 20 30 40
_arr2: 0 10 20 30 40

Я не понимаю тиражи. Если я сделаю шаг за шагом, настроя код, я вижу, что передача a1 в foo ничего не сделает, потому что я не отправил указатель на a1. Но я не понимаю, почему, если я отправил a2 в bar без указателя, он меняет a2.
Я думал о том, что _arr2 является указателем, и из-за него bar меняет его, поэтому a2 изменений. Но мы знаем, что каждый массив является указателем на первый элемент. Итак, _arr1 - это массив, поэтому он указатель, но не меняется!

Может кто-нибудь объяснить мне, почему это происходит? tnx много заранее!

+0

Массивы не указатели. – Quentin

+0

, когда вы не передадите struct указателями, у вас будет неявная копия. в вашем примере, 'bar' модифицирует массив через указатель, вот почему. – HuStmpHrrr

+0

и массивы не являются указателями семантически, но они могут быть одинаковыми в системе типов. два - разные понятия. 'int a [10], b [10]; a = b; 'является незаконным назначением. – HuStmpHrrr

ответ

2

Причина, изменения сделанные bar видны в исходном struct потому, что _arr2 в копии struct все еще указывает на _arr1 оригинального struct, что вы прошли. По сути, вы передаете указатель, но теперь он скрыт в struct, который передается по значению.

Illustration

Вот способ, чтобы увидеть, что происходит:

void bar(A a) { 
    printf("%p %p", (void*)a._arr2, (void*)&a._arr1); 
    for (int i=0;i< ARR_SIZE;++i) { 
     a._arr2[i] = 10*i; 
    } 
} 

Это будет печатать различные указатели для _arr2, хранящейся в struct и _arr1 встроенных в него.

1

struct A имеет массив и указатель внутри.

typedef struct _A { 
    int _arr1[ARR_SIZE];  // _arr1 is an array 
    int* _arr2; } A;   // _arr2 is a pointer 

Если вы передадите копию указателя, копия все еще указывает на то же место.

Изменение того, что копия указывает на отражение в вызывающей функции.

Возможно, вам захочется прочитать о различиях между массивами и указателями.
Предлагаю раздел 6 c-faq.