C ++ указатели на оригинальный объект и указатели на скопированный объект - PullRequest
0 голосов
/ 06 ноября 2011

Я хочу кое-что прояснить в отношении указателей, поскольку я думаю, что это сложно в C ++.Когда я объявляю указатель и передаю его функции, например:

//just an example
void showInt(int* numbers)
{
    numbers += 3;
}

int main()
{
    int* a = 10;
    showInt(a);

    return 0;
}

Когда я передаю переменную a функции, я фактически передаю ей исходную переменную?Или он создает копию переменной, а затем передает ее функции?

Как узнать, передаю ли мне копию или настоящую / оригинальную?

Ответы [ 4 ]

3 голосов
/ 06 ноября 2011

Вы не можете сделать

int* a = 10

Это не имеет смысла, и ваш компилятор сообщит вам об ошибке.

Когда вы сделаете это:

//just an example
void showInt(int* numbers)
{
    numbers += 3;
}

int main()
{
   int a = 10;
   showInt(&a);

   return 0;
}

Там вы передаете адрес a , а затем добавляете 3 к этому адресу, поэтому ничего не меняется.

Если вы измените:

numbers += 3;

на

*numbers += 3;

, тогда вы измените значение переменной a .

Для этого есть еще один способ: просто измените

void showInt(int* numbers)

to

void showInt(int& numbers)

Итак, вы можете использовать

showInt(a);

, и вы измените значение a , и копия не будет создана.

0 голосов
/ 06 ноября 2011

С указателем вы передаете копию указателя в качестве параметра, указатель указывает на исходную переменную. Поэтому, если вы разыменуете указатель, у вас будет исходное значение. Помните, что указатель - это в основном адрес чего-то, int * - это адрес целого числа. Если вы изменяете значение указателя, вы меняете адрес, что означает, что указатель будет указывать на что-то другое, если вы измените значение того, на что указывает указатель, вы измените значение, указывая на тот же объект.

void ptrfunc(int *a)
{
  *a = 10;
}

void reffunc(int &a)
{
  a = 50;
}

void valfunc(int a)
{
  a = 30;
}

int main()
{
  int b = 20;
  // Pass the point to b to the function, will alter the original.
  ptrfunc(&b);
  cout << b << endl;
  // Pass a reference to b to the function, will alter the original.
  ptrfunc(b);
  cout << b << endl;
  // Pass the value of b to the function, will not alter the original.
  valfunc(b);
  cout << b << endl;
  return 0;
}

Эта функция напечатает значение 10 в первом цикле и 50 в следующем, так как значение функции, на которую указывают и на которую ссылаются, изменяется в функции. Valfunc изменяет значение копии b и, следовательно, не оригинала.

0 голосов
/ 06 ноября 2011

Давайте рассмотрим ваш пример:

void showInt(int* numbers) // (1)
{
    numbers += 3;          // (2)
}

int main()
{
   int* a = 10;            // (3)   
   showInt(a);             // (4)
   return 0;
}

(1) numbers переменная является копией переменной, переданной этой функции;

(2) из-за (1) все изменения, сделанные здесь numbers, останутся только в этой функции; значение исходной переменной, переданной этой функции, останется прежним! Но обратите внимание на следующее: вы не можете изменить значение указателя (a), переданного функции, но с помощью копии этого указателя (numbers) вы можете изменить значение, на которое она указывает! Это главный трюк - если у вас есть адрес внутри функции, вы можете писать по этому адресу, и эти изменения остаются после возврата функции. Запись по адресу включает разыменование указателя, но вы, к счастью, этого не сделали - я говорю «к счастью», потому что переданный вами адрес был просто произвольным адресом в памяти (10). Если вы попытаетесь написать по адресу 10, ваша программа, скорее всего, вылетит.

(3) Вы объявили a типа «указатель на int», поэтому предполагается, что это значение является адресом некоторого объекта int. Вы допустили здесь опасную ошибку, так как предположили, что 10 был действительным адресом некоторого int, но вы на самом деле не знаете, что находится по этому адресу.

(4) Вы передаете копию переменной a в функцию. Функция сохраняет значение в переменной numbers и увеличивает его. Таким образом, numbers теперь содержит адрес 13 (а не адрес некоторой целочисленной переменной, значение которой равно 13!). a остается тем же, хотя и имеет то же значение, 10.

Вы, вероятно, хотели что-то вроде этого:

void showInt(int* numbers)
{
   *numbers += 3;           // (1)
}

int main()
{
   int a = 10;              // (2)
   showInt(&a);             // (3) 
   return 0;
}
Функция

(1) изменяет значение по адресу, который хранится в numbers. Указатель разыменовывается.

(2) У нас должен быть действительный адрес некоторой переменной int, а не просто случайно выбранный адрес (например, 10). Поэтому мы объявляем переменную типа int, a. Его адрес &a.

(3) Адрес a передается в showInt через переменную numbers, и теперь функция может записывать в этот адрес (который теперь является действительным адресом объекта int - a) и таким образом изменять значение a. Когда функция возвращается, a имеет значение 13. Обратите внимание, что адрес a здесь не изменяется ни в какой момент времени.

0 голосов
/ 06 ноября 2011

a относится к указателю, который указывает на значение 10.Если вы хотите передать значение 10 методу, используйте *a.В таком виде вы передаете ячейку памяти методу top.В этом методе вы увеличиваете его на 3.

Нет «копирования» и «оригинала» как таковых: в main(), 10 существует в памяти, и a содержит указатель на него.В другом методе [без имени?] Он принимает int - не указатель - поэтому, если вы измените его, вы не измените цель указателя, просто параметр (который действует как локальная переменная).

Надеюсь, это каким-то образом поможет.

[Редактировать: вы изменили метод top, чтобы теперь он принимал параметр int* вместо int.Это имеет больше смысла ... позвольте мне пересмотреть мой ответ]

Сначала я хочу уточнить, что в вашем коде не копируются никакие объекты (на самом деле в коде вообще нет реальных объектов, только int в памяти иуказатель передан и возможно изменен).

showInt теперь правильно принимает указатель.Он увеличивает этот указатель, в данном случае указывая на что-то неопределенное / недействительное.Если вы сделаете numbers += 3, то числа будут просто указывать на что-то на 3 байта от того места, на которое они изначально указывали, и это все, что изменилось.И это только в рамках этого метода.

Если вы сделали: *numbers += 3, вы бы увеличили цель указателя, что означает замену 10 на 13.Это будет действовать везде, где осуществляется доступ к этой памяти, например, в main.

. Могу ли я предложить вам ознакомиться с преимуществами указателей против ссылок (например, int&) -с приличной статьей у вас должен быть довольно приличный момент "ага":)

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