Что значит быть «обнуляемым»? - PullRequest
11 голосов
/ 19 апреля 2010

Я вхожу в C / C ++, и появляется много терминов, которые мне незнакомы. Одним из них является переменная или указатель, который заканчивается нулем. Что означает, что пространство в памяти заканчивается нулем?

Ответы [ 8 ]

16 голосов
/ 19 апреля 2010

Взять строку Hi в ASCII. Его простейшее представление в памяти - два байта:

0x48
0x69

Но где этот кусок памяти заканчивается? Если вы не готовы также передать количество байтов в строке, вы не знаете - фрагменты памяти по своей природе не имеют длины.

Таким образом, C имеет стандарт, в котором строки заканчиваются нулевым байтом, также известным как символ NUL:

0x48
0x69
0x00

Строка теперь однозначно состоит из двух символов, потому что перед NUL.

есть два символа.
14 голосов
/ 19 апреля 2010

Это зарезервированное значение для обозначения конца последовательности (например) символов в строке.

Более правильно известен как null (или NUL) прекращено . Это потому, что используемое значение - ноль, а не код символа для «0». Чтобы прояснить различие, ознакомьтесь с таблицей набора символов ASCII .

Это необходимо, поскольку языки типа C имеют тип данных char, но не тип данных string. Поэтому разработчик должен решить, как управлять строками в их приложении. Обычный способ сделать это состоит в том, чтобы иметь массив char s с нулевым значением, используемым для завершения (т.е. обозначения конца) строки.

Обратите внимание, что существует различие между длиной строки и длиной массива char, который был первоначально объявлен.

char name[50];

Это объявляет массив из 50 символов. Однако эти значения будут неинициализированы. Поэтому, если я хочу сохранить строку "Hello" (длиной 5 символов), я действительно не хочу задавать оставшиеся 45 символов пробелами (или каким-либо другим значением). Вместо этого я сохраняю значение NUL после последнего символа в моей строке.

Более поздние языки, такие как Pascal, Java и C #, имеют определенный определенный тип string. Они имеют значение заголовка, чтобы указать количество символов в строке. Это имеет несколько преимуществ; во-первых, вам не нужно идти до конца строки, чтобы узнать ее длину, во-вторых, ваша строка может содержать нулевые символы .

В Википедии есть дополнительная информация в строке (информатика) .

5 голосов
/ 19 апреля 2010

Завершено нулем

Это когда ваш заостренный босс увольняет вас.

0 голосов
/ 26 мая 2015

В то время как классический пример "завершается нулем" - это пример строк в C, концепция более общая. Его можно применять к любому списку вещей, хранящихся в массиве, размер которых не известен явно.

Хитрость заключается в том, чтобы просто избежать передачи размера массива путем добавления значения Sentinel в конец массива. Обычно используется некоторая форма нуля, но это может быть что угодно еще (например, NAN, если массив содержит значения с плавающей запятой).

Вот три примера этой концепции:

  1. C строк, конечно. К строке добавляется один нулевой символ: "Hello" кодируется как 48 65 6c 6c 6f 00.

  2. Массивы указателей, естественно, допускают нулевое завершение, поскольку нулевой указатель (тот, который указывает на нулевой адрес) определен так, чтобы никогда не указывать на действительный объект. Таким образом, вы можете найти такой код:

    Foo list[] = { somePointer, anotherPointer, NULL };
    bar(list);
    

    вместо

    Foo list[] = { somePointer, anotherPointer };
    bar(sizeof(list)/sizeof(*list), list);
    

    Вот почему execvpe() требуется только три аргумента, два из которых передают массивы определенной пользователем длины. Поскольку все, что передано execvpe(), - это (возможно, множество) строк, эта маленькая функция фактически поддерживает два уровня нулевого завершения: нулевые указатели, завершающие списки строк, и нулевые символы, завершающие сами строки.

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

    Foo list[] = {
        { someValue, somePointer },
        { anotherValue, anotherPointer },
        { 0, NULL }
    };
    bar(list);
    

    или даже

    Foo list[] = {
        { someValue, somePointer },
        { anotherValue, anotherPointer },
        {}    //C zeros out an object initialized with an empty initializer list.
    };
    bar(list);
    
0 голосов
/ 19 апреля 2010

Существует два распространенных способа обработки массивов, которые могут иметь содержимое различной длины (например, Strings).Первый - отдельно хранить длину данных, хранящихся в массиве.Такие языки, как Fortran и Ada и std :: string в C ++, делают это.Недостатком этого является то, что вам нужно как-то передавать эту дополнительную информацию всему, что имеет дело с вашим массивом.

Другой способ - зарезервировать дополнительный элемент, не являющийся данными, в конце массива, чтобыслужить в качестве дозорногоДля стража вы используете значение, которое никогда не должно появляться в реальных данных.Для строк 0 (или «NUL») - хороший выбор, поскольку он не печатается и не служит никакой другой цели в ASCII.Итак, что делает C (и многие языки, скопированные с C), это предполагает, что все строки заканчиваются (или «заканчиваются») на 0.

У этого есть несколько недостатков.Во-первых, это медленно.Каждый раз, когда подпрограмме нужно знать длину строки, это операция O (n) (поиск по всей строке в поисках 0).Другая проблема заключается в том, что вы можете однажды захотеть поставить 0 в вашей строке по какой-то причине, так что теперь вам нужен целый второй набор строковых подпрограмм, которые игнорируют нуль и в любом случае используют отдельную длину (например, strnlen ()).Третья большая проблема заключается в том, что если кто-то забудет поставить этот 0 в конце (или он каким-то образом уничтожен), следующая строковая операция, выполняющая дополнительную проверку, будет весело перемещаться по памяти, пока не произойдет случайный поиск другого 0,падает, или пользователь теряет терпение и убивает его.Такие ошибки могут быть серьезной PITA для отслеживания.

По всем этим причинам подход C обычно рассматривается с пренебрежением.

0 голосов
/ 19 апреля 2010

Строки в стиле C завершаются символом NUL ('\ 0'). Это обеспечивает маркер для функций, которые работают со строками (например, strlen, strcpy), чтобы использовать для идентификации конца строки.

0 голосов
/ 19 апреля 2010

Относится к тому, как строки C хранятся в памяти. Символ NUL, представленный \ 0 в строковых итерациях, присутствует в конце строки C в памяти. Нет других метаданных, связанных со строкой C, например длина, например. Обратите внимание на различное написание между символом NUL и указателем NULL.

0 голосов
/ 19 апреля 2010

Массивы и строки в C - это просто указатели на ячейку памяти. По указателю вы можете найти начало массива. Конец массива не определен. Конец массива символов (который является строкой) является нулевым байтом.

Итак, в строке памяти привет записывается как:

68 65 6c 6c 6f 00                                 |hello|
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...