2015-02-10 2 views
0

У меня есть пример программы C, которую я пытаюсь понять. Ниже приводится функция выдержки из исходного кода:Что означает ** в C?

double** Make2DDoubleArray(int arraySizeX, int arraySizeY) 
{ 
    double** theArray; 
    theArray = (double**) malloc(arraySizeX*sizeof(double*)); 
    int i = 0; 

    for (i = 0; i < arraySizeX; i++) 
    theArray[i] = (double*) malloc(arraySizeY*sizeof(double)); 

    return theArray; 
} 

Мой вопрос: какова значимость ** в типе возвращаемого значения. Я знаю, что * обычно используется как pointer. Я знаю, что он также может использоваться для указателя dereference.

Это заставляет меня думать, что double** является двойным значением, потому что это по существу разыменование ссылки. Правильно ли я считаю? Если нет, может кто-нибудь объяснить, пожалуйста, использование ** в этом примере?

+5

Указатель на указатель – sashas

+0

@sasha Какое значение имеет указатель на указатель? Можете ли вы объяснить это в ответ? –

+0

Cdecl C бредом ↔ английский объявить как указатель на указатель на двойной постоянную ссылку –

ответ

3

В этом случае double означает переменную типа double.

double* означает указатель на двойную переменную.

double** означает указатель на указатель на двойную переменную.

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

+1

@Jonathan Спасибо. Можете ли вы уточнить, почему указатель на указатель полезен/необходим в контексте этого примера? –

+5

@StenSoft: Нет, ** указатели не являются массивами **. Пожалуйста, прочитайте раздел 6 [comp.lang.c FAQ] (http://www.c-faq.com/). Я прошу удалить ваш комментарий, поскольку он может ввести в заблуждение других. Идея о том, что массивы являются «действительно» указателями, является распространенным заблуждением; пожалуйста, не помогайте его распространять. –

+0

@StenSoft: Не действительно в C; массивы отличаются от указателей (хотя массив будет неявно преобразовываться в указатель при любой возможности, которую он получает). –

2
some_type* 

является указателем на некоторый тип. Таким образом,

some_type** 

- указатель на указатель на some_type.

Обычно используется для 2D-массивов.

В вашем случае первый malloc резервирует память для указателей на массив удвоений. Второй malloc резервирует память для массива двойников. Таким образом, у вас есть 2D-массив.

EDIT: Исправленный как указал С. Моргенштерн

2

Вот более общий ответ: spiral rule. Для этого конкретного примера:

 +-----------+ 
     |+--------+ | 
     || +---+ | | 
     ||^ | | | 
double** foo; | | | 
^|^  | | | 
    | |+------+ | | 
    | +---------+ | 
    +--------------+ 

Читать это как «\» Foo \ «указатель на указатель на double

В этом случае каждый указатель семантически представляет собой массив, поэтому он представляет собой 2D-массив типа double.

1

* имеет несколько значений:

  1. обозначающие указатель на тип.
  2. Оператор разыменования.
  3. Оператор умножения.

Ваш пример использует только ** в типе для определения автоматической переменной:
double**, то есть указатель на указатель-to double.

1

Это ** в вашем случае означает указатель на указатель. Думаю, это понятно. A ** указывает на указатель, который по очереди указывает на ячейку памяти. Полезно сказать, хотите ли вы сохранить память, и вам нужно объявить 2D-массив с r строками и c столбцами, и они являются переменными. Так следующее, что вы делаете

 void create_matrix(int r,int c) 
     { 
      double ** matrix; 
      matrix = (double **)malloc(sizeof(double *)*r); 
      for(int i=0;i<r;i++) 
       matrix[i] = (double *)malloc(sizeof(double)*c); 
      /* do operations on matrix */ 
      return ; 
     } 
2

Автор использует один метод (не только) в C создания двумерного массива двойников, а именно, создание Y одномерные массивы дважды, и один массив из X указателей на них. К каждой из этих массивов Y обращается переменная типа double *. Затем он создает один одномерный массив указателей для каждого из этих массивов и сохраняет эти указатели в массиве типа double ** или указателя на указатель на двойное.

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

Единственным недостатком является то, что они занимают немного больше памяти.

+0

«меньше математики для достижения элемента» - для уточнения, это означает использование синтаксиса типа 'theArray [x_index] [y_index]' для доступа к элементу – anatolyg

+0

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

+0

Меньше математики, конечно. Но больше косвенности и сурового сокращения местности ссылок, что является гораздо более важным. Теперь, если массив должен быть неровным, это может быть приемлемым (возможно, неизбежным) решением ... – Deduplicator