Dlaczego const char * nie potrzebuje wskaźnika do adresu pamięci?

18

To może być proste pytanie, ale dlaczego const char * nie potrzebuje adresu pamięci, aby wskazywać?

Przykład:

const char* a = "Anthony";

i nie:

const char *a = // Address to const char

jak inne typy?

Weidelix
źródło
8
Co sprawia, że ​​myślisz, że literały łańcuchowe nie mają adresów pamięci?
user207421
2
Zgoda. Nie spodziewałbym się, że ktoś zadający to pytanie dowie się nawet o kategoriach wartości , nie mówiąc już o tym, że mają nazwy.
user4581301
13
Nie zadawaj pytań oznaczonych C i C ++. Jak możemy zauważyć, odpowiedzi są teraz specyficzne dla C ++, a komentarze ponownie wykoleją się na temat różnic między obydwoma językami. Jest tak wiele różnic, że trudno jest zadać pytanie, które w rzeczywistości ma taką samą prawidłową odpowiedź dla obu języków. Przed pytaniem zdecyduj, którego języka chcesz używać.
larkey

Odpowiedzi:

26

Możesz sobie wyobrazić tę deklarację

const char* a = "Anthony";

w następujący sposób

const char string_literal[] = "Anthony";

const char *a = string_literal;

Oznacza to, że kompilator tworzy tablicę znaków o statycznym czasie przechowywania, który przechowuje ciąg "Anthony" a adres pierwszego znaku tablicy (z powodu niejawnej konwersji desygnatorów tablic na wskaźniki na ich pierwsze znaki) jest przypisany do wskaźnika a.

Oto program demonstracyjny, który pokazuje, że literały łańcuchowe są tablicami znaków.

#include <iostream>
#include <type_traits>

decltype( auto ) f()
{
    return ( "Anthony" );
}

template <size_t N>
void g( const char ( &s )[N] )
{
    std::cout << s << '\n';
}

int main() 
{
    decltype( auto ) r = f();

    std::cout << "The size of the referenced array is "
              << std::extent<std::remove_reference<decltype( r )>::type>::value
              << '\n';

    g( r );

    return 0;
}

Wyjście programu to

The size of the referenced array is 8
Anthony

Rozmiar literału łańcuchowego (tablicy przechowującej literał łańcuchowy) jest równy, 8ponieważ łańcuch zawiera również kończący znak zero \0'.

W programie demonstracyjnym wyrażenie

std::extent<std::remove_reference<decltype( r )>::type>::value

może być zastąpione tylko wyrażeniem

sizeof( r )
Vlad z Moskwy
źródło
5

dlaczego const char nie potrzebuje adresu pamięci, aby wskazywać? *

To robi.

Literał C-string jak

"Anthony"

jest zepsute na adres jej 1 st charakteru. Podobnie jak BTW; robi to dowolna tablica w C.

alk
źródło
Mówiąc dokładniej, jest on typu const char[8](w C ++, może nie być char [8]w C, nie jestem pewien) i podobnie jak wszystkie wbudowane tablice, gdy używa go jako wartości, rozpada się na wskaźnik do pierwszego elementu.
Nikos C.
@NikosC .: Dziękujemy za przypomnienie mi najważniejszego czasownika magicznego w tym kontekście! ;)
alk
Dziękuję za odpowiedź! Zastanawiałem się, skąd bierze się pamięć.
Weidelix
1
Nie mogę mówić w języku C, ale jestem prawie pewien, że C ++ nie określa, gdzie należy przechowywać literał żądła. Po prostu poszedłem kopać. Jeśli istnieje reguła, jest ona zakopana gdzieś dziwnie i daleko od jakiejkolwiek wzmianki o „dosłownym łańcuchu znaków”.
user4581301
2
@NikosC. char [8]w C: c-faq.com/ansi/strlitnotconst.html
David Ranieri
1

Potrzebuje adresu pamięci i ma adres pamięci. W twoim przykładzie jest to po prostu adres pamięci początku łańcucha. Tak samo jest z każdą inną zmienną tablicową, która została zainicjowana w czasie kompilacji, na przykład „int array [] = {0, 1, 2, 3};”.

Jeśli użyjesz edytora binarnego do sprawdzenia pliku wykonywalnego, zobaczysz tam ciąg „Anthony”. Jeśli wstawisz wiersz „printf („ a jest w% p \ n ”, (void *) a);” w swoim programie, a następnie skompiluj i uruchom go, zobaczysz adres.

jamesqf
źródło
0

„Dlaczego const char*nie potrzebuje wskaźnika do adresu pamięci?”

W rzeczywistości tak potrzebujesz adresu pamięci do punktu do.

const char* a znaczy a wskaźnik do literału lub stałej znakowej.

Wskaźnik zawsze wymaga adresu do wskazania, ponieważ charakter wskaźnika wskazuje na określony obiekt w pamięci. Więc,a i każdy inny wskaźnik doconst char .

Dosłowny ciąg znaków, taki jak "Hi My Name is Alfred!"przy przypisaniu:

const char* a;
a = "Hi My Name is Alfred!";

rozpada się na wskaźnik do adresu pierwszego elementu literału łańcucha.

Oznacza z kolei, azostaje przypisany przez adres pierwszego elementu literału łańcucha"Hi My Name is Alfred!" który może być przechowywany w dowolnym miejscu w pamięci w zależności od środowiska wykonywania.

To nie jest w mocy programisty, gdzie dosłowny ciąg znaków jest dokładnie przechowywany. Twoim zadaniem jest tylko odpowiednie przypisanie i obsługa odpowiedniego wskaźnika.

RobertS obsługuje Monikę Cellio
źródło