2010-01-10 53 views

回答

36

以空字符结尾的字符串是连续的字符序列,最后一个字符串的二进制位模式全为零。我不确定“常用字符串”是什么意思,但如果您的意思是std::string,则不需要std::stringuntil C++11)是连续的,并且不需要有终结符。此外,std::string的字符串数据始终由包含它的std::string对象进行分配和管理;对于以空字符结尾的字符串,不存在这样的容器,并且通常使用裸指针来引用和管理这样的字符串。

所有这些都应该在任何体面的C++教科书中真正涵盖 - 我建议您抓住Accelerated C++,这是其中最好的一个。

+4

基本上,归零字节决定了C中字符串的长度。 – Costique 2010-01-10 14:08:20

+0

这很简单,thx! – lhj7362 2010-01-10 14:10:17

+0

最后一个字符不需要所有零的位模式,它只需要*值*为0. – avakar 2010-01-10 14:10:29

2

以空字符结尾的字符串表示字符串的末尾是通过出现空字符(所有位为零)定义的。

“其他字符串”例如必须存储自己的长度。

46

“字符串”实际上只是一个数组char s;以空字符结尾的字符串是空字符'\0'标记字符串的结尾(不一定是数组的结尾)。代码中的所有字符串(由双引号""分隔)都由编译器自动终止为空。

因此,例如,"hi"{'h', 'i', '\0'}相同。

+4

比接受的答案更好理解。 +1 – Mike 2015-04-17 21:39:00

+1

值得一提的是,编译器会查找空字符来确定字符串的长度。 – 2015-07-15 13:56:37

+0

我有一个字符串临时工,我存储了一个,b,c作为临时[0],临时[1]和临时[2]。现在,当我做“cout << temp”时,它不会给出 - “abc”。我该怎么办? 我知道'\ 0'在这里也不能用作字符串终结符。 – 2016-08-23 00:57:09

1

以空字符结尾的字符串是C中的本地字符串格式。例如,字符串文字实现为以null结尾。因此,大量代码(以C运行时库开始)假定字符串以空字符结尾。

14

有表示一个字符串的两种主要方式:

1)与ASCII空(NUL)字符,0的字符序列,在末端。您可以通过搜索终止符来判断它有多长。这被称为以空字符结尾的字符串,或者有时以nul结尾。

2)一个字符序列,加上一个单独的字段(整数长度或指向字符串末尾的指针),告诉你它有多长。

我不太确定“通常的字符串”,但经常发生的是,当谈到某种特定的语言时,“字符串”一词用于表示该语言的标准表示。所以在Java中,java.lang.String是一个2类字符串,所以这就是“string”的含义。在C中,“字符串”可能意味着1类字符串。为了准确,标准相当冗长,但人们总是想要忽略什么是“明显的”。

在C++中,不幸的是,这两种类型都是标准的。 std :: string是一个2型字符串[*],但从C继承的标准库函数对类型1字符串进行操作。 [*]实际上,std :: string通常是作为一个字符数组来实现的,其中一个单独的长度字段是一个nul终止符。这样就可以实现c_str()函数而不需要复制或重新分配字符串数据。我不记得在不存储长度字段的情况下实现std :: string是否合法:问题是标准需要什么复杂性保证。对于一般容器size()建议为O(1),但实际上并不需要。因此,即使它是合法的,只使用nul-terminators的std :: string的实现也会令人惊讶。

6
'\0' 

与代码0,null终止,空字符,NUL一个ASCII字符。在C语言中,它充当用于表示字符串结尾的保留字符。许多标准函数(如strcpy,strlen,strcmp等)都依赖于此。否则,如果没有NUL,另一种方式来发信号串的末尾必须已被用于:

这允许字符串是仅与一个 字节的开销任何长度;存储计数的替代方法需要字符串 长度限制为255或多于一个字节的开销。

wikipedia

C++std::string遵循此其他公约和其数据由称为_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); 
     }; 

的实际数据可能与获得:

_Rep* _M_rep() const 
     { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); } 

这个代码片断来自哪个我的机器上位于usr/include/c++/4.4/bits/basic_string.h

因此,大家可以看到,不同的是显著文件basic_string.h

0

以空字符结尾的字符串(c-string)是char的数组,并且该数组的最后一个元素是0x0值。 std :: string本质上是一个向量,它是一个值的自动调整大小的容器。它不需要空终止符,因为它必须跟踪大小以知道何时需要调整大小。

说实话,我更喜欢c-strings而不是std,他们只是在基本库中有更多的应用程序,只有最少的代码和分配的应用程序,因此很难使用。

相关问题