#c
#c
Вопрос:
Мой вопрос относится как к конкретному заданию, над которым я работаю, так и к концептуальным отношениям между указателями и массивами. Я пишу хеш-таблицу в виде массива указателей на отсортированные списки. Я создал структуру для определения типа хэш-таблицы, а количество элементов в таблице определяется в макросе. Поскольку размер таблицы является переменным, структура должна содержать указатель на саму таблицу — указатель на массив указателей. Моя проблема заключается в том, что указатель на некоторый тип данных совпадает с меткой для первого элемента массива этого типа данных.
У меня есть тип данных SortedList
. Насколько я понимаю, SortedList*
может интерпретироваться либо как указатель на один SortedList, либо как указатель на первый элемент массива SortedList
‘s. В дополнение к этому, SortedList**
может быть массивом SortedList
указателей и SortedList***
может быть указателем на этот массив. Это то, что у меня есть в моей структуре хэш-таблицы. Мой первый вопрос: правильно ли я это понимаю?
В функции, которая создает хеш-таблицу, у меня есть это:
SortedList** array;
if ((array = calloc(size,sizeof(SortedList*))) == NULL) {
// error allocating memory
printf("Memory Errorn");
return NULL;
}
table->arrayPtr = amp;array;
So array
предназначен для моего массива SortedList
указателей и arrayPtr
является SortedList***
типом в моей структуре хэш-таблицы. Я использую calloc
, потому что думаю, что это инициализирует все мои указатели NULL
. Пожалуйста, дайте мне знать, если я ошибаюсь в этом. Все это компилируется без ошибок, так что, насколько я знаю, пока
все хорошо.
У меня есть функция, которая вставляет данные в таблицу, которая сначала проверяет, не использовался ли этот указатель уже, проверяя, указывает ли он на NULL
, если нет, он создает SortedList
для него указатель.
int i = index->hashFunc(word);
SortedList*** table = index->arrayPtr;
if (*(table i) == NULL){
return 0;
}
Итак, мне кажется, что разыменование (table i)
должно дать мне SortedList ** — i-й элемент в массиве указателей SortedList, который я могу затем проверить, установлен ли он NULL
. К сожалению, компилятор не согласен. Я получаю эту ошибку:
ошибка: недопустимые операнды для двоичного файла == (имеют ‘struct SortedList’ и ‘void *’)
Так что где-то вдоль линии мои рассуждения обо всем этом неверны.
Комментарии:
1. Прочитайте раздел 6 FAQ по comp.lang.c .
Ответ №1:
Возможно, вам потребуется прочитать немного больше о массивах и указателях в C, потому что я не думаю, что вы полностью понимаете концепцию. Я могу ошибаться, но я сомневаюсь, что вам понадобится трехуровневый указатель для достижения того, что вы пытаетесь сделать; Я думаю, вы можете запутать себя и думать, что если вы хотите указать на данные массива, вам нужно указать на фактический массив (amp;array ), который по сути являетсясам указатель. Рисование изображения также может действительно помочь визуализировать то, что происходит в памяти.
Массив — это просто блок последовательных данных, где имя переменной в C (без каких-либо [ ] , которые могли бы получить элемент из массива) указывает на первый элемент в массиве. Две строки в приведенном ниже примере эквивалентны (где array — это, очевидно, массив):
int *p_array;
p_array = array; /* equivalent */
p_array = amp;array[0]; /* equivalent */
Затем вы могли бы использовать p_array точно так же, как если бы вы использовали array, т. Е..
p_array[3] == array[3]
Ненужная вещь, которую некоторые люди могут делать, когда они учатся, — это иметь указатель на указатель на массив (я думаю, это то, что вы делаете):
int **p_p_array = amp;array;
И затем, чтобы получить доступ к элементам массива, им пришлось бы разыменовать указатель, а затем использовать нотацию массива для указания элемента в массиве:
*p_p_array[3] == array[3]
Что мы на самом деле сделали здесь, так это сохранили адрес памяти массива (который сам по себе является указателем на первый элемент), который затем мы должны разыменовать, чтобы добраться до первого элемента, а затем переместим на 3 позиции вперед, чтобы добраться до четвертого элемента (array[3] ).
В первом примере это намного проще и логичнее, поскольку мы храним указатель на первый элемент в массиве, и указатель действует так же, как наша начальная переменная массива.
Я рекомендую вам нарисовать то, что вы пытаетесь сделать, на листе бумаги / доске, чтобы увидеть, что вы делаете неправильно, и тогда может стать очевидным, как правильно это реализовать. правильный путь. Моя доска — один из моих лучших инструментов, когда я что-то пишу.
Комментарии:
1. Ссылки Кейта и Дж.Ф. объясняют это намного лучше, чем я могу; важно иметь возможность знать, что есть разница между указателем и массивом.
2. Спасибо за подробный ответ. Я думаю, что теперь я наконец-то заработал. Я использовал один * слишком много.