Когда C не нужен адрес оператора?

Есть ли в C случаи, когда для массивов адрес оператора не нужен? Например, я знаю, что этот код нуждается в адресе оператора:

typedef struct foo_t {
    int bar;
} foo_t;

void foo_init(foo_t *f) { f->bar = 123; }

... {
    foo_t f;

    foo_init(&f);
}

Но этот код не будет нуждаться в адресе оператора:

... {
    char buffer[1024];
    memset(buffer, 0, 1024);
}

Вот memset объявлен как:

void *memset(void *ptr, int value, size_t num);

И в C он будет автоматически разыгрывать это char[] к void* - но пытаясь сделать то же самое для foo_t как это:

 foo_t f;
 memset(f, 0, sizeof(foo_t));

Не будет работать и будет генерировать ожидаемую ошибку типа во время компиляции. Как с char[] Например, если мы используем массив, он будет работать:

foo_t list[16];
memset(foo, 0, sizeof(list));

Он снова автоматически разыграет foo_t[] в void*

Это единственный раз, когда такой тип произойдет в C? Как я могу знать, когда произойдут эти приведения?

3 ответа

Решение

Я знаю только один "другой" (см. Комментарии) случай неявного получения адреса с помощью указателей на функции [ 1, 2]. Учитывая функцию

int
f(void);

следующие две строки имеют одинаковое значение.

int (*fptr1)(void) = f;
int (*fptr2)(void) = &f;

Оба делают fptr1 а также fptr2 указатель на функцию f соответственно.

В этом выражении

char buffer[1024];
memset(buffer, 0, 1024);

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

Эта функция

void foo_init(foo_t *f) 
{ 
    f->bar = 123; 
}

также может быть написано как

void foo_init(foo_t f) 
{ 
    f.bar = 123; 
}

но переданный параметр будет копией исходного, и изменения будут применяться только к локальной копии.

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

Таким образом, вам не нужно брать адрес массива, потому что он автоматически распадается на указатель, который указывает на его первый элемент, когда используется как таковой, тогда как когда вы передаете объект, размещенный в стеке, и хотите изменить его в Функция получателя, вам нужно передать указатель на нее, для которой вы используете адрес оператора.

Строковые литералы присваиваются по адресу указателям и по "значению" при использовании в качестве правого числа инициализации:

const char *str_ptr = "foo";  /* str_ptr points to a string "foo",
                                 in read-only memory. */

char chr_ar[] = "barbar";     /* chr_ar is 7 bytes, and is initialized
                                 with the bytes "barbar" */
Другие вопросы по тегам