Использование или назначение указателя на указатель (C)

Я понимаю, что такое указатель, но я изо всех сил пытаюсь понять, для чего они используются. Я мог бы придумать ситуации, в которых вы МОЖЕТЕ использовать указатель, но эти ситуации, о которых я могу думать, также могут быть решены по-другому без дополнительной работы. В любом случае, чего я действительно не понимаю, так это использования указателей на указатели. Например, я наткнулся на этот простой C-код:

#include <stdlib.h>

int main(int argc, char** argv)
{
    ...
}

Насколько я понял, это должна быть программа, которую можно вызывать из командной строки с бесконечными параметрами, и это своего рода соглашение. Какова цель char** argv? Зачем здесь использовать указатель на указатель на char? Извините, если это тривиальный вопрос, но я, кажется, действительно изо всех сил пытаюсь получить здесь общую картину.

Заранее спасибо, Спаркс

возможный дубликат Как указатель на указатели работает в C?   —  person Sparkas    schedule 05.09.2015

argv — это (указатель на первый элемент) массив char*. Длина массива argc. Применяется нормальное затухание массива к указателю.   —  person Sparkas    schedule 05.09.2015

Использование указателей в C   —  person Sparkas    schedule 05.09.2015

См. также:  Проверка даты на основе массива Laravel after_or_equal несколько дат?
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 3
  1. Sparkas

    Указатель на указатель (на указатель…) полезен во всех ситуациях, когда вам требуется более одного уровня косвенности.

    В конкретном случае char** args у вас есть массив строк, которые являются аргументами, каждая строка в C является char*, поэтому в основном у вас есть что-то вроде

    char** args
            |
             ->  | char* | char* | char* | char* |
                     |       |
                     v       |
                    |f|o|o|  |
                             |
                             v
                            |b|a|r|
    

    Что в этом странного? Подумайте о том, что T* определяет тип, который является указателем на T. Теперь, если T == char*, то char** определяет указатель на char*, который, в свою очередь, является указателем на char.

    Помните, что в C и C++ указатель может представлять массив.

    Я бы никогда не догадался, что char **args будет указывать на массив указателей. Я бы просто предположил, что это будет указывать на один указатель. Хотя я не понимаю, как это работает, это, по крайней мере, помогает мне понять, почему мой данный пример работает именно так, так что спасибо за ответ! person Sparkas; 07.09.2015

  2. Sparkas

    Есть примеры C, где argv попеременно объявляется как массив указателей:

    char *argv[]
    

    Синтаксис указателя на указатель:

    char **argv
    

    объявляет указатель на то, что может быть первым указателем в массиве указателей. Другое распространенное использование — передача указателя на указатель на связанный список:

    node *head; /* pointer to linked list */
    /* ... */
    /* pass a pointer to head */
    list_function(&head);
    /* ... */
    /* use and update head */
    list_function(node **head){ ... }
    

    Спасибо за ответ! Теперь я знаю, что char **argv указывает на массив, но я бы интуитивно использовал способ char *argv[], если бы меня попросили создать массив указателей. Я просто не совсем понимаю, как массив создается или объявляется с помощью **argv. Обычно я предполагаю, что это просто указатель на одиночный указатель, но, возможно, я пойму это, когда узнаю больше об указателях. person Sparkas; 07.09.2015

  3. Sparkas

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

    Рассмотрим следующее:

    void foo( T *p ) // for any type T
    {
      *p = new_value(); // write to the thing p points to
    }
    
    void bar( void )
    {
      T var;
      foo( &var ); // foo updates value of var
      ...
    }
    

    Здесь функция foo обновляет переменную var, определенную в bar, через указатель p.

    Теперь давайте заменим тип T указателем типа Q *:

    void foo( Q **p )
    {
      *p = new_pointer_value(); // write to the thing p points to
    }
    
    void bar( void )
    {
      Q *var;
      foo( &var );  // foo updates the value of var
      ...
    }
    

    Семантика точно такая же; мы записываем новое значение в var. Единственное отличие состоит в том, что var имеет тип указателя, поэтому нам нужно использовать несколько уровней косвенности в foo.

    Вторая распространенная ситуация — когда у вас есть массив указателей, и вы передаете этот массив другой функции. Например:

    void foo( char **s )
    {
      while ( *s )
        puts( *s++ );
    }
    
    void bar( void )
    {
      char *strings[] = { "blurga", "bletch", "blah", NULL };
      foo( strings );
    }
    

    strings — это массив указателей на char; каждый элемент массива является адресом строкового литерала (или NULL). При вызове foo выражение массива strings преобразуется («затухает») в выражение типа «указатель на указатель на char«, а значением выражения является адрес первого элемента массива strings1. . Так как первый элемент массива является указателем, то и адрес первого элемента является указателем на указатель.

    Третий случай — когда вы выделяете память для 2D-массива по частям:

    T **arr = malloc( sizeof *arr * rows );
    if ( arr )
    {
      for( size_t i = 0; i < rows; i++ )
      {
        arr[i] = malloc( sizeof *arr[i] * cols );
      }
    }
    

    <�ч> 1. За исключением случаев, когда это операнд оператора sizeof или унарного оператора &, или строкового литерала, используемого для инициализации другого массива в объявлении, выражение типа «N-элементный массив T» будет преобразуется («распад») в выражение типа «указатель на T«, а значением выражения будет адрес первого элемента массива.

    Спасибо за примеры, я бы не подумал об этом, и это помогает понять использование указателей. person Sparkas; 07.09.2015

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: