Указатели в С++, передача по указателю и по ссылке

Рассмотрим самый простой пример с указателем:

#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; // в р - адрес по которому расположена переменная 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++;
    }
}

 



Оставить свой ответ:

Имя:*
E-Mail:
Вопрос:
Skolko buдет пять пдюс сeмь?
Ответ:*
QQpedia21.ru - cамые интересные вопросы