Указатели в С++, передача по указателю и по ссылке
#include <iostream>
#include "Employe.h"
using namespace std;
int main()
{
int balance=333; // обычная переменная для числа
int *ukazatel; // указатель для int чисел
int newvalue; // обычная переменная для числа
ukazatel = &balance; // здесь мы в указатель помещаем АДРЕС переменной balance где
//начинается int значение
newvalue = *ukazatel; // в новую переменную записываем значение int которое
//начинается с АДРЕСА записанного в переменной ukazatel
// * означает, что мы берем значение из указателя
// если * не указать, то получим ошибку error: invalid conversion from 'int*' to 'int' [-fpermissive]|
cout << newvalue; // вывод 333
cout << ukazatel; // 0х28ff02 -> ВЫВОД АДРЕСА памяти переменной balance
//где начинается число 333
cout << *ukazatel; // 333 -> ВЫВОД ЗНАЧЕНИЯ из АДРЕСА памяти переменной balance
}
В выражении ukazatel = &balance; звездочку перед указателем ставить не надо, ведь звездочка указывается только при инициализации этой переменной, а когда в нее записываем адрес * уже не нужна. Звездочка будет только нужна, когда мы захотим ВЫТАЩИТЬ значение из этого адреса и присвоить другой int переменной или чтобы записать новое значение по этому адресу.
Еще один небольшой пример:
#include <iostream>
#include "Employe.h"
using namespace std;
int main()
{
int balance; // обычная переменная для числа
int *ukazatel; // указатель для int чисел
// указатели обязательно нужно инициализировать (в отличии от ссылок, смотри ниже пример)
// в указатель сохраняем адрес с которого начинает переменная balance
ukazatel = &balance;
// в эту память записыаем число
// если не указать *, то будет ошибка, так как мы в адрес памяти пытаемся записать int значение
*ukazatel = 3;
cout << balance; // 3
}
Рассмотрим еще пример, только еще раз с объяснениями:
int main () {
int balance;
int *balptr; // создаем указатель с помощью *
int value;
balance = 3200;
balptr = &balance; // в переменную balptr помещается АДРЕС (внутренней памяти компа) переменной balance
value = *balptr; // унарный оператор * ссылается на ЗНАЧЕНИЕ переменной, заданной операндом balptr, то есть переменная value получает значение по адресу взятому в balptr
cout << "Баланс равен: " << value << '\n'; // 3200
}
К сожалению, знак умножения (*) и оператор со значением “по адресу” обозначаются одинаковыми символами “звездочка”, что иногда сбивает с толку новичков в языке C++. Эти операции никак не связаны одна с другой. Имейте в виду, что операторы '*' и '&' имеют более высокий приоритет, чем любой из арифметических операторов, за исключением унарного минуса, приоритет которого такой же, как у операторов, применяемых для работы с указателями.
Операции, выполняемые с помощью указателей, часто называют операциями непрямого доступа, поскольку мы косвенно получаем доступ к переменной посредством некоторой другой переменной.
Присваивание значений с помощью указателей
*p = 100; // число 100 присваивается области памяти, по адресу который расположен в p
Пример 1:
int *p, num;
p = # // в р - адрес по которому расположена переменная num
*p = 200; // по этому адресу записываем числр 200, которое можно взять используя переменную num
cout << num; // 200
(*p)--;
(*p)--;
cout << num; // 198
Пример 2:
double x, y;
double *p;
x = 123.2;
p = &x;
y = *p;
cout << y; //123.2
(*p)++;
cout << x; //124.2
cout << y; //123.2
Указатели и функции
Простой пример который передает в функцию адрес переменной а, и в функции через адрес присваеваем этой переменной новое значение (by pointer - передача по указателю):
#include <iostream>
#include "Employe.h"
using namespace std;
// так как передается адрес в функцию,
// значит нам нужно объявить указатель *x который и примет этот адрес
void f(int *x)
{
// записываем число по адресу переменной a
*x = 444;
// если тут не указать *, то получим ошибку
// error: invalid conversion from 'int' to 'int*' [-fpermissive]|
// *x означает, что мы записываем значение через этот указатель,
// без звездочки х нам выведет адрес переменной a
}
int main()
{
int a;
// передаем в функцию адрес int переменной а
f (&a);
cout << a; // 444
}
Если добавить в функцию *x = *x+1; то мы увеличим значение на 1 и программа выдаст 445.
Можно записать коротко (*x)++;
Скобки нужны для того, чтобы выставить приоритет, без скобок, ++ сработает раньше к иксу (перейдет по адресу выше) и только потом звездочка.
Передаче по ссылке (by reference)
Этот же пример можно записать иначе:
#include <iostream>
#include "Employe.h"
using namespace std;
void f(int &x) // сюда придет ссылка на передаваемую переменную a
{
x = 444; // иск это как бы псевдоним переменной а, что икс, что и а, ссылаются на одну и ту же область памяти
}
int main()
{
int a;
f (a);
cout << a; // 444
}
Этот код полность идентичен предыдущем, но скомпилируется только в С++, на С он не будет работать.
Указатели и массивы
Указатель на массив устанавливается по умолчанию на первый элемент массива.
int *p, num[10];
p = num; // р указывает на элемент массива num[0]
cout << p;
p = &num[3]; // здесь ставим знак амперсант и указываем номер элемента массива, адрес которого мы хотим получить
cout << p;
Изменяя указатели, можно гулять по переменным или по массиву:
int *i, j;
double *f, g[10];
int x;
j = 22;
i = &j;
f = g;
for(x=0; x<10; x++)
cout << i+x << ' ' << f+x << '\n'; // к int будет добавляться 4 байта (в 32-раздрядной среде) а к double 8
Гулять по массивам можно через арифметику указателей. Компилятор С++ такую программу сделает эффективней и быстрее, чем если бы вы пользовались массивами, обычным индексным способом. Именно быстродействие заставляет использовать указатели в массивах.
Пример, программа которая из строки выделяет слова, разделенные пробелами:
char str[80];
char token[80];
char *p, *q; // делаем указатели на два массива, они позволят перемещаться по элементам строкового массива
cout << "Введите предложение:"; gets(str);
p = str; //ставим указатель р на массив, чтобы "гулять" по массиву БЫСТРЕЕ
// Считываем лексему из строки,
while(*p) {
q = token; // Устанавливаем q для указания на начало массива token
/* Считываем символы до тех пор пока не встретится либо пробел, либо нулевой символ (признак завершения строки)
while (*p!=' ' && *p!='\0' ) {
*q = *p;
q++; p++; // переходим на следующий элемент массива
}
if (*p) p++; // Перемещаемся за пробел. Если мы в середине строки, то просто идем на следующую букву,
//если в конце, то то перехода не будет, чтобы следующая иттерация while смогла остановится встретив \0
// иначе мы выйдем за область массива и могут возникнуть непредвиденные ситуации
*q = '\0'; // Завершаем лексему нулевым символом
cout << token << '\n';
}
Более удобный синтаксис указателя на массив
char str[20] = "I love you";
char *p;
int i;
p = str;
for(i=0; p[i]; i++) p[i] = toupper(p[i]);
cout << p; // I LOVE YOU
cout << str; // I LOVE YOU
Еще альтернативная запись указателя на массив
Следующая инструкция, при выполнении которой элементу num [ 3 ] присваивается значение 100:
*(num+3) = 100;
Запись и чтения массива с помощью указателей
#include <iostream>
using namespace std;
int main () {
int *start, *endd;
int arr[5];
start = arr; // ставим указатель на начало массива
endd = &arr[4]; // ставим указатель в конец массива
while (start <= endd) {
cout << "input:";
cin >> *start; // записываем число в массив (УКАЗАТЕЛЬ СО ЗВЕЗДОЧКОЙ)
*start++; // следующий элемент массива
}
start = arr;//восставливаем указатель
while (start <= endd) {
cout << *start << " "; // читаем элемент массива
*start++;
}
}
Оставить свой ответ: