Как массив C является «самостоятельной именованной переменной»?

На странице 103 в книге Питера Ван Дер Линдена Expert C Programming: Deep C Secrets есть таблица о разнице между массивами и указателями.

Один вопрос, который я не очень понимаю - прямая цитата:

Указатель. Обычно указывает на анонимные данные.

Массив: именованная переменная сама по себе.

Что это значит? Так как вы можете сделать следующее:

#include <stdio.h>
#include <stdlib.h>

int main(void){
  int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
  int *y = malloc(9*sizeof(int));
  printf("sizeof(x) == %zu\n", sizeof(x));
  printf("&(x[2]) = %p\n", (void*)&(x[2]));
  printf("sizeof(y) == %zu\n", sizeof(y));
  printf("&(y[2]) = %p\n", (void*)&(y[2]));
  return 0;
}

Вывод:

sizeof(x) == 36
&(x[2]) = 0x7fffffffe5f8
sizeof(y) == 8
&(y[2]) = 0x800e18008

Я не понимаю, почему y меньше именованной переменной, чем x.


person viuser    schedule 10.02.2019    source источник
comment
Данные, на которые указывает y, не являются y (вы можете назначить y = x;, а y будет указывать куда-то еще, но это все равно не будет y). Данные в x на самом деле являются неотъемлемой частью x; x и есть эта память, и никакая другая.   -  person ShadowRanger    schedule 10.02.2019


Ответы (4)


Тут автор мог бы быть понятнее, согласен. Указатель также является именованной переменной сам по себе, но если он указывает на массив, он не имеет никакой информации о длине массива. Фактически, он не знает, что указывает на массив. Синтаксис p[100] действителен (хотя и не определен), даже если p был назначен адрес одного int или другого типа данных.

Вот почему, когда массив передается в качестве аргумента функции, это либо:

  • Сопровождается параметром «длина», который доверяет вызывающему коду, чтобы предоставить его правильно.
  • Завершается сигнальным значением (например, нулевым терминатором для строк)

Чтобы более четко продемонстрировать это различие, попробуйте следующее:

int arr[3] = { 1,2,3 };
int *ptr;
ptr = &arr;

Я получаю следующее предупреждение о компиляции:

'=': 'int *' differs in levels of indirection from 'int (*)[3]'

Но если вы измените ptr так, чтобы он указывал на первый элемент arr (что и происходит, когда arr затухает до указателя), проблем не возникает:

ptr = &arr[0];
person Govind Parmar    schedule 10.02.2019
comment
Хм, извините, так что на практике, если нас не волнуют предупреждения, разница в вашем примере будет заметна только в том случае, если мы будем делать такие вещи, как ptr = (&arr)+1; (плохо!)? - person viuser; 10.02.2019

Я думаю, что автор пытается сказать, что элементы массива образуют именованный "объект" (согласно определению стандарта C), тогда как элементы указателя часто происходят из безымянного "объекта".

См. C11 §3.15 для определения объекта и §6.2.4 для информации о продолжительности хранения объекта.

Существует много дрянных книг по программированию, а C, старый и популярный язык, содержит больше, чем большинство других.

person o11c    schedule 10.02.2019

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

  int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
  int *y = malloc(9*sizeof(int));

x — это имя массива.

y — это имя указателя. Массив, на который он указывает, не имеет имени.

person Community    schedule 18.03.2019

На самом деле то, что вы написали, - это два способа объявить массив. Первый, конечно, традиционнее и проще. Автор пытается сказать нам, что массив — это именованная переменная, потому что вам нужна именованная переменная для доступа ко всем элементам массива. Чтобы перейти к следующему элементу и т. д., вам нужно поместить номер индекса. Итак, умножив «адрес» первого элемента на порядковый номер, вы получите нужный элемент. Если мы проанализируем его, массив [0] указывает на первый элемент и сам по себе является указателем.

Однако, чтобы правильно понять указатель, рассмотрим следующее:

int *y = malloc(sizeof(int));
int x[] = {1,2,3};
y = &x[2]; //points to an anonymous data because pointer "y" doesn't "know" the 
           //variable "x", only it's memory address
y = &x[0]; //points to the first element of x
person user9512695    schedule 10.02.2019
comment
Когда вы используете malloc, у вас есть указатель на блок памяти. Вы можете изменить, куда указывает указатель, вы можете изменить его размер. Вызвать утечку памяти, указав ее в другом месте. Ничего не произойдет с массивом. Хотя большинство людей думают об этом как о массиве. - person Manny_Mar; 10.02.2019
comment
Да, это вызовет утечку памяти при неправильном использовании. То, что вы получите, является мусорными значениями, потому что вы напрямую обращаетесь к адресу памяти (ячейкам памяти в вашем оборудовании RAM), если в коде есть логические ошибки. Вот почему лучше не использовать указатели как можно чаще. - person user9512695; 10.02.2019