Подтвердить что ты не робот

Что такое строка с нулевым завершением?

Как он отличается от std::string?

4b9b3361

Ответ 1

Строка с нулевым символом - это непрерывная последовательность символов, последняя из которых имеет бинарный битовый шаблон всех нулей. Я не уверен, что вы подразумеваете под "обычной строкой", но если вы имеете в виду std::string, то std::string не требуется (до С++ 11), чтобы быть смежным и не требуется иметь терминатор. Кроме того, строковые данные std::string всегда выделяются и управляются объектом std::string, который содержит его; для строки с нулевым завершением нет такого контейнера, и вы обычно ссылаетесь на такие строки и управляете такими строками с помощью простых указателей.

Все это должно действительно быть рассмотрено в любом приличном учебнике на С++ - я рекомендую завладеть Ускоренный С++, один из лучших их.

Ответ 2

"Строка" - это просто массив из char s; строка с завершающим нулевым символом является строкой, где нулевой символ '\0' отмечает конец строки (не обязательно конец массива). Все строки в коде (разделенные двойными кавычками "") автоматически завершаются нулевым компилятором.

Так, например, "hi" совпадает с {'h', 'i', '\0'}.

Ответ 3

Существует два основных способа представления строки:

1) Последовательность символов с нулевым (nul) символом ASCII, 0, в конце. Вы можете сказать, как долго это происходит, ища терминатор. Это называется строкой, завершающей нуль, или иногда nul-terminated.

2) Последовательность символов плюс отдельное поле (либо целая длина, либо указатель на конец строки), чтобы рассказать вам, как долго это будет.

Я не уверен в "обычной строке", но часто случается, что при разговоре о конкретном языке слово "строка" используется для обозначения стандартного представления для этого языка. Таким образом, в Java, java.lang.String является строкой типа 2, так что это означает "строка" . В C "строка" , вероятно, означает строку типа 1. Стандарт достаточно подробный, чтобы быть точным, но люди всегда хотят отказаться от того, что "очевидно".

В С++, к сожалению, оба типа являются стандартными. std::string является строкой типа 2 [*], но стандартные библиотечные функции, унаследованные от C, работают с строками типа 1.

[*] На самом деле std::string часто реализуется как массив символов с отдельным полем длины и терминатором nul. Это значит, что функция c_str() может быть реализована без необходимости копирования или перераспределения строковых данных. Я не могу вспомнить, вне зависимости от того, является ли законным внедрение std::string без сохранения поля длины: вопрос в том, какие стандарты сложности требуются стандарту. Для контейнеров вообще size() рекомендуется быть O (1), но на самом деле не требуется. Поэтому, даже если это законно, реализация std::string, которая просто использует nul-terminators, была бы удивительной.

Ответ 4

'\0' 

является символом ASCII с кодом 0, нулевым терминатором, нулевым символом, NUL. В языке C он служит в качестве зарезервированного символа, используемого для обозначения конца строки. Многие стандартные функции, такие как strcpy, strlen, strcmp среди других, полагаются на это. В противном случае, если не было NUL, должен был использоваться другой способ сигнализации конца строки:

Это означает, что строка имеет любую длину с только накладными расходами одного байт; альтернатива хранения счетчика требует либо строки предел длины 255 или накладные расходы более чем на один байт.

из wikipedia

С++ 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]); }

этот фрагмент кода происходит из файла basic_string.h, который на моей машине находится в usr/include/c++/4.4/bits/basic_string.h

Итак, как вы можете видеть, разница значительна.

Ответ 5

Строка с нулевым символом означает, что конец вашей строки определяется через появление null- char (все биты равны нулю).

"Другие строки", например. должны хранить свою длину.

Ответ 6

Строка с нулевым символом является родным строковым форматом в C. Строковые литералы, например, реализованы как завершающие нуль. В результате, весь код (C-библиотека времени выполнения для начала) предполагает, что строки имеют нулевое завершение.

Ответ 7

Строка с нулевым завершением (c-string) представляет собой массив из char ', а последний элемент массива имеет значение 0x0. std::string по существу является вектором, поскольку он представляет собой контейнер для автоматического изменения размеров. Он не нуждается в нулевом терминаторе, так как он должен отслеживать размер, чтобы знать, когда требуется изменить размер.

Честно говоря, я предпочитаю c-строки поверх std, у них просто больше приложений в базовых библиотеках, те, у которых минимальный код и распределения, и труднее использовать из-за этого.