2017-01-23 58 views
6

Czy istnieje powód podpis StrCpy jest to:Dlaczego program strcpy nie używa wskaźnika const dla dest?

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

zamiast tego?

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

O ile mi wiadomo, funkcja nigdy nie zmieni wskaźnika.

Czy nie rozumiem do czego służą wskaźniki const? Moim zdaniem, gdy funkcja, którą piszę, akceptuje wskaźnik, który nie zostanie zmieniony (przez realloc, itp.), To oznaczam go jako wskaźnik const, aby można było zapewnić, że wskaźnik nie zostanie na nich przesunięty. (W przypadku, gdy mają inne struktury/itp. Odnoszące się do lokalizacji wskaźnika, która stałaby się nieaktualna)

Czy to jest OK, czy może mieć niezamierzone konsekwencje?

+0

myślę stałą można zainicjować/assighned/zdefiniowany tylko raz lub jest zdefiniowany na podstawie deklaracji. –

+0

Nie tylko _ funkcja nigdy nie zmieni wskaźnika._, ale nie ma mowy, aby 'strcpy' mógł zmienić' dest' mimo to nawet bez const. –

Odpowiedz

11

Kod źródłowy strcpy jest z grubsza tak:

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

Tu faktycznie zmodyfikować dest ale nie ma to konsekwencje dla osoby dzwoniącej, ponieważ wewnątrz funkcji strcpy, dest jest zmienną lokalną.

Ale następujący kod nie będzie kompilować bo dest jest const:

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

musielibyśmy napisać to:

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

który wprowadza zakaz niezbędne temp zmienną.

+1

Uwaga: 3 przykłady nie zwracają wartości dla funkcji char chartrx(), która powoduje, że są one UB - oczywiście są one _rough_. Interesujące będzie zobaczenie kodu bez "niezbędnej zmiennej tymczasowej", która zwraca oryginalny "dest", jak określono w bibliotece C. – chux

+0

@chux masz rację, ale to tylko do celów demonstracyjnych. –

3

Kwalifikatory w argumentach funkcji są całkowicie ignorowane w deklaracjach (prototypach). Jest to wymagane przez język C, i ma to sens, ponieważ nie ma żadnego możliwego znaczenia, jakie taka kwalifikacja mogłaby mieć dla osób dzwoniących tej funkcji.

W przypadku const char *src, argument src nie jest tym, co jest kwalifikowane; typ, na który wskazuje, jest kwalifikowany. W Twojej hipotetycznej deklaracji dla dest kwalifikator dotyczy dest i dlatego jest bez znaczenia.

-1

O ile mi wiadomo, funkcja nigdy nie zmieni wskaźnika.

Tak, ale można. Możesz zmienić wskaźnik. Nie trzeba wykonywać dest wskaźnika const.

Na przykład:

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

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

To nie ma sensu, aby oznaczyć ją jako const jak sugerujesz. W C argumenty funkcji są przekazywane jako kopia. Oznacza to, że zmienna dest wewnątrz strcpy() jest w rzeczywistości nową zmienną (wciśniętą na stos), która zawiera tę samą zawartość (tutaj, adres).

Spójrz na tym prototypie funkcji:

void foo(int const a); 

To nie ma żadnej wartości semantycznej, bo wiemy, że oryginalny zmienną że minęliśmy się foo() nie mogą być zmienione, ponieważ jest to kopia. Tylko kopia może się zmienić. Kiedy zwracamy foo, mamy gwarancję, że oryginalna zmienna a pozostanie niezmieniona.

W parametrach funkcji, chcesz użyć słowa kluczowego const tylko wtedy, gdy funkcja może rzeczywiście trwale zmienić stan zmiennej. Na przykład:

size_t strlen(const char *s); 

Oznacza zawartość zmiennej s (czyli wartością zapisaną pod adresem s wskazuje na) jako const. Dlatego masz gwarancję, że twój ciąg znaków pozostanie niezmieniony po powrocie strlen.

2

oznacza, że ​​wskaźnik nie zmieni się w treści funkcji.

Nie oznacza to, że dane wskazane przez dest ulegną zmianie.

const char *src zapewnia kod wywołujący, że dane wskazane przez src nie ulegną zmianie.

W wywołaniu funkcji jak strcpy(d,s) lub foo(d,s), kod wywołujący nie obchodzi czy funkcja zmienia Jego kopię wskaźnika. Cały kod wywołujący troszczy się o to, czy dane wskazywane przez s lub d ulega zmianie i to jest kontrola przez const lewej stronie *

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`.