Различаются ли указатели и массивы в C? - PullRequest
7 голосов
/ 28 июня 2009

Я пишу небольшую программу на C для некоторого сокращения чисел, и она должна передавать массивы между функциями. Функции должны принимать и возвращать указатели, верно?

Например, это (я знаю, что это не самая эффективная вещь):

int* reverse(int* l, int len) {
    int* reversed = malloc(sizeof(*reversed)*len);
    int i, j;
    for (i = 0, j = len-1; i < len; i++, j--) {
        reversed[j] = l[i];
    }
    return reversed;
}

Я правильно использую указатели?

Ответы [ 5 ]

14 голосов
/ 28 июня 2009

Ваш фрагмент кода правильный. Однако указатели и массивы в Си действительно разные. Проще говоря, «указатель на тип T» не совпадает с «массивом типа T».

Пожалуйста, посмотрите на C Faq обсуждение указателей и массивов, чтобы лучше понять это.

2 голосов
/ 28 июня 2009

Ссылка на C-FAQ: Массивы и указатели уже были даны, но в C также есть подробное объяснение для умных: Массивы и указатели . Вы можете сначала прочитать страницу «Анализ выражений».

Несколько вещей о вашем примере, которые следует исправить:

  1. Использование int вместо правильного size_t для хранения размеров объектов.
  2. Не удалось проверить возвращаемое значение malloc().

Один из способов «исправить» эту вторую проблему - позволить вызывающей стороне решить, где хранится вывод (возможно, вызывающая сторона не хочет или нуждается в недавно выделенном массиве):

int *reverse(int *out, int *l, size_t len) {
   size_t i, j;
   for (i = 0, j = len - 1; i < len; ++i, --j) {
     out[j] = l[i];
   }
   return out;
 }
1 голос
/ 28 июня 2009

В педантичной теории массивы и указатели - это разные вещи, поскольку массив задает область памяти и, следовательно, размер массива является частью его типа. Поэтому говорят, что имя массива распадается на указатель при использовании в этом контексте. В C-FAQ есть подробное объяснение .

На практике они одинаковы, поскольку формально a[i] - это то же самое, что и *(a+i), и, следовательно, серверная часть компилятора обрабатывает имя массива и указатель точно так же. Единственное, о чем стоит беспокоиться, это то, что

void foo()
{
   int a[5]; // allocates five words of space on the stack
   int *b;   // allocates *one* word of space on the stack (to hold the pointer)
}

Ваш фрагмент кода в порядке. Просто будьте осторожны, чтобы освободить память, которую выполняет ваша функция malloc() в том, кто ее вызывает.

1 голос
/ 28 июня 2009

С точки зрения низкого уровня, массив - это непрерывный кусок памяти, доступ к которому осуществляется по адресу начала этого фрагмента и смещения, поэтому с уровня абстракции это указатель. Однако с точки зрения языка Си тип массива отличается от типа указателя. В основном массиву можно присвоить значение указателя, но это не тот же тип .

Для выполнения вашей функции у вас все в порядке.

0 голосов
/ 28 июня 2009

массивы в C представлены и управляются указателем на первый элемент, например,

int arr[50];
int * ptr1 = arr;
int * ptr2 = &arr[0];

в этом примере ptr1 == ptr2, потому что адрес первого элемента массива и базовый указатель для массива совпадают.

так что ваш основной пример верен, хотя я подозреваю, что malloc, вероятно, должен быть:

int* reversed = malloc(sizeof(int)*len);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...