Почему strcpy не использует указатель const для dest?

есть подписи причина и strcpy это:

char *strcpy(char *dest, const char *src);

вместо этого?

char *strcpy(char *const dest, const char *src);

насколько я знаю, функция не изменяет указатель.

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

это нормальная практика, или она будет иметь непреднамеренные последствия?

5 ответов


исходный код strcpy - Это очень грубо так:

char *strcpy(char *dest, const char *src)
{
  while (*dest++ = *src++);
}

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

но следующий код не будет компилироваться, потому что dest является const:

char *strcpy(char * const dest, const char *src)
{
  while (*dest++ = *src++);
}

нужно писать так:

char *strcpy(char * const dest, const char *src)
{
  char *temp = dest;
  while (*temp++ = *src++);
}

, который вводит не надо temp переменной.


Квалификаторами аргументов функции являются полностью игнорируется в заявления (образцы). Это требуется языком C, и это имеет смысл, потому что нет никакого возможного смысла, такая квалификация может иметь для вызывающих функцию.

в случае const char *src аргумент src - это не то, что квалификацию; тип указывает на квалификацию. В вашем гипотетическом заявлении для dest, квалификатор применяется к dest и таким образом бессмысленный.


char *foo(char *const dest, const char *src) { ... } означает указатель dest не будет меняться в теле функции.

это не означает данные, на которые указывает dest будет или не будет меняться.

const char *src уверяет вызывающий код, что данные, на которые указывает src не изменится.

при вызове функции типа strcpy(d,s) или foo(d,s), вызывающий код не заботится о том, изменяется ли функция его копия указателя. Весь вызывающий код заботится о том, если данные, на которые указывает s или d изменяется, и это управление с помощью const левой стороне *

char *dest,     // data pointed by `dest` may or may not change.
const char *src // data pointed by `src` will not change change because of `src`.

бессмысленно отмечать его как const, как вы предлагаете. В C аргументы функции передаются как copy. Это означает, что переменная dest внутри strcpy() фактически является новой переменной (нажатой в стеке), которая содержит тот же контент (здесь, адрес).

посмотрите на этот прототип функции:

void foo(int const a);

это не имеет семантического значения, потому что мы знаем, что исходная переменная a, которую мы передали foo() не может быть изменен, потому что это копия. Только копия будет потенциально измениться. Когда foo возвращается, мы гарантируем, что исходная переменная a остается неизменной.

в параметрах функции вы хотите использовать ключевое слово const только в том случае, если функция действительно может постоянно изменять состояние переменной. Например:

size_t strlen(const char *s);

это содержимое переменной s (т. е., значение, хранящееся по адресу s указывает на) как const. Таким образом, Вы гарантированно ваша строка будет неизменной, когда strlen возвращается.


насколько я знаю, функция не изменяет указатель.

да, но вы можете. Вы можете изменить указатель. Нет необходимости делать dest указатель const.

например:

int main(void)
{
    char *s = "Hello";
    char *d = malloc(6);

    strcpy(d, s);
    puts(d);
    strcpy(d, "World");
    puts(d);
}