Когда указатель на массив полезен?

Я могу заявить:

int (*ap)[N];

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

C Часто задаваемые вопросы:

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

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

Ответ 1

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

Ответ 2

Указатель на массив может использоваться для динамического выделения многомерного массива 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 |
         +-----+
           : :  

Ответ 3

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

Это не большое дело, и это зависит от разработчика.

Ответ 4

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

Ответ 5

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

Ответ 6

Как правило, единственный раз, когда вы увидите указатель на массив (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], но это верно только для объявлений параметров функции:

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

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

Помните, что в большинстве контекстов выражение массива (например, arr выше) будет иметь свой тип, неявно преобразованный из "N-element array of 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 *

Ответ 7

Это, вероятно, будет перенесено в субъективное/аргументированное, но...

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

Ответ 8

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

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

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

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

Ответ 9

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

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

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

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

Фрагмент кода # 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:

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.  

код >