Нужна помощь в понимании указателей и различных других вещей C - PullRequest
0 голосов
/ 19 ноября 2009
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct dict_pair {
  void *key;
  void *value;
  struct dict_pair *tail;
} dict;


dict* NewDictionary(void) {
  dict *dictionary = malloc(sizeof(dict)); //or we can malloc(sizeof(struct dict_pair))
  dictionary->tail = NULL;
}

//dict operations
void put(dict *dictionary, void *key, void *value) {
  //new pair
  dict *new_pair = malloc(sizeof(dict));
  new_pair->key = key;
  new_pair->value = value;
  //chaining
  new_pair->tail = NULL;
  dict *last_node = dictionary;
  while (last_node->tail != NULL) {
    last_node = last_node->tail;
  }

  last_node->tail = new_pair;
}

void* get(dict *dictionary, void *key) {
  dict *current_dict = dictionary;
  while (1) {
    if (current_dict->key == key) {
      return current_dict->value;
    }
    else if (dictionary->tail != NULL) {
      current_dict = current_dict->tail;
    } else break;
  }
  return NULL;
}
//end operations

int main(void) {
  dict *dictionary = NewDictionary();
  put(dictionary,(void *) "buffer1",(void *) "Fake1");
  put(dictionary,(void *) "buffer2",(void *) "Fake2");
  put(dictionary,(void *) "key",(void *) "This is the value.");
  char *result = (char *) get(dictionary, (void *) "key");
  printf("%s\n",result);
}

Итак, мне удалось написать приведенный выше код для реализации словаря. Хотя я смог написать код, скомпилировать и заставить его работать ожидаемым образом, есть некоторые вещи, которые мне не совсем понятны. В основном касательно указателей:

dict *current_dict = dictionary;

Давайте возьмем эту строку, например. Мы объявляем переменную, которая содержит тип dict. current_dict - это указатель, верно? а словарь это указатель. Однако * current_dict не является указателем, как его можно назначить указателю?

Или я должен явно напечатать это, чтобы сделать это ошибкой?

dict (*current_dict) = dictionary;

Если это так, то означает ли это, что приведенная выше строка означает, что мы объявляем переменную current_dict с типом dict, а это указатель. Разве это объявление не будет

(dict*) current_dict = dictionary;

Как видите, интервал и расположение сбивают меня с толку.

Может ли кто-нибудь помочь объяснить разницу в * расположении?

Спасибо!

Ответы [ 6 ]

7 голосов
/ 19 ноября 2009

Хотя dict *dictionary и dict* dictionary имеют одинаковое значение в C, я предпочитаю первое.

Я предпочитаю думать об объявлениях указателей в следующих терминах:

int   x; //  x is an int
int  *y; // *y is an int
int **z; //**z is an int

Если вы помните, что *y - это объект, на который указывает y, то из этого следует, что y должен быть указателем на int. И аналогично z должен быть указателем на указатель на int.

4 голосов
/ 19 ноября 2009

Когда вы пишете:

dict * current_dict = dictionary;

это эквивалентно:

dict * current_dict;
current_dict = dictionary;

Я понимаю вашу путаницу, потому что * используется в языке C для двух целей: одна цель - объявить указатель в объявлении. Вторая цель - разыменовать указатель в выражении.

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

2 голосов
/ 19 ноября 2009
// * to the right of a type means a pointer of that type
Dict* dictPtr1 = dictPtr2; // LHS and RHS are pointers
Dict* dictPtr4 = (Dict *) malloc( sizeof(Dict));

// * to the left of a variable means dereference that variable
// the variable must be a pointer
Dict dictObject = *dictPtr; // LHS and RHS are objects


// & to the left of a variable means the address-of the object
Dict* dictPtr3 = &dictObject;
1 голос
/ 19 ноября 2009
dict *current_dict;

- указатель, пробел здесь не имеет значения. Все эти определения похожи:

dict *current_dict;
dict* current_dict;
dict * current_dict;
dict*current_dict;

Во всех вышеупомянутых случаях current_dict имеет тип указатель на dict

Имейте в виду, если у вас есть что-то вроде этого:

dict * current_dict,other_dict;

Вы объявили 2 переменные; current_dict имеет тип указатель на dict , тогда как other_dict имеет тип dict

1 голос
/ 19 ноября 2009

Неважно, где * стоит в объявлении переменной. dict* current и dict *current одинаковы. Но если вы используете указатель в выражении, то *dict означает разыменование, то есть возвращает объект, на который указывает dict.

0 голосов
/ 19 ноября 2009

dict *current_dict = dictionary;

Давайте возьмем эту строку, например. Мы объявляют переменную, которая содержит тип дикт current_dict является указателем, право? а словарь это указатель. Тем не менее, * current_dict не является указатель, как это может быть назначено указатель

Это объявляет current_dict указателем на dict и устанавливает его так, чтобы оно указывало на то же место, на которое указывает dictionary. Расположение * имеет значение только тогда, когда вы объявляете несколько переменных в одной строке.

Если бы вы положили

dict current_dict = dictionary;

это не сработало бы правильно, потому что объявляет current_dict фактической структурой.

Для чего это стоит, в вашей функции пут нет смысла делать

dict *last_node = dictionary;

и затем используйте last_node вместо dictionary. Они оба являются указателями на одно и то же, и когда вы объявляете указатель в параметрах вашей функции, как вы это делали с dict *dictionary, ваша функция фактически получает локальную копию указателя из вызывающей функции. Изменения в локальной копии указателя в dictionary не повлияют на указатель в вызывающей функции (если вы хотели такую ​​вещь, вам нужно иметь объявление функции, например void put(dict **dictionary, void *key, void *value) ... но вы не хотите что тут. :)).

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