Определение строки без нулевого завершающего символа (\ 0) в конце

Какие существуют способы в C / C ++ для определения строки без завершающего нулевого символа char (\ 0) в конце?

РЕДАКТИРОВАТЬ: Меня интересуют только массивы символов, а не строка STL.

 Alexander Rafferty30 сент. 2010 г., 08:42
Кажется, многие люди повторяют один и тот же ответ: используйте std :: string.
 paxdiablo30 сент. 2010 г., 08:38
Этоне строка в C. В C строка определяется как массив символов, оканчивающийся символом NUL. То, что вы просите, это просто массив символов.
 Prasoon Saurav30 сент. 2010 г., 08:33
C / C ++ ?? [.....]
 Michael23 февр. 2018 г., 20:26
std :: string прекращается с n ++ после C ++ 11:en.cppreference.com/w/cpp/string/basic_string/data

Ответы на вопрос(9)

Существуют десятки других способов хранения строк, но использование библиотеки часто лучше, чем создание собственной. Я уверен, что мы все могли бы придумать множество дурацких способов делать строки без нулевых терминаторов :).

Завершающий ноль существует для завершения строки. Без этого вам нужен какой-то другой метод для определения его длины.

Вы можете использовать предопределенную длину:

char s[6] = {'s','t','r','i','n','g'};

Вы можете эмулировать строки в стиле паскаля:

unsigned char s[7] = {6, 's','t','r','i','n','g'};

Ты можешь использоватьstd::string (в C ++). (поскольку вы не заинтересованы в std :: string).

Желательно, чтобы вы использовали какую-то уже существующую технологию, которая обрабатывает юникод или, по крайней мере, понимает кодирование строк (т.е.wchar.h).

И комментарий: если вы помещаете это в программу, предназначенную для запуска на реальном компьютере, вы можете подумать об определении собственной строки. Это побудит ваш компилятор прекратить, если вы случайно попытаетесь передать его в функцию, ожидающую строку в стиле C.

typedef struct {
    char[10] characters;
} ThisIsNotACString;
 kriss27 июл. 2017 г., 11:44
если вы дойдете до определения своего собственного типа структуры, то нет смысла смешивать длину с символами для эмуляции строк паскаля. Было бы намного чище иметь отдельное поле для len. Это никак не изменит лежащую в основе структуру памяти, но позволит избежать некоторой путаницы.
 Tony Delroy30 сент. 2010 г., 09:01
+1 за самый полный ответ до сих пор, главное, что не хватает, это обсуждениеchar s[3] = "abc";...

строка класс и не иметь дело с нулевым символом вообще.

 Michael23 февр. 2018 г., 20:25

что обработчик строки может определить ее длину. Если вы не используете NULL-завершение, вам нужно передать длину строки либо через отдельный параметр / переменную, либо как часть строки. В противном случае вы можете использовать другой разделитель, если он не используется внутри самой строки.

Если честно, я не совсем понимаю ваш вопрос, или, если это действительно вопрос.

std::stringS не NUL прекращается.

П.С .:NULL это макрос1. NUL является\0, Не путай их.

1: C.2.2.3 Макрос NULL

Макрос NULL, определенный в любом из<clocale>, <cstddef>, <cstdio>, <cstdlib>, <cstring>, <ctime>, или же<cwchar>, является определенной в реализации постоянной нулевого указателя в этом международном стандарте (18.1).

 Chaoran01 нояб. 2018 г., 02:58
Начиная с c ++ 11, std :: string завершается нулем.
 JoshD30 сент. 2010 г., 08:55
Я хотел бы дать еще один +1 для этого пустого разъяснения с сноской.
 Alexander Rafferty30 сент. 2010 г., 08:50
NULL и NUL - просто причудливый способ сказать 0.
 David Rodríguez - dribeas30 сент. 2010 г., 10:14
@ Александр Рафферти: NUL - это имя нулевого символа '\ 0', а NULL - нулевой указатель. В Си это обычно определяется как(void*)0в то время как в C ++ есть только0, Обратите внимание, что разница - это тип, а не значение.

как правило, не будет более простого решения. Вы могли бы сделать то же, что сделал Паскаль, и поместить длину строки в первый символ, но это немного болезненно и ограничит длину вашей строки размером целого числа, которое может поместиться в пространство первого символа. ++ я бы определенно использовал класс std :: string, к которому можно получить доступ

#include <string>

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

Решение Вопроса

Типично, как написал другой постер:

char s[6] = {'s', 't', 'r', 'i', 'n', 'g'};

или если ваша текущая кодировка C является ASCII, что обычно верно (не так много EBCDIC сегодня)

char s[6] = {115, 116, 114, 105, 110, 107};

Существует также в значительной степени игнорируемый способ, который работает только в C (не C ++)

char s[6] = "string";

Если размер массива слишком мал, чтобы удерживать окончательный 0 (но достаточно велик, чтобы вмещать все остальные символы константной строки), конечный ноль не будет скопирован, но он все равно действителен C (но недействителен C ++).

