Почему char ** не может быть типом возврата следующей функции в C ++? - PullRequest
3 голосов
/ 21 августа 2011

У меня есть следующая функция в C ++:

char** f()
{
    char (*v)[10] = new char[5][10];
    return v;
}

Visual studio 2008 говорит следующее:

error C2440: 'return' : cannot convert from 'char (*)[10]' to 'char **'

Каким именно должен быть тип возвращаемого значения, чтобы эта функция работала?

Ответы [ 3 ]

16 голосов
/ 21 августа 2011

char** отличается от типа char (*)[10]. Оба эти типа несовместимы, поэтому char (*)[10] не может быть неявно преобразовано в char**. Отсюда и ошибка компиляции.

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

char (*f())[10]
{
    char (*v)[10] = new char[5][10];
    return v;
}

Теперь он компилирует .

Или вы можете использовать typedef как:

typedef char carr[10];

carr* f()
{
    char (*v)[10] = new char[5][10];
    return v;
}

Ideone .


По сути, char (*v)[10] определяет указатель на массив char размера 10. Он такой же, как и следующий:

 typedef char carr[10]; //carr is a char array of size 10

 carr *v; //v is a pointer to array of size 10

Таким образом, ваш код становится эквивалентным этому:

carr* f()
{
    carr *v = new carr[5];
    return v;
}

cdecl.org помогает здесь:

  • char v[10] читается как declare v as array 10 of char
  • char (*v)[10] читается как declare v as pointer to array 10 of char
13 голосов
/ 21 августа 2011

Указатель на указатели не совпадает с указателем на массивы.

very crude diagram

(В частности, обратите внимание, как sizeof(*ptr1) равно sizeof(char)*6, тогда как sizeof(*ptr3) равно sizeof(char*) & ndash; это имеет серьезные последствия для арифметики указателей.)


new char[5][10] дает вам char (*)[10] (что, кстати, не имеет абсолютно никакого отношения к указателям на функции), потому что указатели и символы расположены таким образом в памяти (мой второй пример).

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

Таким образом, тип возврата вашей функции должен быть char (*)[10]:

char (*f())[10] {
    char (*v)[10] = new char[5][10];
    return v;
}

Конечно, это действительно ужасно, так что вам гораздо лучше с std::vector<std::string>.


Эта запись часто задаваемых вопросов объясняет это лучше всего под заголовком "Конверсии".

5 голосов
/ 21 августа 2011

Потому что char** и char (*)[10] - это два разных типа. char** - это указатель на указатель (на char), а char (*)[10] - это указатель на массив (размером 10) с char. В результате шаг перемещения из char** составляет sizeof(void *) байт, что составляет 4 байта на платформе win32, а шаг перемещения из char (*)[10] составляет sizeof(char) * 10 байт. *

Пример

   char *c = NULL;
   char **v = &c;
   cout << typeid(v).name() << endl;
   cout << (void*)v << endl;
   v += 1;
   cout << (void*)v << endl;

   char d[10];
   char (*u)[10] = &d;
   cout << typeid(u).name() << endl;
   cout << (void*)u << endl;
   u += 1;
   cout << (void*)u << endl;

выход

char * *
0034FB1C
0034FB20
char (*)[10]
001AFC50
001AFC5A

Чтобы использовать char (*)[10] в качестве типа возврата функции (или в качестве параметра ввода / вывода функции), самый простой и читаемый способ - использовать typedef:

// read from inside-out: PTRTARR is a pointer, and, it points to an array, of chars.
typedef char (*PTRTARR)[10];

Обратите внимание, что его можно легко перепутать с typedef массива указателей , если не соблюдать осторожность:

// operator[] has higher precedence than operator*,
// PTRARR is an array of pointers to char.
typedef char *PTRARR[10];

Ссылка

Массивы и указатели

...