Может ли / почему использование char * вместо const char * в типе возврата вызывать сбои? - PullRequest
6 голосов
/ 14 сентября 2009

Я где-то читал, что если вы хотите, чтобы функция C / C ++ возвращала массив символов (в отличие от std :: string), вы должны вернуть const char *, а не char *. Это может привести к сбою программы.

Кто-нибудь сможет объяснить, правда это или нет? Если это правда, почему возвращение char * из функции так опасно? Спасибо.

const char * my_function()
{
    ....
}

void main(void)
{
    char x[] = my_function();
}

Ответы [ 5 ]

14 голосов
/ 14 сентября 2009

Если у вас есть функция, которая возвращает «строковые литералы», она должна возвращать const char *. Их не нужно выделять в куче с помощью malloc, потому что они скомпилированы в секции только для чтения самого исполняемого файла.

Пример:

const char* errstr(int err)
{
    switch(err) {
        case 1: return "error 1";
        case 2: return "error 2";
        case 3: return "error 3";
        case 255: return "error 255 to make this sparse so people don't ask me why I didn't use an array of const char*";
        default: return "unknown error";
    }
}
11 голосов
/ 14 сентября 2009

То, что вам сказали, это не правда.

Возвращение const char * может улучшить семантику функции (т. Е. Не связываться с тем, что я вам даю), но возвращение char * совершенно нормально.

Однако, в любом случае, вы должны убедиться, что вы вернули char * или const char *, который был выделен в куче в my_function (т.е. выделен с использованием malloc или new), в противном случае всякий раз, когда возвращается my_function, память для [const] char * будет освобождена, и вы получите доступ к неверному указателю.

И, наконец, вы должны не забудьте free или delete [const] char *, который был возвращен вам, как только вы закончили с ним, или вы потеряете память , Разве C / C ++ не такие замечательные языки?

Итак, в C вы бы получили

const char *my_function() {
    const char *my_str = (const char *)malloc(MY_STR_LEN + 1);  // +1 for null terminator.
    /* ... */
    return my_str;
}

int main() {
    const char *my_str = my_function();
    /* ... */
    free(my_str);
    /* ... */
    return 0;
}
4 голосов
/ 14 сентября 2009

Обычно это не проблема, но есть вещи, на которые стоит обратить внимание. Обычно это вопрос правильности, что означает отслеживание того, что вы можете изменить, а что нет.

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

Если вы вернете массив символов в стеке (то есть, локальную переменную вызываемой функции), он исчезнет, ​​и указатель не будет указывать ни на что конкретно, возможно, с плохими результатами в какой-то момент.

Если вызываемая функция возвращает что-то, что уже const char *, то для изменения на char * требуется приведение. Кроме того, если вы на самом деле собираетесь изменить это, вы должны быть уверены, что это можно изменить. Обычно гораздо лучше сохранить его как const char *.

Нет немедленной проблемы с возвратом памяти, выделенной с помощью malloc() или new, но у вас есть проблема с владением: какая функция должна free() / delete, когда и что вы делаете с возможной копии? Вот где светятся умные указатели C ++.

2 голосов
/ 14 сентября 2009

Если символ * выделен в стеке, вы возвращаете висячий указатель. В противном случае, если оно соответствует прототипу функции, а объявление соответствует возвращаемому значению, все будет в порядке.

1 голос
/ 14 сентября 2009

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

...