Czym się różni od std::string?Co to jest łańcuch zakończony znakiem NUL?
Odpowiedz
Łańcuch zakończony znakiem NUL jest ciągiem ciągłym znaków, z których ostatni ma binarny wzorzec bitowy zawierający wszystkie zera. Nie jestem pewien, co masz na myśli przez "zwykły ciąg znaków", ale jeśli masz na myśli std::string
, to nie jest wymagane std::string
(until C++11), aby być przyległym i nie musi mieć terminatora. Ponadto dane ciągów std::string
są zawsze przydzielane i zarządzane przez obiekt std::string
, który je zawiera; dla łańcucha zakończonego zerem, nie ma takiego kontenera, a Ty zazwyczaj odwołujesz się do tych łańcuchów i zarządzasz nimi za pomocą gołych wskaźników.
Wszystko to powinno być opisane w przyzwoitym podręczniku tekstowym w języku C++ - polecam uzyskanie Accelerated C++, jednego z najlepszych z nich.
Łańcuch zakończony znakiem NUL oznacza, że koniec łańcucha jest definiowany przez wystąpienie znaku null (wszystkie bity są zerowe).
"Inne ciągi" np. muszą przechowywać swoją własną długość.
"Ciąg" jest tak naprawdę tylko tablicą char
s; łańcuch zakończony zerem to taki, w którym pusty znak '\0'
oznacza koniec ciągu (niekoniecznie koniec tablicy). Wszystkie ciągi w kodzie (ograniczone przez podwójne cudzysłowy ""
) są automatycznie kończone przez kompilator.
Na przykład "hi"
jest taki sam jak {'h', 'i', '\0'}
.
Lepiej zrozumieć, niż zaakceptowana odpowiedź. +1 – Mike
Warto wspomnieć, że kompilatory szukają znaku pustego, aby określić długość łańcucha. –
Mam stałą łańcuchową i zapisałem a, b, c jako temp [0], temp [1] i temp [2]. Teraz, gdy robię "cout << temp", to nie daje - "abc". Co powinienem zrobić? Dowiedziałem się, że '\ 0' również nie działa tutaj jako terminator znaków. –
Łańcuch zakończony znakiem NUL jest rodzimym formatem ciągu w C. Literały łańcuchowe na przykład są zaimplementowane jako zakończone znakiem NUL. W wyniku tego cała masa kodu (początkowo biblioteka C-run-time) zakłada, że łańcuchy są zakończone znakiem NUL.
Istnieją dwa główne sposoby reprezentujące ciąg:
1) sekwencję znaków ASCII posiadających wartość null (nul) charakteru, 0, na końcu. Możesz sprawdzić, jak długo trwa wyszukiwanie terminatora. Nazywane jest to łańcuchem zakończonym znakiem NUL, lub czasem zakończone nul.
2) Sekwencja znaków plus oddzielne pole (długość całkowita lub wskaźnik na końcu łańcucha), aby poinformować, jak długo to trwa.
Nie jestem pewien co do "zwykłego łańcucha", ale często zdarza się, że mówiąc o danym języku, słowo "łańcuch" oznacza standardową reprezentację tego języka. Tak więc w Javie plik java.lang.String jest ciągiem typu 2, więc to właśnie oznacza "ciąg znaków". W C, "ciąg" prawdopodobnie oznacza ciąg typu 1. Standard jest dość gadatliwy, aby być precyzyjnym, ale ludzie zawsze chcą pominąć to, co "oczywiste".
Niestety w C++ oba typy są standardowe. std :: string jest łańcuchem typu 2 [*], ale standardowe funkcje biblioteczne odziedziczone po C działają na łańcuchach typu 1.
[*] Właściwie std :: string jest często implementowany jako tablica znaków, z osobnym polem długości i terminatorem nul. Dzieje się tak dlatego, że funkcja c_str()
może zostać zaimplementowana bez konieczności kopiowania lub ponownego przydzielania danych ciągu. Nie pamiętam od ręki, czy legalne jest wdrażanie std :: string bez przechowywania pola długości: pytanie, jakie wymagania gwarantuje standard złożoności. Ogólnie dla kontenerów size()
zaleca się mieć wartość O (1), ale nie jest to wymagane.Więc nawet jeśli jest to legalne, implementacja std :: string, która po prostu używa nul-terminatorów byłaby zaskakująca.
'\0'
jest znak ASCII o kodzie 0, null, null terminatora charakteru, NUL. W języku C służy jako zarezerwowana litera, która służy do oznaczenia końca ciągu znaków. Wiele standardowych funkcji, takich jak strcpy, strlen, strcmp i inne, polega na tym. W przeciwnym razie, jeśli nie było NUL, inny sposób zasygnalizować koniec łańcucha musi zostały wykorzystane:
Pozwala to ciąg być dowolnej długości tylko obciążania jednej bajt; alternatywa zapisywania zliczeń wymaga albo ograniczenia długości linii o wartości 255, albo o wiele więcej niż jednego bajtu.
C++std::string
wynika to innych konwencji, a jej dane są reprezentowane przez strukturę zwaną _Rep
:
// _Rep: string representation
// Invariants:
// 1. String really contains _M_length + 1 characters: due to 21.3.4
// must be kept null-terminated.
// 2. _M_capacity >= _M_length
// Allocated memory is always (_M_capacity + 1) * sizeof(_CharT).
// 3. _M_refcount has three states:
// -1: leaked, one reference, no ref-copies allowed, non-const.
// 0: one reference, non-const.
// n>0: n + 1 references, operations require a lock, const.
// 4. All fields==0 is an empty string, given the extra storage
// beyond-the-end for a null terminator; thus, the shared
// empty string representation needs no constructor.
struct _Rep_base
{
size_type _M_length;
size_type _M_capacity;
_Atomic_word _M_refcount;
};
struct _Rep : _Rep_base
{
// Types:
typedef typename _Alloc::template rebind<char>::other _Raw_bytes_alloc;
// (Public) Data members:
// The maximum number of individual char_type elements of an
// individual string is determined by _S_max_size. This is the
// value that will be returned by max_size(). (Whereas npos
// is the maximum number of bytes the allocator can allocate.)
// If one was to divvy up the theoretical largest size string,
// with a terminating character and m _CharT elements, it'd
// look like this:
// npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
// Solving for m:
// m = ((npos - sizeof(_Rep))/sizeof(CharT)) - 1
// In addition, this implementation quarters this amount.
static const size_type _S_max_size;
static const _CharT _S_terminal;
// The following storage is init'd to 0 by the linker, resulting
// (carefully) in an empty string with one reference.
static size_type _S_empty_rep_storage[];
static _Rep&
_S_empty_rep()
{
// NB: Mild hack to avoid strict-aliasing warnings. Note that
// _S_empty_rep_storage is never modified and the punning should
// be reasonably safe in this case.
void* __p = reinterpret_cast<void*>(&_S_empty_rep_storage);
return *reinterpret_cast<_Rep*>(__p);
}
bool
_M_is_leaked() const
{ return this->_M_refcount < 0; }
bool
_M_is_shared() const
{ return this->_M_refcount > 0; }
void
_M_set_leaked()
{ this->_M_refcount = -1; }
void
_M_set_sharable()
{ this->_M_refcount = 0; }
void
_M_set_length_and_sharable(size_type __n)
{
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
{
this->_M_set_sharable(); // One reference.
this->_M_length = __n;
traits_type::assign(this->_M_refdata()[__n], _S_terminal);
// grrr. (per 21.3.4)
// You cannot leave those LWG people alone for a second.
}
}
_CharT*
_M_refdata() throw()
{ return reinterpret_cast<_CharT*>(this + 1); }
_CharT*
_M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2)
{
return (!_M_is_leaked() && __alloc1 == __alloc2)
? _M_refcopy() : _M_clone(__alloc1);
}
// Create & Destroy
static _Rep*
_S_create(size_type, size_type, const _Alloc&);
void
_M_dispose(const _Alloc& __a)
{
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
if (__gnu_cxx::__exchange_and_add_dispatch(&this->_M_refcount,
-1) <= 0)
_M_destroy(__a);
} // XXX MT
void
_M_destroy(const _Alloc&) throw();
_CharT*
_M_refcopy() throw()
{
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
__gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
return _M_refdata();
} // XXX MT
_CharT*
_M_clone(const _Alloc&, size_type __res = 0);
};
rzeczywistych danych może być uzyskana z:
_Rep* _M_rep() const
{ return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }
ten fragment kodu pochodzi z pliku basic_string.h
który na moim komputerze znajduje sie w usr/include/c++/4.4/bits/basic_string.h
Więc jak widać, różnica jest znacząca.
Łańcuch znaków zakończony znakiem zerowym (ciąg-c) jest tablicą znaków, a ostatni element tablicy jest wartością 0x0. Std :: string jest w zasadzie wektorem, ponieważ jest to automatyczny rozmiar kontenera dla wartości. Nie potrzebuje terminatora zerowego, ponieważ musi śledzić rozmiar, aby wiedzieć, kiedy wymagana jest zmiana rozmiaru.
Szczerze mówiąc, wolę ciągi c-owe niż standardowe, mają po prostu więcej aplikacji w podstawowych bibliotekach, te z minimalnym kodem i przydziałami, a tym trudniejsze w użyciu.
- 1. C++, doładowanie asio, odbiera łańcuch zakończony znakiem o wartości NUL
- 2. Podwójny łańcuch zakończony znakiem Null
- 3. Jak przekonwertować łańcuch zakończony znakiem NUL w buforze bajtów na ciąg w Go?
- 4. Jak mogę wyprowadzać łańcuchy zakończone znakiem NUL w Awk?
- 5. Czy istnieje mimo to utworzenie łańcucha zakończonego znakiem NUL w programie Go?
- 6. NUL-bajt między każdym innym znakiem na wyjściu
- 7. Instrukcja php if z jednym równym znakiem ...? Co to znaczy?
- 8. Jak wydrukować łańcuch zakończony znakiem Null za pomocą znaków nowej linii bez pokazywania odwrotnych ukośników w gdb?
- 9. Co to jest użycie funkcji c_str W języku C++
- 10. Co to jest Serializable? Co to znaczy?
- 11. Co to jest "usuń to"?
- 12. Co to jest "obiekt zakończony" i dlaczego nie mogę wywoływać na nim metod?
- 13. Czy java definiuje łańcuch jako zakończone znakiem null?
- 14. Co to jest Pagel?
- 15. Co to jest _GLOBAL_OFFSET_TABLE?
- 16. Co to jest "android.R.layout.simple_list_item_1"?
- 17. Co to jest DetailsView.EnableModelValidation?
- 18. Co to jest NSPathStore2?
- 19. Co to jest czasownik = "*"?
- 20. Co to jest Postgresql_psycopg2?
- 21. Co to jest ?
- 22. co to jest .netrwhist?
- 23. co to jest Microsoft.Practices.EnterpriseLibrary.Data
- 24. Co to jest CGVector?
- 25. Co to jest $ {project.licensePath}?
- 26. co to jest alloc.h?
- 27. Co to jest PurpleEventCallback?
- 28. Co to jest global ::?
- 29. Co to jest? rodzaj?
- 30. Co to jest __meteor_bootstrap__?
Co to jest "zwykły" ciąg znaków? –
std :: string W każdym razie, mam już odpowiedź, thx. – lhj7362