значения неинициализированных указателей в C - PullRequest
0 голосов
/ 21 марта 2019

предположим, у нас есть следующие объявления в C:

double d[25], * p;
int * t;
char * c;

Как мы можем объяснить следующие результаты printf ()?

printf("d : %x\t",d);
printf("p : %x\t",p);
printf("t : %x\t",t);
printf("c : %x\t",c);

, которые печатают строку:

d : 62fd30    p : 1    t : 0    c : 39    

Мы можем ясно видеть адрес памяти d, но и p, t и c не похожи на адреса.Раньше я думал, что неинициализированный указатель принимает значение Null после его объявления.Я ошибся?как мы можем объяснить эти результаты?

Ответы [ 3 ]

5 голосов
/ 21 марта 2019

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

Кроме того, простое чтение значения неинициализированного указателя не является автоматически UB (в C), а разыменование неинициализированнымуказатель определенно равен.

Однако, как уже упоминалось в одном комментарии, вам нужно использовать "%p" для печати указателей (технически они также должны быть приведены к void *).Несоответствие printf спецификатора формата и типа аргумента do приводит к UB.

3 голосов
/ 21 марта 2019

Раньше я думал, что неинициализированный указатель принимает Null значение после его объявления. Я не прав?

Да , ваше предположение неверно. Неинициализированный указатель , объявленный с помощью автоматического хранения , всегда содержит данные мусора или ненужные данные, т. Е. Недопустимый адрес, поэтому лучше сначала инициализировать с помощью NULL при объявлении. Например,

double *d = NULL;
/* some processing */
if(d == NULL) {
  /* @TODO error handling. Not allowed to de-reference NULL pointer */
}

Здесь

double d[25];
printf("d : %x\t",d);

d - это массив 25 двойного & имени самого массива с адресом , в то время как печать d с использованием %x вызывает неопределенное поведение , даже ваш компилятор может иметь предупредил вас, как это

main.c: 5: 19: предупреждение: формат указывает тип 'unsigned int', но аргумент имеет тип 'double *' [-Wformat]

Но вы, похоже, игнорируете предупреждения компилятора, не следует. Всегда компилируйте ваш код с минимальными флагами, такими как -Wall. Например, 1037 *

gcc -Wall -Werror -Wpedantic test.c

Чтобы напечатать имя массива, используйте спецификатор формата %p. например,

double d[25];
printf("Array d : %p\t",(void*)d);

Аналогично указателю int, указателю t и char, указателю c, используйте спецификатор формата %p вместо %x. Также не держите в коде неинициализированный указатель.

int * t; /* initialized with valid address else 
            dereferencing uninitialized pointer causes UB */
printf("t : %p\n",(void*)t);
3 голосов
/ 21 марта 2019

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

int * t = NULL;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...