Я пытаюсь изучить C, и я работаю в к проблемам с помощью символа* и массивы символов. Я использую универсальный установленный на хеш контейнер из библиотеки (который я не хочу детально описывать). Эта библиотека включает функцию
void *HashSetLookup(hashset *h, const void *elemAddr);
который я должен использовать для поиска в наборе хеша, чтобы видеть, существует ли элемент уже там (хеш, и сравните, функции являются частью hashset структуры). В этом случае я использую hashset для хранения указателей на струны до, или более конкретно (символ * *). Моя проблема состоит в том, что следующий код дает отказ сегментации:
char word[1024];
/* Some code that writes to the word buffer */
HashSetLookup(stopList, &word);
в то время как этот код хорошо работает (и как ожидалось):
char word[1024];
/* The same code as before that writes to the word buffer */
char* tmp = strdup(word);
HashSetLookup(stopList, &tmp);
free(tmp);
Я думал, что символьное слово [] и символ* было в основном тем же самым. Так как единственной разницей является тот символьный Word [1024], находится в стеке с фиксированной длиной 1 024, но tmp в "куче", занимающей только столько же пространства по мере необходимости (strlen (Word) +1).
Поэтому я не понимаю, почему я должен сделать копию строки в "куче", чтобы смочь вызвать эту функцию. Почему это происходит? Есть ли некоторое более принципиальное различие между символом* tmp = strdup ("что-то") и символьным Word [1024] = "что-то"?
Вы упоминаете, что вам нужен char **
и здесь кроется проблема: для массива, word
и &word
означают одно и то же - фактическое расположение содержимого массива. Когда вы используете указатель, это работает потому, что "указатель" хранится в другом месте, а указывает на тот же массив. Вам не нужен strdup
, вам просто нужно создать указатель:
char* tmp = word;
HashSetLookup(stopList, &tmp);
Трудно сказать без документации по HashSetLookup.
Но он ожидает const void * в качестве второго параметра, поэтому вы должны передать tmp, а не &tmp, потому что tmp уже является указателем.
Я вообще не вижу здесь необходимости в char **.
Также, возможно, вам будет интересно узнать, что возвращает HashSetLookup().
Вы, должно быть, что-то упустили в первом примере, потому что "слово" вообще не используется.
Так или иначе, в большинстве сред, когда вы пишете 'char *s = "Hello World"', он создается в сегменте кода и не может быть изменен. Сегмент кода означает, что это часть исполняемого кода, который нельзя изменять, а только читать. Когда вы пытаетесь записать его, вы получаете ошибку seg fault.
Однако 'char[]' создается в сегменте данных, поэтому он может быть изменен без проблем.
Возможно, это поможет:
Поскольку вы упомянули char **
, я думаю, проблема в том, что функция пытается записать в место, указанное вторым аргументом, то есть когда вы пишете:
HashSetLookup( stopList, &word );
он пытается присвоить адрес слову
(и поэтому ему нужен его адрес .), которое перезаписывает буфер указателем.
Это демонстрирует следующий глупый фрагмент (имейте в виду, что адрес массива по-прежнему является адресом его первого элемента):
#include <stdio.h>
#include <stdlib.h>
void func( void* boo )
{
char** ptr = ( char** )boo;
printf( "func: got %p\n", boo );
*ptr = "bad func";
}
int main( int argc, char* argv[] )
{
char buf[128], *p;
func( &buf ); /* buf got overwritten */
printf( "array: %s\n", buf );
p = malloc( 128 );
func( &p ); /* p got new value */
printf( "malloc: %s\n", p );
return 0;
}