Я писал такие вещи, как
char *x=NULL;
в предположении, что
char *x=2;
создаст char
указатель на адрес 2.
Но в The GNU C Programming Tutorial говорится, что int *my_int_ptr = 2;
целочисленное значение сохраняется 2
по любому случайному адресу, по которому my_int_ptr
оно выделяется.
Это может означать, что я char *x=NULL
присваиваю любое значение NULL
cast для a char
некоторому случайному адресу в памяти.
Пока
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *x=NULL;
if (x==NULL)
printf("is NULL\n");
return EXIT_SUCCESS;
}
действительно печатает
нулевой
когда я компилирую и запускаю его, меня беспокоит, что я полагаюсь на неопределенное поведение или, по крайней мере, на недоопределенное поведение, и что я должен написать
char *x;
x=NULL;
вместо.
c
pointers
initialization
Fagricipni
источник
источник
int *x = whatever;
делает, и тем, чтоint *x; *x = whatever;
делает.int *x = whatever;
на самом деле ведет себя какint *x; x = whatever;
, а не*x = whatever;
.Ответы:
TL; DR Да, очень нравится.
Фактическое утверждение , сделанное на направляющей читается как
Ну, они являются неправильно, вы правы.
Для оператора ( пока игнорируем тот факт, что указатель на целочисленное преобразование является поведением, определяемым реализацией )
int * my_int_ptr = 2;
my_int_ptr
является переменной (типа указателя наint
), у нее есть собственный адрес (тип: адрес указателя на целое число), вы сохраняете значение2
в этом адресе.Теперь,
my_int_ptr
будучи типом указателя, мы можем сказать, что он указывает на значение «type» в ячейке памяти, на которую указывает хранимое значениеmy_int_ptr
. Таким образом, вы существенно присваивая значение из переменной указателя, а не значение ячейки памяти , на которую указывает указатель.Итак, в заключение
char *x=NULL;
инициализирует переменную указателя ,
x
чтобыNULL
, не значение в адреса памяти , на который указывает указатель .Это то же самое, что и
char *x; x = NULL;
Расширение:
Теперь, будучи строго согласованным, утверждение вроде
int * my_int_ptr = 2;
является незаконным, поскольку влечет за собой нарушение ограничений. Чтобы было ясно,
my_int_ptr
переменная-указатель, типint *
2
имеет типint
.и они не являются «совместимыми» типами, поэтому эта инициализация недействительна, поскольку она нарушает правила простого присваивания, упомянутые в главе §6.5.16.1 / P1, описанной в ответе Лундина .
Если кому-то интересно, как инициализация связана с простыми ограничениями присваивания, цитата
C11
, глава §6.7.9, P11источник
2
этоint
задание - проблема. Но это еще не все.NULL
может также бытьint
,int 0
. Просто этоchar *x = 0;
хорошо определено, аchar *x = 2;
не так. 6.3.2.3 Указатели 3 (BTW: C не определяет целочисленный литерал , только строковый литерал и составной литерал .0
Является целочисленной константой )char *x = (void *)0;
, чтобы соответствовать? или это только с другими выражениями, которые дают значение0
?0
особенные: они неявно преобразуются в нулевые указатели отдельно от обычных правил явного приведения общих целочисленных выражений к типам указателей.int *p = somePtrExpression
IMHO довольно ужасный, поскольку похоже, что он устанавливает значение,*p
но на самом деле устанавливает значениеp
.Учебник неправильный. В ISO C
int *my_int_ptr = 2;
это ошибка. В GNU C это означает то же, что иint *my_int_ptr = (int *)2;
. Это преобразует целое число2
в адрес памяти каким-то образом, как определено компилятором.Он не пытается хранить что-либо в месте, указанном по этому адресу (если есть). Если вы продолжите писать
*my_int_ptr = 5;
, он попытается сохранить номер5
в месте, адресованном по этому адресу.источник
Чтобы прояснить, почему руководство неверно,
int *my_int_ptr = 2;
это «нарушение ограничений», это код, который не разрешается компилировать, и компилятор должен дать вам диагностику при обнаружении этого.Согласно 6.5.16.1 Простое назначение:
В этом случае левый операнд - неквалифицированный указатель. Нигде не упоминается, что правый операнд может быть целым числом (арифметический тип). Таким образом, код нарушает стандарт C.
Известно, что GCC ведет себя плохо, если вы явно не укажете, что это стандартный компилятор C. Если вы скомпилируете код как
-std=c11 -pedantic-errors
, он будет правильно давать диагностику, как и должен.источник
void *
, называется константой с нулевым указателем». Обратите внимание на предпоследний маркер в вашей цитате. Следовательно,int* p = 0;
это законный способ писатьint* p = NULL;
. Хотя последнее более наглядно и условно.int m = 1, n = 2 * 2, * p = 1 - 1, q = 2 - 1;
легальным и патологическое обфускацию .intptr_t
явно преобразовать объект в один из разрешенных типов с правой стороны. То естьvoid* a = (void*)(intptr_t)b;
допустимо по пункту 4, но не(intptr_t)b
является ни совместимым типом указателя, ниvoid*
константой,void* a
ни константой нулевого указателя, ни арифметическим типом, ни_Bool
. В стандарте говорится, что преобразование разрешено, но не подразумевается.int *my_int_ptr = 2
Это совершенно неверно. Если это действительно написано, пожалуйста, получите лучшую книгу или учебник.
int *my_int_ptr = 2
определяет целочисленный указатель, который указывает на адрес 2. Скорее всего, вы получите сбой, если попытаетесь получить доступ к адресу2
.*my_int_ptr = 2
, т.е. без символаint
в строке, сохраняет значение два для любого случайного адреса, наmy_int_ptr
который указывает. Сказав это, вы можете назначитьNULL
указателю, когда он будет определен.char *x=NULL;
совершенно верно C.Изменить: при написании этого я не знал, что преобразование целого числа в указатель - это поведение, определяемое реализацией. Подробности см. В хороших ответах @MM и @SouravGhosh.
источник
Значительная путаница в отношении указателей C возникает из-за очень плохого выбора, который изначально был сделан в отношении стиля кодирования, подтвержденного очень плохим небольшим выбором синтаксиса языка.
int *x = NULL;
правильно C, но это очень вводит в заблуждение, я бы даже сказал бессмысленно, и это затрудняет понимание языка для многих новичков. Это наводит на мысль, что в дальнейшем мы сможем сделать,*x = NULL;
что, конечно, невозможно. Видите ли, тип переменной - нетint
, имя переменной - нет*x
, и при этом*
в объявлении не играет никакой функциональной роли в сотрудничестве с=
. Это чисто декларативно. Итак, что имеет гораздо больше смысла, так это:int* x = NULL;
что также является правильным C, хотя он не соответствует исходному стилю кодирования K&R. Он дает совершенно понять, что тип естьint*
, а переменная-указатель естьx
, поэтому даже для непосвященных становится ясно, что значениеNULL
сохраняетсяx
, то есть указатель наint
.Кроме того, это упрощает вывод правила: когда звездочка находится вдали от имени переменной, тогда это объявление, а звездочка, прикрепленная к имени, - это разыменование указателя.
Итак, теперь становится намного понятнее, что дальше мы можем либо делать,
x = NULL;
либо,*x = 2;
другими словами, новичку легче увидеть, какvariable = expression
ведет кpointer-type variable = pointer-expression
иdereferenced-pointer-variable = expression
. (Для посвященных под «выражением» я подразумеваю «rvalue».)Неудачный выбор в синтаксисе языка заключается в том, что при объявлении локальных переменных вы можете сказать,
int i, *p;
что объявляет целое число и указатель на целое число, поэтому это наводит на мысль, что*
это полезная часть имени. Но это не так, и этот синтаксис - просто причудливый частный случай, добавленный для удобства, и, на мой взгляд, он никогда не должен был существовать, потому что он аннулирует правило, которое я предложил выше. Насколько мне известно, нигде в языке этот синтаксис не имеет смысла, но даже если это так, он указывает на несоответствие в способах определения типов указателей в C. Везде в других объявлениях с одной переменной, в списках параметров, в членах структуры и т. д. вы можете объявлять указатели какtype* pointer-variable
вместоtype *pointer-variable
; это совершенно законно и имеет больше смысла.источник
int *x = NULL; is correct C, but it is very misleading, I would even say nonsensical,
... Я должен согласиться, чтобы не согласиться.It makes one think
.... перестаньте думать, сначала прочтите книгу на C, без обид.int* somePtr, someotherPtr
объявлять два указателя, на самом деле, я обычно писал,int* somePtr
но это приводит к описанной вами ошибке.create
вместоcreat
. :) Дело в том, что так оно и есть, и нам нужно приспособиться к этому. Согласитесь, все сводится к личному выбору в конце дня.К многочисленным отличным ответам я хотел бы добавить что-то ортогональное. На самом деле инициализация
NULL
- это далеко не плохая практика и может быть удобной, если этот указатель может использоваться или не использоваться для хранения динамически выделяемого блока памяти.int * p = NULL; ... if (...) { p = (int*) malloc(...); ... } ... free(p);
Так как в соответствии со стандартом ISO-IEC 9899
free
аргумент является ошибочным, поэтомуNULL
приведенный выше код (или что-то более значимое в том же направлении) является допустимым.источник
void*
конвертируют по необходимости. Но наличие кода, работающего с компиляторами C и C ++, может иметь преимущества.const
указателями, объявленными в medias res , но даже когда указатель должен быть изменяемым (например, тот, который используется в цикле или с помощьюrealloc()
), установка его дляNULL
отлова ошибок там, где он использовался раньше он установлен с его реальной стоимостью. В большинстве систем разыменованиеNULL
вызывает segfault в момент сбоя (хотя бывают исключения), тогда как неинициализированный указатель содержит мусор, а запись в него повреждает произвольную память.NULL
, но бывает очень сложно отличить указатель мусора от действительного. Поэтому полезно убедиться, что все указатели всегда действительны илиNULL
с момента объявления.это нулевой указатель
int * nullPtr = (void*) 0;
источник
Это верно.
int main() { char * x = NULL; if (x==NULL) printf("is NULL\n"); return EXIT_SUCCESS; }
Эта функция подходит для того, что делает. Он присваивает адрес 0 указателю символа x. То есть он указывает указателем x на адрес памяти 0.
Альтернатива:
int main() { char* x = 0; if ( !x ) printf(" x points to NULL\n"); return EXIT_SUCCESS; }
Я предполагаю, что вы хотели:
int main() { char* x = NULL; x = alloc( sizeof( char )); *x = '2'; if ( *x == '2' ) printf(" x points to an address/location that contains a '2' \n"); return EXIT_SUCCESS; } x is the street address of a house. *x examines the contents of that house.
источник
char* x = 0; if (x == 0)
будет истинным. Указатели не обязательно являются целыми числами.