символ [1024] против символа * - PullRequest
5 голосов
/ 04 июля 2010

Я пытаюсь изучить C, и я сталкиваюсь с проблемами, используя char * и массивы char.Я использую универсальный контейнер с хэш-набором из библиотеки (который я не хочу описывать подробно).Эта библиотека включает в себя функцию

void *HashSetLookup(hashset *h, const void *elemAddr);

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

    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);

Я думал, что слово char [] и символ *были в основном то же самое.Единственное отличие состоит в том, что символьное слово [1024] находится в стеке с фиксированной длиной 1024, но tmp в куче занимает столько места, сколько необходимо (strlen (word) +1).

Поэтому яне понимаю, почему я должен сделать копию строки в куче, чтобы иметь возможность вызывать эту функцию.Почему это происходит?Есть ли еще фундаментальная разница между char * tmp = strdup ("что-то") и словом char [1024] = "что-то"?

Ответы [ 5 ]

6 голосов
/ 05 июля 2010

Вы упоминаете, что вам нужен char **, и здесь кроется проблема: для массива word и &word означают одно и то же - фактическое расположение содержимого массива.Причина, по которой он работает при использовании указателя, заключается в том, что «указатель» хранится в другом месте, а указывает на тот же массив.Вам не нужно strdup, вам просто нужно создать указатель:

char* tmp = word;
HashSetLookup(stopList, &tmp);
1 голос
/ 04 июля 2010

Трудно сказать без документации HashSetLookup.

Но он ожидает const void * в качестве второго параметра, поэтому вы должны передать tmp, а не & tmp, потому что tmp уже является указателем.

Здесь я вообще не вижу необходимости в символе **.

Кроме того, вас, возможно, заинтересует, что возвращает HashSetLookup ().

0 голосов
/ 05 июля 2010

Поскольку вы упомянули char** Я думаю, что проблема в том, что функция пытается записать в местоположение, указанное вторым аргументом, т.е. когда вы пишете:

HashSetLookup( stopList, &word );

идет и пытается присвоить адрес 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;
}
0 голосов
/ 04 июля 2010
0 голосов
/ 04 июля 2010

Вы, должно быть, что-то пропустили в первом примере, потому что "слово" вообще не используется.

Во всяком случае, в большинстве сред, когда вы пишете 'char * s = "Hello World"', он создается в сегменте кода и не может быть изменен.Сегмент кода означает, что он является частью исполняемого кода, который нельзя изменять, а только читать.Когда вы пытаетесь записать его, вы получаете ошибку сегмента.

Однако в сегменте данных создается 'char []', поэтому его можно без проблем изменить.

...