C ++: что не так с int * j; * J = 50; ? - PullRequest
0 голосов
/ 31 июля 2011

Это вопрос новичка в C ++.Я понятия не имею, почему это происходит ...

Я обнаружил, что если я напишу этот код.Это полностью верно.

Code1

int *j;    //create an pointer j
*j = 50;   //assign 50 to the *j, meaning value pointed by address 50 is xxx

Однако, когда я хочу попытаться сделать это более простым.Компилятор выдаёт мне это сообщение об ошибке.

Code2

int *j = 50; //i guess this should be the same with Code1...

Ошибка компиляции

error: invalid conversion from ‘int*’ to ‘int’

Так почему же так?

Ответы [ 6 ]

13 голосов
/ 31 июля 2011

В синтаксисе Си есть некоторая двусмысленность.

int *j = 50;

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

int *j;
j = 50;

На самом деле то, что вы делаете в первом фрагменте кода, опаснопотому что вы еще не выделили памяти для j, прежде чем присваивать ей значение.Вам нужно сделать память для этого примерно так:

в C:

int *j = (int*) malloc(sizeof(int));
*j = 50;

в C ++

int *j = new int;
*j = 50;

Или наведите указатель на другой блок памяти, который уже действителен:

int k;
int *j = &k;
*j = 50;
printf("%d", k); // 50

Редактировать: Стоит отметить, что двусмысленность связана с символом '*'.В объявлении int *j; * j означает «указатель с именем j».Но когда вы используете его во второй строке «* j = 50», * становится символом разыменования, что означает «значение по адресу j».

2 голосов
/ 31 июля 2011

После того, как вы объявите int *j;, в стеке (в данном случае) выделяется пространство типа int *, которое имеет некоторый адрес addr_stk и с содержимым, которое мы не знаем, т.е. мусор.

 +--------+          +--------+
 |  ???   |----+     |  xxx   |     trying to store 50 here
 +--------+    |     +--------+
 |   j    |    |     |        |
 +--------+    |     +--------+
 |addr_stk|    +---->|  ???   |     have no permission to access this location
 +--------+          +--------+

Когда вы используете *j = 50;, содержимое переменной-указателя (объекта) j используется в качестве адреса для хранения значения 50. Поэтому вы пытаетесь сохранить значение 50 в некотором адресном местоположении, которое имеет значение адреса мусора, что означает, что оно может быть где угодно. Всякий раз, когда вы пытаетесь получить доступ к тем ячейкам памяти, которые вам не выделены, вы не сможете сохранить или получить доступ к этой папке, операционная система остановит вас и выдаст ошибку.

Сначала нужно инициализировать переменную-указатель j с некоторым допустимым адресом. Это можно сделать, сначала выделив часть памяти с помощью malloc, а затем используя ее. Или инициализировать j адресом какой-либо другой переменной (локальной или глобальной). как

int *j, i;
j = &i;
*j = 50;

или

int *j;
j = malloc (sizeof (int));
*j = 50;

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

Важно то, что когда вы выделяете память с помощью malloc, вы всегда должны освобождать память. Это хорошая привычка, иначе в больших программах это приведет к утечкам памяти.

2 голосов
/ 31 июля 2011

В целом они имеют разные значения.

Первый объявляет указатель и устанавливает int, на который указывает адрес в настоящее время в j, на 50.Без другого контекста это уже плохо;адрес в j не инициализирован, и вы, скорее всего, вызовете ошибку сегментации, записав значение в произвольное место в памяти.

Второй фрагмент кода объявляет указатель и определяет сохраненный адресв нем до 50. Если вы отделите его, это будет похоже на запись (обратите внимание на отсутствие звездочки во втором утверждении):

int *j; j = 50;
1 голос
/ 31 июля 2011

* является частью типа переменной, а не ее имени .

int* j означает «У меня есть переменная с именем j, которая является указателем наint ".

int* j = 50 (код 2) означает" У меня есть переменная с именем j, которая является указателем на int и которая должна быть инициализирована значением 50 ".Это не разрешено;указатели не могут быть инициализированы с целочисленным значением, отличным от 0, без явного приведения. Явное приведение в порядок, чтобы обойти это, очень, очень плохая идея, если вы не знаете, что делаете, и если вы задаете эти вопросы, тогда совершенно точно, что вы не знаете, что делаетедостаточно хорошо, чтобы попробовать .

Вы должны быть в состоянии понять это из сообщения об ошибке.Недопустимое преобразование - это просто: ваш код пытается преобразовать один тип в другой (посредством присваивания), и это недопустимо.То, что вы назначаете, не соответствует типу того, что вы назначаете.Он также сообщает, какие типы используются.

*j = 50 (вторая строка в коде 1) означает «записать значение 50 в месте, на которое указывает j».Это плохо, потому что j еще не инициализирован. Это называется "неопределенным поведением", и это именно так - оно может давать сбой любым количеством способов, или нет, но это всегда неправильно, даже если кажется, что оно работает. Но оно скомпилируется, и большинствокомпиляторы даже не попытаются предупредить вас о подобных вещах, если вы не спросите их о действительно высоких уровнях предупреждения - если вообще.

1 голос
/ 31 июля 2011

Оба ваших примера неверны.

Первый:

int *j;
*j = 50;

сохраняет 50 по адресу j.Тем не менее, вы никогда не инициализировали j, поэтому вы просто храните по неизвестному адресу.Иногда это будет «успешно», иногда это приведет к аварийному завершению работы вашего приложения, а иногда просто повредит состояние вашего приложения, не вызывая ошибки;это никогда не то, что вы на самом деле хотите сделать.

Второе:

int *j = 50;

пытается инициализировать переменную типа "pointer-to-int" со значением типа "int",что является ошибкой.

Вместо этого вы хотите сделать что-то вроде:

int i = 50;
int *j = &i; // j is now a pointer to i.

или:

int i;
int *j;
j = &i;  // note: no * before j.  j now contains a valid address.
*j = 50; // store 50 to the address j.  After this, i == 50.
0 голосов
/ 31 июля 2011
int *j = 50

Фактически равно

int *j;
j = 50;

Поскольку присвоение при инициализации присваивает переменную itsel, несмотря ни на что.

В обоих случаях это очень плохая идея, потому что указатель недействителен.

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