Поле массива структуры полностью клонируется при передаче значения функции?

In C:

  • Когда структура отправляется (через параметр) по значению в функцию, создается новая структура, поэтому изменение структуры внутри функции не изменит оригинал структура.

  • Когда массив отправляется (через параметр) по значению в функцию, создается новый указатель, поэтому изменение массива внутри функции не изменит исходный массив, но изменение значений массива внутри функции (поскольку у нас есть указатель на исходный массив) изменит значения в исходном массиве.

  • Когда структура с полем массива отправляется (через параметр) по значению в функцию, создается ?????, так что изменение массива (указателя) внутри функции не изменит исходный массив, а изменение значений массива не изменит значения в исходном массиве.

Означает ли третий пункт, что поле массива в структуре при отправке в функцию будет полностью клонировано? Почему вместо этого не используется просто указатель? Что об этом говорит спецификация?

Кусок кода, с которым я играл:

typedef struct {
    int value;
    int array[3]; /* initialized to 0 by default */
} Struct_t;

void foo(Struct_t structure)
{
    printf("-- %p\n", structure.array); /* Pointer to local array */

    structure.value = 1;
    *structure.array = 1;       /* Won't change the original array */
    *(structure.array + 1) = 1; /* Won't change the original array */
    structure.array[2] = 1;     /* Won't change the original array */
}

int main()
{
    Struct_t s = { .value = 0 };

    foo(s);

    printf("-- %p\n", s.array); /* Pointer to original array */

    printf("%d\n", s.value);
    printf("%d\n", s.array[0]);
    printf("%d\n", s.array[1]);
    printf("%d\n", s.array[2]);
}

Выход:

-- 0x7ffe8f17d194
-- 0x7ffe8f17d1b4
0
0
0
0

person Dorin Botan    schedule 13.09.2018    source источник
comment
Массив является частью структуры, поэтому он также будет скопирован (все значения в нем). Если это будет указатель, будет скопирован только указатель и, следовательно, он будет указывать на ту же память, что и оригинал.   -  person mch    schedule 13.09.2018
comment
изменение массива внутри функции не изменит исходный массив, но изменение значений массива внутри функции массива является его значениями /elements, ни больше, ни меньше.   -  person alk    schedule 13.09.2018


Ответы (4)


OP «При отправке массива ...» нуждается в разъяснении.

Когда массив отправляется (через параметр) по значению в функцию, создается новый указатель, поэтому изменение массива внутри функции не изменит исходный массив, но изменение значений массива внутри функции (поскольку у нас есть указатель на исходный массив) изменит значения в исходном массиве. (ОП)

Когда массив, например s[] ниже, передается в strcpy(char *s1, const char *s2), преобразование происходит сначала. Объект s преобразуется в адрес первого элемента массива. strcpy() не получает s[] в качестве параметра s1, вместо этого он получает копию значения &s[0].

char s[6] = "Hello";
strcpy(s, "World");

В пределах strcpy() s1 не является массивом. s1 — это указатель на char. strcpy() не имеет понятия "изменение массива внутри функции", так как функция не знает s1 указывает на память массива, выделенную память или что-то еще. strcpy() понимает, что s1 указывает на char.


Означает ли третий пункт, что поле массива структуры при отправке в функцию будет полностью клонировано?

Да. Когда объект передается функции в C, он потенциально преобразуется, а затем передается по значению. Это очень похоже на любое задание. Содержимое объекта после преобразования копируется в место назначения. После преобразования не имеет значения, является ли объект struct, union, int, double, void*, int(*)() и т. д. или элементом struct, содержащим массив.

int a;
double b;
a = 5;  // 5 is copied to a
b = a;  // a is converted to double and copied to b


char s[6] = "Hello";
char *e;
void *v;
e = s; // s is converted to the address on the first array element and then copied to e
v = e; // e is converted to a `void*` and then copied to v

Struct_t f = {0};
Struct_t g;
g = f; // f is copied to g
person chux - Reinstate Monica    schedule 13.09.2018

Означает ли третий пункт, что поле массива структуры при отправке в функцию будет полностью клонировано?

Да.

Почему вместо этого не используется просто указатель?

Потому что нет указателя. Массив не является указателем. (Подробнее об этом здесь.)

person alk    schedule 13.09.2018

В C все передается по значению.

  1. При передаче по значению мы передаем копию переменной функции.

  2. Когда мы передаем по ссылке, мы передаем псевдоним переменной в функцию.

    Это копирование значения указателя, адреса, в функцию.

Если struct передается по значению функции, bytes из struct копируются как параметр функции. Все, что делается с этим struct внутри функции, изменяет копию, а не оригинал struct

person kiran Biradar    schedule 13.09.2018
comment
Означает ли это, что массив в структуре будет полностью частью этой структуры, а не просто указателем на значения, расположенные где-то еще в памяти? Похоже на то, что sizeof(struct) — это сумма размеров всех элементов массива в структуре. Но есть ли для этого конкретная причина? Не вызовет ли это потенциально проблемы с производительностью? - person Dorin Botan; 13.09.2018
comment
Я знаю, что передача structs по значению была запрещена в K&R и была добавлена ​​позже. Что говорят об этом новые спецификации? Что такое массив в struct на самом деле и почему это так? - person Dorin Botan; 13.09.2018
comment
@DorinBotan Массив является частью структуры. Используйте sizeof(Struct_t) для проверки (примечание: может быть больше, чем ожидалось - см. Почему sizeof для структуры не равен сумме sizeof каждого члена?) - person Johnny Mopp; 13.09.2018

Структура — это предопределенная структура памяти, которая имеет определенную структуру памяти. При добавлении массива в структуру фактическая память массива находится в структуре, а не в указателе. Вот почему его необходимо скопировать с остальной частью структуры.

Массивы не являются указателями, массивы имеют определенную неизменяемую ячейку памяти, а указатель может указывать куда угодно.

person Kami Kaze    schedule 13.09.2018