2015-09-05 3 views
0

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

#include <stdlib.h> 

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

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

Спасибо заранее, Sparkas

+4

возможно дубликат [Как сделать указатель на указатели работы в C?] (Http://stackoverflow.com/questions/897366/how-do-pointer-to-pointers-work-in-c) –

+1

' argv' является (указателем на первый элемент) массивом 'char *'. Длина массива - 'argc'. Применяется нормальный разброс от множества к указателю. – molbdnilo

+0

[Использование указателей в C] (http://stackoverflow.com/questions/5337848/could-you-help-me-understand-pointers-please/5341028#5341028) –

ответ

3

Указатель на указатель (к указателю ..) полезно во всех ситуациях, в которых вам нужно больше, чем один уровень косвенности.

В конкретном обстоятельстве 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++ указатель может представлять массив.

+0

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

1

Есть примеры 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){ ... } 
+0

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

1

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

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

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», а значение выражения является адресом первого элемента массива strings . Поскольку первый элемент массива является указателем, то адрес первого элемента является указателем на указатель.

Третий случай, когда вы выделения памяти для 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», а значение выражение будет адресом первого элемента o f массив.

+0

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

Смежные вопросы