Подтвердить что ты не робот

Неявное преобразование из char ** в const char **

Почему мой компилятор (GCC) не скрывает от char** до const char**?

Следующий код:

#include <iostream>

void print(const char** thing) {
    std::cout << thing[0] << std::endl;
}

int main(int argc, char** argv) {
    print(argv);
}

Дает следующую ошибку:

oi.cpp: In function ‘int main(int, char**)’:
oi.cpp:8:12: error: invalid conversion from ‘char**’ to ‘const char**’ [-fpermissive]
oi.cpp:3:6: error:   initializing argument 1 of ‘void print(const char**)’ [-fpermissive]
4b9b3361

Ответ 1

Такое преобразование позволит вам помещать const char* в ваш массив char*, что было бы небезопасно. В print вы можете сделать:

thing[0] = "abc";

Теперь argv[0] будет указывать на строковый литерал, который нельзя изменить, а main ожидает, что он будет не const (char*). Поэтому для безопасности типа это преобразование не допускается.

Ответ 2

@Fred Overflow ссылка на часто задаваемые вопросы - это полный ответ. Но (извините Маршалла) это не самое ясное объяснение. Я не знаю, насколько ясен, но надеюсь.


Дело в том, что если p является указателем char*, тогда его можно использовать для изменения того, на что он указывает.

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

И с этим вы можете использовать p для изменения const char. Или, вы могли бы подумать, что могли бы. Но что const char может быть даже в памяти только для чтения & hellip;

В коде:

char const        c = 'a';
char*             p = 0;
char const**      pp = &p;               // Not allowed. :-)

*pp = &c;        // p now points to c.
*p = 'b';        // Uh oh.


Как практическое решение для вашего кода, который не компилируется, & hellip;
#include <iostream>

void print(const char** thing) {
    std::cout << thing[0] << std::endl;
}

int main(int argc, char** argv) {
    print(argv);    // Dang, doesn't compile!
}

просто сделай & hellip;

#include <iostream>

void print( char const* const* thing )
{
    std::cout << thing[0] << std::endl;
}

int main( int argc, char** argv )
{
    print( argv );    // OK. :-)
}

Приветствия и hth.,

Ответ 3

Обратите внимание, что хотя

void dosmth(const char** thing);

int main(int argc, char** argv) {
  dosmth(argv);

запрещено, вы можете и должны делать

void dosmth(const char* const* thing);

int main(int argc, char** argv) {
  dosmth(argv);

Скорее всего, это то, что вы хотели. Дело здесь в том, что thing теперь относится к массиву const char*, который сам по себе является неизменным и которые ссылаются на значения char сами по себе неизменяемы. Итак, для "взглянуть на него, но не меняйте его", const char* const* - это тип, который нужно использовать.

Примечание. Я использовал более общий (но, по моему мнению, худший) стандарт, пытающийся написать модификатор const как можно более левым. Лично я рекомендую писать char const* const* вместо const char* const*, так как это намного более кратким.

Ответ 4

Потому что это может позволить нам изменить постоянное значение. Читайте здесь, чтобы понять, почему: http://c-faq.com/ansi/constmismatch.html