'\ 0' и printf () в C - PullRequest
       62

'\ 0' и printf () в C

21 голосов
/ 07 февраля 2020

Во вводном курсе C я узнал, что при хранении строки хранятся с нулевым символом \0 в конце. Но что, если я хочу напечатать строку, скажем printf("hello"), хотя я обнаружил, что она не заканчивается на \0, следуя инструкции

printf("%d", printf("hello"));

Output: 5

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

Ответы [ 9 ]

13 голосов
/ 07 февраля 2020

Нулевой байт отмечает конец строки. Он не учитывается по длине строки и не печатается, когда строка печатается с printf. Обычно нулевой байт сообщает функциям, которые выполняют манипуляции со строками, когда останавливаться.

Разница будет в том, что вы создадите массив char, инициализированный строкой. Использование оператора sizeof будет отражать размер массива, включая нулевой байт. Например:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6
8 голосов
/ 07 февраля 2020

printf возвращает количество напечатанных символов. '\0' не печатается - это просто сигнал о том, что в этой строке больше нет символов. Также не учитывается длина строки

int main()
{
    char string[] = "hello";

    printf("szieof(string) = %zu, strlen(string) = %zu\n", sizeof(string), strlen(string));
}

https://godbolt.org/z/wYn33e

sizeof(string) = 6, strlen(string) = 5
6 голосов
/ 07 февраля 2020

Все ответы действительно хороши, но я хотел бы добавить еще один пример, чтобы завершить все эти

#include <stdio.h>

int main()
{
    char a_char_array[12] = "Hello world";

    printf("%s", a_char_array);
    printf("\n");

    a_char_array[4] = 0; //0 is ASCII for null terminator

    printf("%s", a_char_array);
    printf("\n");

    return 0;
}

Для тех, кто не хочет испытывать это на онлайн GDB, вывод:

Hello world

Ад

https://linux.die.net/man/3/printf

Помогает ли это понять, что делает escape-терминатор? Это не граница для массива символов или строки. Это персонаж, который скажет парню, который анализирует -STOP, (печатает), анализирует до тех пор, пока здесь.

PS: А если вы проанализируете и распечатаете его как массив символов

for(i=0; i<12; i++)
{
    printf("%c", a_char_array[i]);
}
printf("\n");

, вы get:

Hell world

где, пробел после двойного l, является нулевым терминатором, однако, анализируя массив char, будет просто значение char каждого байта , Если вы выполните другой анализ и напечатаете значение int каждого байта ("% d%, char_array [i]), вы увидите, что (вы получаете представление ASCII code-int), пробел имеет значение 0.

6 голосов
/ 07 февраля 2020

В C все строковые литералы на самом деле являются массивами символов, которые включают в себя нулевой терминатор.

Однако, нулевой терминатор равен , а не , считая на длину строки ( буквальный или нет), и это не напечатано. Печать останавливается при обнаружении нулевого терминатора.

6 голосов
/ 07 февраля 2020

Ваше предположение неверно. Ваша строка действительно заканчивается \0.

. Она содержит 5 символов h, e, l, l, o и 0 символов.

То, что выводит внутренний вызов print() - это количество напечатанных символов, и это 5.

4 голосов
/ 07 февраля 2020

В C функция printf() возвращает количество напечатанных символов, \0 - терминатор null, который используется для обозначения конца строки на языке c, а встроенный string отсутствует. введите c++, однако размер вашего массива должен быть как минимум больше числа char, которое вы хотите сохранить.

Вот ссылка: cpp ссылка printf ()

3 голосов
/ 07 февраля 2020

Но что, если я захочу напечатать строку, произнесите printf ("привет") , хотя я обнаружил, что она не заканчивается на \ 0 следующим выражением

printf("%d", printf("hello"));

Output: 5

Вы не правы. Это утверждение не подтверждает, что строковый литерал "hello" не заканчивается завершающим нулевым символом '\0'. Это утверждение подтвердило, что функция printf выводит элементы строки до тех пор, пока не встретится завершающий нулевой символ.

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

Так что на самом деле это выражение

printf("hello")

обрабатывается компилятором примерно так:

static char string_literal_hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
printf( string_literal_hello );

Th действие функции printf в этом вы можете представить следующим образом

int printf( const char *string_literal )
{
    int result = 0;

    for ( ; *string_literal != '\0'; ++string_literal )
    {    
        putchar( *string_literal );
        ++result;
    }

    return result;
}

Чтобы получить количество символов, хранящихся в строковом литерале "hello", вы можете запустить следующую программу

#include <stdio.h>

int main(void) 
{
    char literal[] = "hello";

    printf( "The size of the literal \"%s\" is %zu\n", literal, sizeof( literal ) );

    return 0;
}

Вывод программы:

The size of the literal "hello" is 6
0 голосов
/ 13 февраля 2020

Строка - это вектор символов. Содержит последовательность символов, образующих строку, за которой следует специальная конечная строка символов: '\ 0'

Пример: char str [10] = {'H', 'e', ​​'l', ' l ',' o ',' \ 0 '};

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

char str [2 ] = {'h', 'e'};

0 голосов
/ 10 февраля 2020

Сначала вы должны очистить свою концепцию. Поскольку она будет очищена при работе с массивом, используемая вами команда печати просто подсчитывает символы, помещенные в парантез. В строке массива необходимо, чтобы она заканчивалась на \ 0

...