Зная количество звездочек для использования в определениях методов в C? - PullRequest
1 голос
/ 18 октября 2010

Например:

void DeleteLastNode(NodeType **L)

Если ** L представляет адрес переменной L, не может ли он заменить вместо & L? Кроме того, если бы я использовал * L или просто L, я не смог бы изменить содержимое L? Если так, в чем разница использования * L и L, если L в любом случае является указателем на него? Разве я не смог бы посмотреть на его содержимое, просто отправив в L и используя * L в реальном методе?

Полагаю, я все еще не очень хорош с указателями.

Ответы [ 6 ]

5 голосов
/ 18 октября 2010

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

int x = 10;
int *p = &x;

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

int x, y;
int *p;
int **pp;

pp = &p;  //pp points to pointer p
*pp = &x; //pp changes pointer p to point to variable x
*p = 10;  //p (now points to x) assigns value 10 to x
*pp = &y; //pp changes pointer p again assigning the address of y
*p = 20;  //p assigns 20 to y;
**pp = 25;// that's tricky, the first * give access to the address pointed by p (&y) the second changes the content of that address to 25. so now y ends with 25

В конце х = 10 и у = 25

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

1 голос
/ 18 октября 2010

Давайте проясним некоторые вещи.Технически, L является указателем на указатель на экземпляр NodeType.Однако имя функции предполагает другую интерпретацию: вероятно, L - это адрес указателя на массив или связанный список экземпляров NodeType (чтобы убедиться в этом, обратитесь к документации по функции).

Если это так, то функция обычно используется следующим образом:

NodeType *list = malloc (5 * sizeof(NodeType));
/* do something with the list, e.g. put entries into it */
DeleteLastNode (&list);  /* delete last node in list */

Функция, вероятно, изменяет переменную, указывающую на массив / список, поэтому вы должны передать адрес перечислите функции.

Но чтобы сказать что-то конкретное, нам нужно больше информации о DeleteLastNode ().

0 голосов
/ 18 октября 2010
Если ** L представляет адрес переменной L, не может ли он быть заменен на & L вместо этого?

**L представляет значение в местоположении, на которое указывает местоположениена что указывает L.Для иллюстрации предположим следующие объявления:

int     a =   1;
int  * pa = & a; // whitespace doesn't matter here
int **ppa = &pa;

ppa указывает на pa, что в свою очередь указывает на a, который имеет значение 1.Вот гипотетическая карта памяти, показывающая их отношения (предположим, 32-разрядные целые числа с прямым порядком байтов):

Object       Address        0x00  0x01  0x02  0x03
------       -------        ----------------------
     a       0x10008000     0x00  0x00  0x00  0x01
    pa       0x10008004     0x10  0x00  0x80  0x00 
   ppa       0x10008008     0x10  0x00  0x80  0x04

В объявителе оператор * указывает, что эта переменная указатель и содержит адрес другой переменной.В выражении оператор * возвращает значение, на которое указывает указатель.В деклараторе C ++ оператор & указывает, что эта переменная является ссылкой и является синонимом для другой переменной (котораяне обязательно то же самое, что указатель; C не разрешает & в деклараторе).В выражении оператор & возвращает адрес своего операнда.

Итак, исходя из карты памяти, приведенной выше, все следующее верно:

    a == 1;
 * pa == 1; // again, whitespace doesn't matter here.
**ppa == 1; 

   &a == 0x10008000;
   pa == 0x10008000;
 *ppa == 0x10008000;

  &pa == 0x10008004;
  ppa == 0x10008004;

 &ppa == 0x10008008;
0 голосов
/ 18 октября 2010
NodeType nt;
NodeType *pnt = &nt;

--------         ------
| pnt  |-------->| nt |
--------         ------

Здесь pnt (содержание pnt) равно &nt;*pnt равно nt.

NodeType **L = &pnt;

------        --------         ------
| L  |------->| pnt  |-------->| nt |
------        --------         ------

Теперь L (содержимое L) равно &pnt;*L - это pnt;и, таким образом, **L равен *pnt, что составляет nt.Обратите внимание, что *& отменяет друг друга (*L -> *&pnt -> pnt).

0 голосов
/ 18 октября 2010

Что-то, что может помочь понять

NodeType **L

означает, что L - указатель на указатель на объект NodeType.

Например, если это

NodeType *P

, тогда P - указатель на объект NodeType, а если P - 0xE0101010, а каждый объект NodeType - 80 байтов, то P + 1 будет 0xE0101060 (0xE0101010 плюс 0x50 = 0xE0101060).

Тогда давайте посмотрим на L, который является указателем на указатель на NodeType. Если мы рассмотрим указатель как 4 байта, то если L равно 0xE0202020, а L + 1 будет просто 0xE0202024.

Поэтому важно использовать правильный тип, когда задействована арифметика указателей. Обратите внимание, что L [3] - это то же самое, что и * (L + 3), поэтому L [3] включает в себя арифметику указателей, поэтому типы указателей должны быть очень точными, или же когда вы смотрите на содержимое того, куда указывает указатель на * L, что означает разыменование вызова, тогда может возникнуть ошибка сегментации (Unix / Linux) или ошибка GP (Windows).

0 голосов
/ 18 октября 2010

Нет, не в C, звездочки в заголовке функции не могут быть заменены амперсандами (&) в теле функции. В C ++ это другой вопрос. Люди думали о чем-то похожем и добавляли эту функциональность, когда выбирали функции для C ++.

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