Некоторые массивы символов не заканчиваются на '\0'

У меня есть простой код на C, чтобы увидеть, заканчиваются ли три одинаковых массива символов на '\0':

int main(){
    char a[4] = "1234";
    char b[4] = "1234";
    char c[4] = "1234";


    if(a[4] == '\0')
            printf("a end with '\\0'\n");
    if(b[4] == '\0')
            printf("b end with '\\0'\n");
    if(c[4] == '\0')
            printf("c end with '\\0'\n");

    return 0;
}

Но вывод показывает, что только массив b заканчивается терминатором '\0'. Почему это? Я предполагал, что все массивы символов должны заканчиваться на '\0'.

Выход:

б заканчиваться на '\0'


person Tony Chen    schedule 17.07.2017    source источник
comment
Вы объявили массивы с пространством для 4 байт, но пытаетесь прочитать 5 байт.   -  person Ry-♦    schedule 17.07.2017
comment
Купите хорошую книгу для начинающих. Когда вы выполните все упражнения в нем, вы можете начать искать ошибки в компиляторе :D   -  person 0___________    schedule 17.07.2017
comment
Я полагал, что все массивы char должны заканчиваться на '\0'. -- Нет. Все строки должны заканчиваться разделителем \0, но допустимы массивы символов без разделителя null.   -  person ad absurdum    schedule 17.07.2017
comment
@DavidBowling, но можно ли инициализировать массив символов размером 4 с массивом символов размером 5?   -  person Ajay Brahmakshatriya    schedule 17.07.2017
comment
@AjayBrahmakshatriya - ну, вы не можете инициализировать массив другим массивом; вы инициализируете строковым литералом или списком инициализаторов. Дополнительные элементы в инициализаторе игнорируются, поэтому результатом использования char a[4] = "1234"; является то, что a представляет собой массив символов (как объявлено), инициализированный значениями из строкового литерала, но не string.   -  person ad absurdum    schedule 17.07.2017


Ответы (4)


Основная проблема заключается в том, что для массива, определенного как char a[4] = .... (с размером 4 элемента), использование if (a[4] ....) уже не соответствует одному и вызывает неопределенное поведение.

Вы хотите проверить наличие a[3], так как это последний действительный элемент.

Тем не менее, в вашем случае у вас нет места для нулевого терминатора!

Подчеркивая цитату из C11, §6.7.9,

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

Итак, вам нужно либо

  • используйте размер массива, в котором есть место для нулевого терминатора
  • или используйте массив неизвестного размера, например char a[ ] = "1234";, где размер массива автоматически определяется длиной предоставленного инициализатора (включая нуль-терминатор).
person Sourav Ghosh    schedule 17.07.2017
comment
Приятно видеть отрицательный голос, пожалуйста, добавьте комментарий, я настаиваю. - person Sourav Ghosh; 17.07.2017
comment
Я тоже не понимаю, вы абсолютно правы в своем ответе! - person Andre Kampling; 17.07.2017
comment
Спасибо! Я думаю, это ответ. - person Tony Chen; 17.07.2017
comment
NMDV: в мета просить объяснения самого DV. является спорным. Единственное, что я вижу здесь не так, это массив неизвестного размера s/b массив неопределенного размера - person chux - Reinstate Monica; 17.07.2017

Это неопределенное поведение, потому что вы пытаетесь получить доступ к массиву за пределами границ.

Не указывайте границу строки, инициализированной строковым литералом, потому что компилятор автоматически выделит достаточно места для всего строкового литерала, включая завершающий нулевой символ.

Стандарт C (c11 - 6.7.9: параграф 14) гласит:

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

Итак, не указывает границу массива символов при инициализации массива.

char a[] = "1234";
person msc    schedule 17.07.2017

Вам нужно еще одно место в конце массива для хранения \0. Объявите массивы длиной 5.

Вы можете получить доступ к n элементу массива, если массив состоит из n элементов. Здесь размер массивов составляет 4 байт, и вы пытаетесь получить 5 байт (поскольку индексы массива в C начинаются с 0), когда вы делаете что-то вроде if(a[4] == '\0').

person babon    schedule 17.07.2017

Выполните приведенный выше код без указания размера массива, в этом случае будут выполнены все 3 оператора if, здесь, поскольку мы указали размер массива, и мы знаем, что массив строк будет занимать еще 1 символ для NULL TERMINATION, но здесь мы не давал возможности массиву вести себя таким образом, поэтому компилятор ведет себя случайным образом.

person Manisha Janwani    schedule 18.08.2020