Очевидно, вы также можете сделать это во время выполнения:

char s[6];
s[0] = 's';
s[1] = 't';
s[2] = 'r';
s[3] = 'i';
s[4] = 'n';
s[5] = 'g';

или (то же самое замечание о кодировке ASCII, что и выше)

char s[6];
s[0] = 115;
s[1] = 116;
s[2] = 114;
s[3] = 105;
s[4] = 110;
s[5] = 103;

Или используя memcopy (или memmove, или bcopy, но в этом случае это не выгодно).

memcpy(c, "string", 6);

или strncpy

strncpy(c, "string", 6);

Следует понимать, что в C нет такого понятия, как строка (в C ++ есть объекты строк, но это совсем другая история). Так называемые строки - это просто массивы символов. И даже имя символа вводит в заблуждение, это не символ, а просто числовой тип. Возможно, мы могли бы вместо этого назвать его байтом, но в старые времена было странное оборудование, использующее 9-битные регистры или около того, и байт подразумевал 8-битные.

Поскольку char очень часто будет использоваться для хранения кода символа, дизайнеры C подумали о более простом способе, чем сохранить число в char. Вы можете поместить букву между простыми кавычками, и компилятор поймет, что должен хранить этот код символа в символе.

Я имею в виду (например), что вам не нужно делать

char c = '\0';

Чтобы сохранить код 0 в символе, просто выполните:

char c = 0;

Поскольку нам очень часто приходится работать с кучей символов переменной длины, дизайнеры C также выбрали соглашение для «строк». Просто поместите код 0, где текст должен заканчиваться. Кстати, для этого вида строкового представления есть имя «строка с нулевым символом в конце», и если вы видите две буквы sz в начале имени переменной, это обычно означает, что ее содержимое является строкой с нулевым символом в конце.

«C sz strings» вообще не является типом, это просто массив символов, как обычно, как, скажем, массив int, но функции управления строками (strcmp, strcpy, strcat, printf и многие другие) понимают и используют 0 окончание конвенции. Это также означает, что если у вас есть массив символов, не оканчивающийся нулем, вы не должны вызывать ни одну из этих функций, так как это, вероятно, будет делать что-то не так (или вы должны быть очень осторожны и использовать функции сn письмо в их названии, какstrncpy).

Самая большая проблема с этим соглашением состоит в том, что есть много случаев, когда это неэффективно. Один типичный пример: вы хотите поместить что-то в конец строки с нулем. Если вы сохранили размер, который вы можете просто перепрыгнуть в конце строки, с помощью соглашения sz, вы должны проверить его символ за символом. Другие виды проблем возникают при работе с закодированным Unicode или тому подобное. Но в то время, когда был создан C, это соглашение было очень простым и отлично справлялось с работой.

В настоящее время буквы между двойными кавычками, такими как «строка», не являются простыми символами, как в прошлом, ноconst char *, Это означает, что указатель указывает на константу, которая не должна изменяться (если вы хотите изменить ее, вы должны сначала скопировать ее), и это хорошо, потому что это помогает обнаруживать много ошибок программирования во время компиляции.

 kriss30 сент. 2010 г., 11:26
@David Rodríguez - dribeas: Да, вы правы, но я считаю, что мой ответ уже достаточно сложен без добавления подробностей о различиях между типами массивов и указателями. Для тех, кто интересуется темой, я попытался объяснить это в этом ответе:stackoverflow.com/questions/3613302/...
 David Rodríguez - dribeas30 сент. 2010 г., 10:12
+1, но к мелочам, тип строкового литерала (т.е."hi") не являетсяconst char*, скорееconst char[3] где3 количество символов + 1 для конечного 0. Он может быть непосредственно назначенconst char* так как массивы распадаются на указатели на первый элемент, но этот простой тест покажет разницу:assert( sizeof(const char*) != sizeof("Hi there!") )

vector<char>

string класс будет хранить его с нулем. Если по какой-то причине вам совершенно не нужен нулевой символ в конце строки в памяти, вам придется вручную создать блок символов и заполнить его самостоятельно.

Лично я не могу придумать какой-либо реалистичный сценарий того, почему вы хотите это сделать, поскольку нулевой символ означает конец строки. Если вы тоже храните длину строки, то, я думаю, вы сохранили один байт за счет того, какой размер вашей переменной равен (вероятно, 4 байта), и получили более быстрый доступ к длине указанной строки.

 Adrian10 мая 2013 г., 14:36
Есть такие места, как микроконтроллеры, которые имеют ограниченные ресурсы памяти. В зависимости от количества хранимых строк, это может быть большой нагрузкой.
 Travis Pessetto14 апр. 2013 г., 01:44
Вы хотите строку без нулевого символа для заголовков HTTP. Они могут вызвать проблемы.

Ваш ответ на вопрос