В C ++, какой смысл иметь функцию void foo (int ** p)? - PullRequest
0 голосов
/ 23 октября 2009

Мой коллега сказал мне, что void foo(int** p) используется как параметр out в C #. Может кто-нибудь точно объяснить, как?

Я понял, но чего-то не хватает. Я знаю, что если мы передадим сам указатель p в foo(*p), а тело функции сделает p = new int(), у нас может быть модификатор зависания! Но как foo(**p) предотвращает что-то подобное?

Ответы [ 5 ]

10 голосов
/ 23 октября 2009
void foo(int** p)
{
 *p = new int;
}


void main()
{
 int *p = NULL;

foo(&p);
//unless you pass the pointer to p, the memory allocated in the 
//function foo is not available here.

foo(p); // lets assume foo is foo(int* p)

//when you pass only pointer p to `foo()` then the value of the pointer will be 
//passed ( pass by value) to foo() and hence, any modification to pointer p ( in
// the form of allocating memory also) will not be available after the
// control returns from foo()
// The p will still points to NULL here, not the memory allocated in foo().  

}
3 голосов
/ 23 октября 2009

Другие объяснили, что делает void foo(int **p), но не ответили на другую часть вашего вопроса: «когда параметр не должен быть двумерным массивом».

Ответом здесь является параметр int**p, равный НИКОГДА 2D-массив. Даже если вы разыменуете его как p [row] [column], есть пара существенных отличий:

1) Память организована не как двумерный массив, а скорее как указатель на одномерный массив указателей «строк», каждый из которых указывает на отдельный одномерный массив целых чисел (индексируемых здесь как «столбец»).

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

3) «Строки» не обязательно должны быть одинакового размера (они могут различаться по количеству доступных элементов)

Для передачи двумерного массива в функцию вы можете использовать различные сигнатуры функций. Самый простой - void foo(int p[25][15]) (где 25 и 15 - размер строки и столбца вашего массива).

Следующие сигнатуры функций для двумерных массивов генерируют один и тот же код при вызове: void foo(int (&p)[25][15]) и void foo(int (*p)[25][15]) и void foo(int p[][15]). Последняя версия здесь p[][15] позволяет обрабатывать двумерные массивы с фиксированной шириной столбца, но с различным количеством строк.

Если вы слишком умны, вы можете передать двумерный массив как void foo2(int *p), если передадите адрес первого элемента (или вы можете использовать int a[25][15]; foo2(a[0]);). Однако в foo2 вам нужно будет использовать указатель math для доступа к строкам и столбцам 2D-массива, а также вам придется изменить способ вызова функции (чтобы передать int *, а не указатель массива). Эта «умная» техника иногда полезна в C, когда вам приходится работать с двумерными массивами разных размеров. В C ++ проще использовать шаблон с размерами массива в качестве параметров шаблона для обработки двумерных массивов различных размеров.

3 голосов
/ 23 октября 2009

int **p - это , а не двумерный массив. Это указатель на указатель на целое число .

1 голос
/ 23 октября 2009

Указатель на указатель ... несколько запутанный для: передачи указателя по ссылке Использование typedef значительно упрощает вещи:

typedef int* SomeType;

// C-style output parameter: pass address of variable
void create( SomeType* aVariable ) {
   *aVariable = new int;
}

// easier, more idiomatic C++: pass variable by reference
void create2( SomeType& aVariable ) {
   aVariable = new int;
}

int main() {
   SomeType localVar;
   create( &localVar );
   create2( localVar );
}
0 голосов
/ 23 октября 2009

Используя ** p, вы можете изменить то, на что * p ссылается в другой части вашей программы, и функция по-прежнему работает справа p.

...