В чем разница между "int * p = 0;" и "int * p; * p = 0;" - PullRequest
4 голосов
/ 24 июня 2019

Попытка выяснить разницу между инициализацией указателя и назначением указателя.

C язык

int *p=0;
int *p;
*p=0;

Я не знаю, в чем разница между этими двумя методами. То же самое?

Ответы [ 8 ]

7 голосов
/ 24 июня 2019

Внутри функции

int *p = 0;

эквивалентно:

int *p;
p = 0;

Т.е. сама переменная инициализируется, а часть объявления декларации игнорируется.В отличие от:

int *p;
*p = 0;

, что приводит к неопределенному поведению, поскольку target неопределенного указателя назначается.

2 голосов
/ 24 июня 2019
int *p=0;

Эта строка объявит указатель int * и сделает его указателем 0. Также убедитесь, что вы установили p, чтобы указать правильную память перед разыменованием.

int *p;
*p=0;

Неопределенное поведение. Поскольку p никуда не указывает.

1 голос
/ 24 июня 2019

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

  • int *p; является объявлением указателя нацелое число.
  • *p=0; разыменовывает указатель, получает доступ к местоположению, на которое он указывает, и пытается записать туда значение 0.Чтобы все было в порядке, указатель должен быть вначале установлен на правильную ячейку памяти.
  • int *p = 0; - это объявление указателя на целое число со значением инициализатора.Это устанавливает , куда указывает сам указатель .Это не разыменование.

Присвоение / инициализация значения 0 для самого указателя является особым случаем, поскольку это переводится как «константа нулевого указателя».В основном указатель, указывающий на четко определенный нигде.Вместо этого предпочтительно использовать макрос NULL из stddef.h, чтобы мы не смешивали его с целочисленным значением 0.

, поскольку в случае *p=0; в строкесамо по себе 0 - это просто целое значение.

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

1 голос
/ 24 июня 2019

Оба разные. Здесь

int *p=0;

целочисленный указатель p назначен с 0, и это то же самое, что

int *p; /* first p is declared : uninitialized */
p = 0; /* then assigned with 0 */

Хотя я бы не предпочел p = 0. Это

int *p = NULL;

лучше. И вот

int *p; 
*p=0; /* p doesn't have any valid address, de-referencing it causes UB */

вы пытаетесь присвоить *p с помощью 0, что неверно, поскольку p не имеет действительного адреса в этом случае. Он вызывает неопределенное поведение .

0 голосов
/ 01 июля 2019

Быстрый ответ

Они отличаются, потому что в вашем первом примере int *p=0; вы объявляете p как указатель, а затем устанавливаете его так, чтобы он указывал на адрес 0x0.Этот пример из одной строки эквивалентен этим двум строкам кода int *p; p=0;

Во втором примере int *p; *p=0; вы объявляете p в первой строке, но он не инициализируется ... поэтому p указывает куда-тоне определено.Во второй строке вы идете по адресу в этом неопределенном месте и пытаетесь установить значение по этому адресу равным 0.

Вы можете увидеть разницу между этим примером и эквивалентным 2-строчным примером ранее, потому чтоодин использует p=0;, а другой - *p=0;

Пример

Поэтому, прежде чем пытаться получить доступ к * p, вы хотите определить, куда указывает p.Предположим, вы знаете, что адрес целого числа, на которое хотите указать p, равен 0x76543210.Давайте посмотрим на значения в памяти до запуска кода:

//  Dummy Memory Dump
//   Offset:      0        4        8        C
//  (0x76543200): 00000000 00000000 00000000 00000000
//  (0x76543210): 00000000 00000000 00000000 00000000
//  (0x76543220): 00000000 00000000 00000000 00000000

Я изменил ваш *p=0; на *p=5; в этом примере, чтобы мы могли видеть изменения в памяти.Итак, давайте предположим, что мы запустили следующие строки кода:

int *p;                // Declare a pointer p
p = (int*) 0x76543210; // Set p to point at the address 0x76543210 cast to (int*)
*p = 5;                // Go to the address that p is pointing to, and set the value to 5

Теперь, если мы вернемся назад и посмотрим, что у нас в памяти, мы должны увидеть, что мы установили 5 на адрес, на который указывал p:

//  Dummy Memory Dump
//   Offset:      0        4        8        C
//  (0x76543200): 00000000 00000000 00000000 00000000
//  (0x76543210): 00000005 00000000 00000000 00000000
//  (0x76543220): 00000000 00000000 00000000 00000000

Объяснение

Как правило, объявление разбивается на следующие компоненты:

[type] [name];

И, возможно, встроенная инициализация может быть нарушена следующим образом:

[type] [name] = [value];

В этом примере:

int *p=5;
  • [type] = (int *)
  • [name] = p
  • [значение] = 5

Это может сбивать с толку, поскольку * в объявлении прикреплено к имени.Символ * в объявлении означает, что p является указателем.Но имя указателя по-прежнему просто p.

Итак, теперь, когда мы знаем компоненты, мы можем сказать, что

int *p=5;

эквивалентно

int *p;
p=5;

Теперь, чтобы добавить к путанице, есть разница между * при объявлении указателя и при обращении к адресу указателя.Когда вы используете * во время доступа, он использует значение в p как адрес, к которому будет осуществляться доступ.В этом примере:

int *p; // This declares a pointer p with no value
*p=5;   // This line wants to go to the address that p is pointing to and set it to 5
        // At this point, p is undefined because p was just declared and hasn't been set
        // So it is trying to go to an unknown location to set the value 5.
0 голосов
/ 25 июня 2019
int *p = 0;

Это создает целочисленный указатель, который будет указывать на адрес ноль. Так что это нулевой указатель. Нулевой указатель просто означает, что указатель не указывает ни на что, или в некоторых языках означает, что неизвестно, на что он указывает. Но так как это нулевой указатель, вы знаете это, код знает это, так что никаких проблем.

Неинициализированная переменная-указатель обычно называется висячим указателем просто потому, что вы не знаете, куда она указывает. Выполнение

  int *p;
    *p=0;

имеет непредсказуемые эффекты.

0 голосов
/ 24 июня 2019

Разницы нет. Всего одна точка.

int *p = 0;

- пример объявления клубов с инициализацией

пока

int *p;
*p = 0;

является примером первого объявления, а затем инициализации.

Как это

int a = 0;

совпадает с

int a;
a = 0;
0 голосов
/ 24 июня 2019

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

Таким образом, в общем случае эти два фрагмента кода имеют одинаковый эффект.

int *p = 0;

и

int *p;
p = 0;

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

В этом операторе

*p=0;

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

int *p;
*p=0;

Как сам указательне был инициализирован, то имеет какое-то неопределенное значение, а оператор выражения с выражением присваивания имеет неопределенное поведение.

Рассмотрим следующий фрагмент кода

int x;
int *p;

p = &x; // pointer assigment
*p = 0; // object assignment pointed to by the pointer

Использование typedef для типа указателя поможетчтобы избежать путаницы между назначением указателя и назначением объектаect указывает на указатель

Например,

typedef int * Pointer;

Pointer p;
p = 0;

Таким образом, в объявлении знак '*' используется для объявления указателя.

В выражении знак'*' означает унарный оператор, обозначающий косвенность.Результатом применения этого оператора к указателю является lvalue, обозначающее объект.

...