2015-06-04 1 views
0

Чтобы прояснить точку, я написал две небольшие тестовые программы, приведенные ниже.Странное поведение при проверке символа NULL в 'C'

#include <stdio.h>                                          

int main(int argc, char *argv[]) 
{ 
    char *p = "ab"; 
    p++; 
    p++; 

    if (*p) 
     printf("p is not NULL \n"); 
    else 
     printf("ps is NULL \n"); 

    return 0; 

} 

выше Программа initalizes указатель обугленного p на строку буквального ab. Я увеличиваю указатель дважды, а затем цикл if проверяет, указывает ли p символ не-NULL. Это работает отлично и дает следующий вывод.

ps is NULL 

#include <stdio.h> 


int main(int argc, char *argv[]) 
{ 
    char *p = '\0';                                          

    if (*p) 
     printf("p is not NULL \n"); 
    else 
     printf("ps is NULL \n"); 

    return 0; 
} 

выше программа инициализирует указатель символ p на NULL символ \0 .Если я скомпилировать и запустить программу, я получаю сегментация fault.Can кто-то объяснить это?

Единственная разница в двух случаях: символ NULL находится в позиции 0 и позиции 2. В противном случае программа выглядит идентично мне.

+3

'char * p = '\ 0'; 'устанавливает значение p в NULL. Он * НЕ * инициализирует p, чтобы указать на NULL. ПРЕДЛОЖЕНИЕ: попробуйте 'char * p =" \ 0 "; 'или' char * p = ""; '. Попробуйте просмотреть сборку (gcc -S в Linux или cl/Fa в Windows). – paulsm4

+0

Вы ссылаетесь на нулевой указатель. – ssnobody

+0

'NULL символ находится в позиции 0':' char * p = ""; ' – BLUEPIXY

ответ

7

Важно понимать разницу между нулевым указателем (NULL) и нулевой символ * ('\0').

char *p = "ab"; 
p++; 
p++; 

Это правильно устанавливает указатель p, чтобы указать на нулевой символ в конце строки "ab".

char *p = '\0'; 

Это устанавливает p быть пустым указатель. Использование '\0' в качестве константы нулевого указателя является плохим стилем, но легальным (любое постоянное целочисленное выражение с нулевым значением является допустимой константой нулевого указателя). Выше эквивалентно понятнее:

char *p = NULL; 

Любая попытка разыменования p имеет неопределенное поведение, и, скорее всего, приведет к краху программы.

Единственная разница в двух случаях: символ NULL находится в положении 0 и в положении 2.

Если вы хотите нулевой символ (не NULL символов) в положении 0, вы можете написать:

char *p = "\0"; 

или почти то же самое:

char *p = ""; 

пустая строка состоит из только завершающий '\0' нуль знак.

+0

«нулевой символ» даже не называется нулевым символом. это символ NUL (именно потому, что нам нужно избегать путаницы целого числа 0 и нулевого указателя). –

+0

@ TheParamagneticCroissant: Да, это так. [N1570] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 5.2.1p2: «Байт со всеми битами, установленными в 0, называемый символом * null * , должен существовать в базовом наборе символов исполнения, он используется для завершения символьной строки. " –

+0

@TheParamagneticCroissant Возможно, вы думаете об этом, поскольку Windows имеет «NUL», в то время как Linux/UNIX имеет '/ dev/null'? В дополнение к ссылке Кита * нулевого символа * существует также * нулевой указатель *, и мы ** не ** называем его * указателем * nul *. – localhost

3

Вы инициализируете char* значением int. Если вы включите предупреждения, ваш компилятор должен предупредить вас об этом. Попробуйте:

char *p = "\0"; 

с двойными кавычками.

Обратите внимание, что NUL (символ с кодом 0) и NULL (значение указателя, которое не указывает ни на что) - это очень разные вещи.

+0

Я тоже собирался опубликовать это. –

+2

Фактически '' \ 0'' имеет тип 'int', а не' char' - и он является допустимой константой нулевого указателя (хотя использование этого метода - плохая идея). –

+0

Это неправильно; вопрос помечен 'c'. В C символьные литералы имеют тип 'int'. Итак, '' \ 0'' является интегральным постоянным выражением нулевого значения, следовательно, оно является константой нулевого указателя. Если компилятор выдает диагностику этой инициализации, она не соответствует требованиям. –

1

В C, '\0' - целочисленное выражение, поэтому у вас есть char *p = 0;. Поэтому p является указателем NULL.

Также обратите внимание на различие между указателем NULL и символом NUL.

См How do I get a null pointer in my programs?:

Согласно определению языка, символом `` интегральное выражение-константа со значением 0 «» в контексте указателя превращается в пустой указатель во время компиляции. То есть при инициализации, присваивании или сравнении, когда одна сторона является переменной или выражением типа указателя, компилятор может сказать, что константа 0 с другой стороны запрашивает нулевой указатель и генерирует правильно введенное значение нулевого указателя. Таким образом, следующие фрагменты совершенно законно:

char *p = 0; 
if(p != 0) 
3

Единственное различие в этих двух случаях символ NULL находится в положении 0 и положение 2"

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

Первая программа инициализирует p с массивом типа char [3]. Массив распадается на тип указателя, который заставляет p указывать на строку "ab", хранящуюся где-то в памяти. Эта строка заканчивается значением \0 в позиции 2, что является именно тем, что вы наблюдали.

Вторая программа инициализирует p с постоянной символа \0. Эта константа имеет тип int и значение 0. Эта инициализация инициализирует p с нулевым значением указателя. Это эквивалентно просто делает

char *p = NULL; 

Полученные p точки нигде. Проверка *p вызывает неопределенное поведение.

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

char *p = "\0"; 

или просто

char *p = ""; 

Примечание двойные кавычки. Это сделает p, чтобы указать на \0 значение в памяти.Но

char *p = '\0'; 

с одинарными кавычками - совершенно другая история, как объяснялось выше.

Смежные вопросы