Когда указатель на массив полезен? - PullRequest
10 голосов
/ 10 января 2010

Могу заявить:

int (*ap)[N];

Итак, ap - указатель на массив массива размера N. Почему это всегда полезно? Если я передаю его в функцию, что полезного он может с этим сделать, чего не может сделать обычный указатель на содержимое массива?

C FAQ говорят:

2.12: Как объявить указатель на массив?

Обычно вы не хотите.

Ответы [ 9 ]

13 голосов
/ 10 января 2010

Указатель на массив может использоваться для динамического выделения многомерного массива N, где известны размеры N-1. Ниже создается массив Nx3.

int (*ap)[3];
ap = malloc(N * sizeof(*ap));
/* can now access ap[0][0] - ap[N-1][2] */

@ Adam E / Cruachan, это не то же самое, что указатель на указатель. ap - это единственный указатель на блок памяти, содержащий три последовательных целых числа. ap ++ переведет адрес указателя в следующий блок из трех целых чисел. для int **pp; pp указывает на целочисленный указатель, каждый из которых может указывать на целое число в любом месте памяти.

         +-----+                +------+    +-----+
 ap ---> | int |   vs.  pp ---> | int* | -> | int |
         | int |                +------+    +-----+
         | int |        pp+1 -> | int* | -\
         +-----+                +------+   \   +-----+
 ap+1 -> | int |                  :  :      -> | int |
         | int |                               +-----+
         | int |
         +-----+
           : :  
6 голосов
/ 10 января 2010

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

Это не имеет большого значения, и его использование зависит от разработчика.

2 голосов
/ 11 января 2010

Как правило, единственный раз, когда вы увидите указатель на массив (T (*a)[N]) в качестве параметра функции, где a означает 2d массив:

void foo(int (*a)[N], size_t count)
{
  size_t i;
  for (i = 0; i < count; i++)
      a[i][j] = ...;
  ...
}

void bar(void)
{
  int arr[M][N];
  foo(arr, M);
}

Обратите внимание, что для объявления параметров функции int a[][N] эквивалентно int (*a)[N], но это только true для объявлений параметров функции:

void foo (int a[][N], size_t count) {...}

Указатели на массивы, как правило, не так полезны, как указатели на базовый тип, поскольку для правильного объявления указателя на него необходимо знать размер массива (указатель на массив из 10 элементов типа int отличается от типа указатель на массив из 20 элементов типа int). Лично я не нашел для них особого смысла за 20 с лишним лет программирования.

Помните, что в большинстве контекстов выражение массива (такое как arr выше) будет иметь свой тип, неявно преобразуемый из "массива N-элементов T" в "указатель на T" (кроме случаев, когда выражение массива является операндом sizeof или &, или массив является строковым литералом, используемым в качестве инициализатора в объявлении). В этом случае тип arr в вызове foo неявно преобразуется из «массива M-элементов массива N-элементов типа int» в «указатель на массив N-элементов массива int».

Учитывая объявление T a[M][N], все следующие выражения будут оцениваться в одном и том же месте (адрес первого элемента в массиве), но типы будут отличаться, как показано ниже:

Expression            Type                Implicitly converted to
----------            ----                -----------------------
         a            T [M][N]            T (*)[N]
      a[0]            T [N]               T *
        &a            T (*)[M][N]        
     &a[0]            T (*)[N]
  &a[0][0]            T *
2 голосов
/ 10 января 2010

Есть ситуации, когда вы хотите передать ячейку памяти между программами. Например, Windows API может ожидать, что вы передадите указатель на структуру данных или массив, где, как вы программируете на каком-то другом языке, скажем, c #. Windows API не волнует, как целевой язык обрабатывает массивы, для Windows API это просто поток байтов в памяти, и он заполнит его, отправит обратно вам. во избежание несоответствия типов языков в некоторых случаях мы используем указатель на массив, а не неявное имя массива в качестве указателя. Более того, не гарантируется, что неявное имя массива является длинным указателем, некоторые компиляторы могут оптимизировать его, чтобы оно было относительным значением в сегменте. указатель на массив гарантирует, что он имеет порядок размера регистра машины, и вы можете указать местоположение в любом месте доступной оперативной памяти.

2 голосов
/ 10 января 2010

Это не полезно, правда. Но иногда используются указатели на массивы, например в Microsoft Windows API - я видел много всего этого там.

0 голосов
/ 19 января 2011

Следующий код является частью моей статьи: Указатели и массивы в C C ++

Вы можете проверить это @ http://pointersandarrays.blogspot.com/

Указатели и2D-массивы

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

Фрагмент кода # 4


 #include<iostream&rt;  
    using namespace std;  

    int main()  
    {  
     cout<< "Understanding Pointers and 2 D Arrays"<<endl;  
     cout<< "----------------------\n"<<endl;  

    //Declaration of a 2D Array.  
    int tab[3][5];  
    //Total space required : 3*5 * sizeof(int) = 15 * sizeof(int)   
    //Funda : Since the amount of required space is known by compiler, contiguous 15 memory cells are allocated here.     
    //Hence the case is similar to a 1 D Array of size 15. Lets try this out!  

    //Array initialization using array name   
    for(int i=0; i<3;i++)  
     for(int j=0; j<5;j++)  
       tab[i][j]=i+2*j;  

    //Print array using array name   
    cout << "\nPrint array using array name ..."<<endl;    
    for(int i=0; i<3;i++)  
     {  
      for(int j=0; j<5;j++)  
       printf("%2d ",tab[i][j] );  
      printf("\n");  
     }  

    //Print array using a pointer. Proof of 1 D array being allocated  
    cout << "\nPrint array using a pointer. Proof of 1 D array being allocated ..." << endl;       
    int *tptr;  
    tptr = &tab[0][0]; // pointer tptr points at first element of the array.   

    for(int i=0; i<15;i++)  
     printf("%d ",*(tptr+i) );  
    tptr = &tab[0][0];  
    cout << "\nNotice that array is printed row by row in a linear fashion."<<endl;  
     return 0;  
    }  

Выход № 4: </p> <pre><code>Understanding Pointers and 2D Arrays Print array using array name ... 0 2 4 6 8 1 3 5 7 9 2 4 6 8 10 Print array using a pointer. Proof of 1 D array being allocated ... 0 2 4 6 8 1 3 5 7 9 2 4 6 8 10 Notice that array is printed row by row in a linear fashion.

0 голосов
/ 12 января 2010

Я думаю, что вывод из всего этого обсуждения: никогда . Никто здесь действительно не продемонстрировал использование этой конструкции, где что-то еще не работало бы более понятным способом.

0 голосов
/ 10 января 2010

Мне кажется довольно бесполезным указатель на массив. В C массив уже является указателем на блок этого типа данных.

int (*ap)[N];
int **ipp;

оба типа данных (указатель на указатель на целое число). Единственное отличие состоит в том, что есть место для N целых чисел, выделенных для ap.

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

0 голосов
/ 10 января 2010

Это, вероятно, рыскать в субъективное / логичный, но ...

По моему мнению, указатели на массивы находятся на языке, потому что они упали на язык. Есть указатели на каждый другой декларируемый тип данных, так что они здесь тоже. Я никогда не видел, чтобы кто-то получал от них действительно полезную работу. Гипотетически, они допускают прототип, который требует массив, а не указатель на элемент, но ...

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