Почему strrchr() возвращает `char*` вместо `const char*`?
Функция char* strrchr(const char *str, int ch)
возвращает указатель (char*
) в str
(const char *
) где последнее вхождение ch
расположен.
Таким образом, мы можем написать следующий код без приведения:
#include <string.h>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *ptr = strrchr (CONSTSTR, '/');
*ptr++ = 'B';
*ptr++ = 'A';
*ptr++ = 'D';
}
В чем преимущество возвращения char*
вместо const char*
?
РЕДАКТИРОВАТЬ:
Как отметил Shafik Yaghmour, есть очень хорошие ответы на вопрос: Как работает реализация strchr?
Поскольку мой код на C++, я буду использовать <cstring>
вместо <string.h>
, Спасибо за ваши ответы;-)
Тем не менее, ответ Майка Сеймура лучше всего подходит для вопроса. Я даже добавил более подробный ответ ниже, чтобы четко сказать, как strrchr()
является функцией C (перегрузка не разрешена), объявление подходит как для константных, так и для неконстантных строк. Так как strrchr()
может вызываться с неконстантной строкой, возвращаемая строка также должна быть неконстантной.
5 ответов
В Си функция должна быть такой, или заставлять пользователя использовать хитрые приведения во многих ситуациях:
- Если это заняло
const
указатель, вы не можете найтиconst
строка; - Если он вернул
const
указатель, вы не можете использовать его для измененияconst
строка.
В C++ вы должны включить <cstring>
а не устаревший C-only заголовок. Это даст вам две const-правильные перегрузки, которые не могут быть выполнены в C:
const char* strchr(const char* s, int c);
char* strchr( char* s, int c);
Вы смотрите на устаревшую функцию из стандартной библиотеки C (<string.h>
). Библиотека C++ (<cstring>
) вводит соответствующие const
и не const
перегрузки, так что вы должны использовать это везде, где это возможно.
const char *str
средства strrchr
гарантирует не изменять str
,
возврате const char *
средства strrchr
запрещает вам изменять возвращаемое значение.
strrchr()
от<string.h>
является функцией C. Поскольку C не разрешает перегрузку функций, strrchr()
был разработан для соответствия как константным, так и неконстантным строкам.
char* strrchr( const char *str, int ch );
strrchr()
может вызываться с неконстантной строкой, и поэтому возвращаемая строка также должна быть неконстантной, как объяснено в следующих примерах.
const context без ошибки компиляции:
#include <string.h>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
const char *basename = strrchr (CONSTSTR, '/');
// basename points to "foobar.txt"
}
неконстантный контекст без ошибки компиляции:
#include <string.h>
int main()
{
char nonconst[] = "foo/bar/foobar.txt";
char *basename = strrchr (nonconst, '/');
basename[0] = 'G';
basename[3] = 'D';
// basename points to "GooDar.txt"
}
Неправильное использование также без ошибки компиляции:
#include <string.h>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *nonconst = strrchr (CONSTSTR, '/');
*nonconst++ = 'B';
*nonconst++ = 'A'; // drawback of the unique declaration:
*nonconst++ = 'D'; // no compilation error
}
В C++ есть две перегруженные функции:
const char* strrchr( const char* str, int ch ); //1st
char* strrchr( char* str, int ch ); //2nd
const context использует 1-й:
#include <cstring>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
const char *basename = std::strrchr (CONSTSTR, '/');
// basename points to "foobar.txt"
}
неконстантный контекст использует 2-й:
#include <cstring>
int main()
{
char nonconst[] = "foo/bar/foobar.txt";
char *basename = std::strrchr (nonconst, '/');
basename[0] = 'G';
basename[3] = 'D';
// basename points to "GooDar.txt"
}
Неправильное использование должно привести к ошибке компиляции:
#include <cstring>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *nonconst = std::strrchr (CONSTSTR, '/');
// Visual C++ v10 (2010)
// error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'
*nonconst++ = 'B';
*nonconst++ = 'A';
*nonconst++ = 'D';
}
Но этот последний пример не приводит к ошибке компиляции, используя g++ -Wall file.cpp
, Протестировано с использованием версий GCC 4.1.2 (RedHat) и 4.7.2 (MinGW).
Почему вы запрещаете коду изменять возвращаемую переменную? Имейте в виду, что const char *
не является char * const
, вам будет разрешено изменить символ в любом случае, но вы не сможете контролировать само возвращаемое значение, что не имеет особого смысла, так как вы можете изменить его и отредактировать основную строку в другой позиции для твоя цель.