Преобразование char * в char * const * - PullRequest
5 голосов
/ 10 ноября 2011

Извините меня за основную «сущность» этого вопроса.Я в недоумении с указателями время от времени.У меня есть char *, но мне нужно преобразовать его в char * const *, чтобы иметь возможность правильно использовать его в функции fts ().Как мне это сделать?

Спасибо

Ответы [ 3 ]

11 голосов
/ 10 ноября 2011

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

Об указателях и указателях на указатели

char * - это указатель на строку символов, тогда как char ** - это указатель на строку символов. (const является бонусом). Это, вероятно, означает, что вместо предоставления строки символов вы должны предоставить массив строк символов.

Эти две вещи явно несовместимы. Не смешивайте их с актерами.

Об API fts_ *

Чтобы найти решение вашей проблемы, нам нужно прочитать API-функцию fts_ * (например, по адресу http://linux.die.net/man/3/fts), Я вижу, что:

FTS *fts_open(char * const *path_argv, int options,
          int (*compar)(const FTSENT **, const FTSENT **));

с вашим параметром char * const * path_argv, описание объясняет:

[...] Если аргумент сравнения () имеет значение ПУСТО (NULL), порядок обхода каталога находится в порядке, указанном в path_argv для корневых путей [...]

, который подтверждает, что функция fts_open действительно представляет собой набор путей, а не один единственный путь.

Итак, я думаю, вам нужно передать ему что-то вроде следующего:

char *p[] = { "/my/path", "/my/other/path", "/another/path", NULL } ;

О const

Типы в C и C ++ читаются справа налево. Так что если у вас есть:

  • char *: указатель на символ
  • char const *: указатель на const char (т.е. вы не можете изменить указанную строку, но вы можете изменить указатель)
  • const char *: аналогично char const *
  • char * const: постоянный указатель на символ (то есть вы можете изменить указанную строку, но не можете изменить указатель)
  • char **: указатель на указатель на символ
  • char * const *: указатель на постоянный указатель на символ (т. Е. Вы можете изменить указатель, и вы можете изменить строки символа, но вы не можете изменить промежуточный указатель

Это может сбивать с толку, но чтение их в порядке справа налево станет ясным, как только вы познакомитесь с указателями (и если вы программируете на C или C ++, вы хотите, чтобы стали знакомыми с указателями).

Если мы вернемся к первоначальному примеру (который отправляет кучу предупреждений на gcc с C99):

char ** p = { "/my/path", "/my/other/path", "/another/path", NULL } ;

Я играл с API, и вы можете указать его двумя способами:

    char * p0 = "/my/path" ;
    char * p1 = "/my/other/path" ;
    char * p2 = "/another/path" ;

    /* with a fixed-size array */
    char * pp[] = {p0, p1, p2, NULL} ;

    FTS * fts_result = fts_open(pp, 0, NULL);

Edit 2011-11-10: snogglethorpe справедливо прокомментировал, что это решение не является допустимым решением C89, даже если оно успешно компилируется с gcc (исключая pendantic + C89 flags). См. Ошибка: элемент инициализатора не вычисляется во время загрузки для получения дополнительной информации об этом

или

    /* with a malloc-ed array */
    char ** pp = malloc(4 * sizeof(char *)) ;
    pp[0] = p0 ;
    pp[1] = p1 ;
    pp[2] = p2 ;
    pp[3] = NULL ;

    FTS * fts_result2 = fts_open(pp, 0, NULL);
    free(pp) ;

Редактировать

После прочтения ответов других, только два из них ( mkb и moshbear ) избегают ошибки «просто приведите данные».

В своем собственном ответе я забыл терминатор NULL для массива (но тогда я не знаю ни API Linux, ни класса функций fts_ *, так что ...)

2 голосов
/ 10 ноября 2011

Я предполагаю, что вы говорите о fts_open:

FTS *fts_open(char * const *path_argv, int options,
                 int (*compar)(const FTSENT **, const FTSENT **));

От вас требуется массив из const char* указателей, т.е. массив строк. const просто для того, чтобы сказать вам, что он не собирается изменять ваши строки, и дает вам возможность передавать const строк.

Не const переменные могут рассматриваться как const, однако обычно вы не должны обращаться с ними наоборот.

Первый аргумент аналогичен argv, переданному main, вы можете просто получить:

char *path_argv[] = { "/first_path/", "/second_path/", NULL };

Важно, чтобы последний элемент был NULL , чтобы указать конец массива.

Обратите внимание, что path_argv также может быть объявлено как:

char **path_argv

OR *

char * const *path_argv

Любой из этих типов подходит для передачи в качестве первого аргумента fts_open. Однако вам, очевидно, придется инициализировать его не так, как описано выше, но это и другие способы, которыми вы можете объявить path_argv. Я сделал это неясным ранее.

А затем просто fts_open(path_argv, options, compar), где options - ваши параметры, а compar - ваша функция сравнения.

2 голосов
/ 10 ноября 2011

Вам необходимо создать второй массив, определяемый NULL (потому что первый аргумент fts() - это argv).

* 1005 Е.Г. *

char *const buf2[2] = { buf, NULL };
fts(buf2);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...