двойной указатель против указателя на массив, несовместимый тип указателя - PullRequest
3 голосов
/ 21 июня 2020

Имея это:

#define _DEFAULT_SOURCE 1
#include <stdio.h>
#include <string.h>

int main(){
    char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    while((token=strsep(&org,",")))
        printf("Token: %s\n",token);
}

дает ошибку (несовместимый тип указателя):

/usr/include/string.h:439:14: note: expected ‘char ** restrict’ but argument is of type ‘char (*)[47]’
 extern char *strsep (char **__restrict __stringp,
  1. Я знаю, что это другой тип (у одного инициализирована память - > org[], но функция хочет указатель без инициализации памяти), но они имеют такое же поведение , так почему он все равно жалуется?

  2. И может кто-нибудь объясните мне, что означает это ключевое слово restrict или __restrict в случае *strsep (char **__restrict __stringp, (с другой стороны, я предполагаю, что __stringp не является внутренним типом данных (из-за двойного подчеркивания), а всего лишь причудливым имя переменной).

Изменить: я думаю, что массив хранится в стеке, но strsep хочет указатель, указывающий на кучу, что можно сделать с помощью org выделяется с помощью malloc, а затем memcpy, или, что еще лучше, скопируйте строку через strdup (что делает внутренне memcpy). Но в любом случае, способ strsep хочет, чтобы указатель указывал на кучу, а не на стек? Оба являются просто указателями, указывают только на разные адреса, но это не должно иметь значения.

Ответы [ 3 ]

2 голосов
/ 21 июня 2020

Функция strsep требует адрес изменяемого указателя в качестве первого аргумента (или NULL, в этом случае он ничего не делает); вы передаете ему (фиксированный) адрес массива. Вы можете исправить это, объявив отдельную переменную char* и присвоив ей (адрес) org массива:

int main()
{
    char* token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char* porg = org; // "porg" is a MODIFIABLE pointer initialized with the start address of the "org" array
    while ((token = strsep(&porg, ",")))
        printf("Token: %s\n", token);

    return 0;
}

из Linux страницы руководства ( жирным шрифтом):

Если *stringp равно NULL, функция strsep() возвращает NULL и больше ничего не делает. В противном случае эта функция находит первый токен в строке *stringp, который ограничен одним из байтов в строке delim. Этот токен завершается перезаписью разделителя нулевым байтом ('\ 0'), и *stringp обновляются, чтобы указать за токеном . В случае, если разделитель не найден, в качестве токена принимается вся строка *stringp, а *stringp создается NULL.

По значению и использованию ключевого слова restrict , может быть, это поможет: Realisti c использование ключевого слова C99 'restrict'? .

1 голос
/ 21 июня 2020

Адрес массива указывает на место начала массива, он имеет только другой тип - указатель на массив. Это не указатель на указатель.

    char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char *pointer = org;
    while((token=strsep(&pointer,",")))
    /* ... */

Вы не можете привести ссылку на массив к двойному указателю.

restrict это довольно продвинутый topi c. Он обещает компилятору, что если объект, на который ссылается указатель, будет изменен, доступ к этому объекту может быть выполнен только с помощью этого указателя. Это помогает компилятору в оптимизации кода.

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

0 голосов
/ 21 июня 2020
#include <stdio.h>
#include <string.h>

int main()
{
    char org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char *token = strtok(org, ",");
    while (token != NULL) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");
    }
}

Думаю, вам стоит взглянуть на эту страницу: Ограничитель типа

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