Форум программистов, компьютерный форум CyberForum.ru

Указатели. Не понимаю - C++

Восстановить пароль Регистрация
 
extremist38
 Аватар для extremist38
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 03:27     Указатели. Не понимаю #1
Разбираю указатели, слегка запнулся на одном месте.

У меня есть функция:
C++
1
2
3
4
void Dit(int &x)
{
    x *= 2;
}
Использую я в программе это так:
C++
1
Dit(x);
И я не могу понять, почему это работает.
Судя по книжке, которую я читаю, & - взятие адреса. То есть получается, я передаю в функцию адрес. А внутри её использую как обычную переменную. При попытке написать что-то в стиле "*x *= 2;" компилятор пишет, что неверно. Почему так?

Добавлено через 20 минут
Также есть небольшая ситуация.
Возможно использования массивов через указатели, то есть.

C++
1
2
3
int *p;
int arr[100500];
p = &arr;
При этом, если делать p++, то говорится, что р будет указывать на следующий элемент в массиве. Но ведь элементы массива в оперативной памяти разбросаны по участкам и не обязательно идут друг за дружкой (особенно если массив весит очень много). Насколько я знаю, p++ к указателю даёт результат следующей ячейки в памяти. И у меня возникает вопрос: кто следит за тем, чтобы p указывал именно на следующий элемент в массиве, а не в памяти? И гарантированно ли он будет указывать?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
icecreeam
3 / 3 / 0
Регистрация: 25.06.2012
Сообщений: 13
19.12.2012, 03:35     Указатели. Не понимаю #2
Цитата Сообщение от extremist38 Посмотреть сообщение
И я не могу понять, почему это работает.
Судя по книжке, которую я читаю, & - взятие адреса. То есть получается, я передаю в функцию адрес. А внутри её использую как обычную переменную. При попытке написать что-то в стиле "*x *= 2;" компилятор пишет, что неверно. Почему так?
на сколько я знаю, знак амперсанда используется не только для взятия адреса, а и для работы с ссылочными типами данных.

По поводу массивов мне кажется что его элементы не разбросаны и идут друг за другом.
extremist38
 Аватар для extremist38
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 03:46  [ТС]     Указатели. Не понимаю #3
Цитата Сообщение от icecreeam Посмотреть сообщение
на сколько я знаю, знак амперсанда используется не только для взятия адреса, а и для работы с ссылочными типами данных.
Тогда что означает то, что я написал?
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
19.12.2012, 03:48     Указатели. Не понимаю #4
Цитата Сообщение от extremist38 Посмотреть сообщение
void Dit(int &x)
Функция, принимающая целочисленный аргумент по ссылке.

Добавлено через 41 секунду
Цитата Сообщение от extremist38 Посмотреть сообщение
p = &arr;
Взятие адреса указателя на нулевой элемент массива.
extremist38
 Аватар для extremist38
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 03:51  [ТС]     Указатели. Не понимаю #5
Цитата Сообщение от 0x10 Посмотреть сообщение
Функция, принимающая целочисленный аргумент по ссылке.
То есть получается, что я не ссылку принимаю? Или всё же ссылку?
icecreeam
3 / 3 / 0
Регистрация: 25.06.2012
Сообщений: 13
19.12.2012, 03:54     Указатели. Не понимаю #6
C++
1
void Dit(int &x)
в этом случае вы передаете значение по ссылке
C++
1
Dit(x)
при вызове

C++
1
void Dit(int *x)
а в этом вы передаете адрес значения
C++
1
Dit(&x)
при вызове

описал на сколько я себе это представляю.
extremist38
 Аватар для extremist38
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 04:09  [ТС]     Указатели. Не понимаю #7
Кликните здесь для просмотра всего текста
Цитата Сообщение от icecreeam Посмотреть сообщение
C++
1
void Dit(int &x)
в этом случае вы передаете значение по ссылке
C++
1
Dit(x)
при вызове

C++
1
void Dit(int *x)
а в этом вы передаете адрес значения
C++
1
Dit(&x)
при вызове

описал на сколько я себе это представляю.

Я прекрасно понимаю, как работает второй вариант. Только с первым непонятки. Если я передаю значение, почему тогда переменная изменяется? Или я передаю значение вместе с ссылкой? (то есть саму переменную??...)

Добавлено через 2 минуты
Цитата Сообщение от 0x10 Посмотреть сообщение
Функция, принимающая целочисленный аргумент по ссылке.

Добавлено через 41 секунду

Взятие адреса указателя на нулевой элемент массива.
Всё же, всегда ли элементы массива идут друг за дружкой? Что происходит, если невозможно выделить массив одним куском?
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
19.12.2012, 04:14     Указатели. Не понимаю #8
Цитата Сообщение от extremist38 Посмотреть сообщение
Я прекрасно понимаю, как работает второй вариант. Только с первым непонятки. Если я передаю значение, почему тогда переменная изменяется? Или я передаю значение вместе с ссылкой? (то есть саму переменную??...)
Создается ссылка, которая инициализируется объектом.

Цитата Сообщение от extremist38 Посмотреть сообщение
Всё же, всегда ли элементы массива идут друг за дружкой?
А как иначе-то?

Цитата Сообщение от extremist38 Посмотреть сообщение
Что происходит, если невозможно выделить массив одним куском?
Предполагаю, что происходит пичалька. (объяснил, да? =) )
extremist38
 Аватар для extremist38
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 04:17  [ТС]     Указатели. Не понимаю #9
Цитата Сообщение от 0x10 Посмотреть сообщение
Предполагаю, что происходит пичалька. (объяснил, да? =) )
Понятно, что примерно выходит )
Следующий вопрос будет: как можно предусмотреть такую ситуацию и предотвратить печальку? )
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.12.2012, 04:22     Указатели. Не понимаю #10
Цитата Сообщение от extremist38 Посмотреть сообщение
Всё же, всегда ли элементы массива идут друг за дружкой? Что происходит, если невозможно выделить массив одним куском?
1. Всегда.

2. Память не выделяется. А дальше в зависимости от настроек и т. п. возможны три варианта:
a) есть вариант new с дополнительным аргументом, который заставит new просто вернуть NULL;
б) по умолчанию new выбрасывает исключение std::bad_alloc;
в) с помощью set_new_handler() можно установить функцию-обработчик на этот случай, которая должна или повыбрасывать всякий мусор, чтобы new попробовала выделить память ещё раз, или выбросить std::bad_alloc или прибить программу, если она облажалась с высвобождением.
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
19.12.2012, 07:25     Указатели. Не понимаю #11
Цитата Сообщение от extremist38 Посмотреть сообщение
int *p;
int arr[100500];
p = &arr;
ошибка будет
вот такая
1> error C2440: =: невозможно преобразовать 'int (*)[100500]' в 'int *'
все дело в том что arr уже имеет тип int * (указатель)
нет в С массивов как например в Фортране
есть указатель на область памяти где лежит массив
а этим
C++
1
p = &arr
ты берешь указатель на указатель
значит надо писать так если тебе нужна копия указателя
C++
1
2
3
int *p;
int arr[100500];
p = arr;
или так
C++
1
2
3
int *p;
int arr[100500];
p = &arr[0];
что означает взять указатель на первый(нулевой) элемент массива arr
и это равнозначно p = arr
OhMyGodSoLong
19.12.2012, 09:16
  #12

Не по теме:

Цитата Сообщение от ValeryS Посмотреть сообщение
нет в С массивов как например в Фортране
Но схитрить можно:
struct array { int data[100500]; };
Такая штука позволяет передавать массивы по значению.

taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
19.12.2012, 09:55     Указатели. Не понимаю #13
extremist38, указатель есть данное, хранящее адрес подпрограммы, или другого данного. Кратный указатель есть данное, хранящее адрес другого указателя. Указатель, хранящий адрес указателя, хранящего адрес не указателя, называется двойным указателем, указатель, хранящий адрес указателя, хранящего адрес указателя, хранящего адрес указателя, называется тройным указателем и так далее. Сколько указателей нужно использовать, чтоб добраться до не указателя, такова и кратность указателя. Адрес есть значение самого указателя. Адрес есть номер байта в памяти, с которого начинается то, чей это адрес. Например, адрес переменной есть номер байта в памяти, с которого начинается эта переменная. Ссылка есть синоним другой переменной. Можно считать, что ссылка ведёт себя, как неявно разыменуемый при каждом обращении к нему указатель. Но стандарт не гарантирует реализацию ссылок через указатели, вместо этого ссылка может быть реализована дублированием адреса в таблице переменных компилятора, а в готовом коде будет прямая адресация, то есть доступ по адресу в коде программы, а не в данном. Исключение - передаваемые по ссылкам параметры неинлайновых функций и передаваемые по ссылкам операнды неинлайновых перегруженных операторов, в этом случае альтернативные реализации не возможны и ссылка становится синтаксической надстройкой над указателем. Разыменование указателя есть операция доступа не к самому указателю, а к тому, чей адрес он хранит, на низком уровне разыменованию соответствует операция косвенной адресации.

Добавлено через 2 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
нет в С массивов как например в Фортране
C
1
char s[16];
- массив.

Добавлено через 1 минуту
Цитата Сообщение от extremist38 Посмотреть сообщение
& - взятие адреса.
Нет. У тебя этот оператор стоит в декларации, а в этом случае & означает, что следующий идентификатор есть имя ссылки.

Добавлено через 3 минуты
Цитата Сообщение от extremist38 Посмотреть сообщение
Но ведь элементы массива в оперативной памяти разбросаны по участкам и не обязательно идут друг за дружкой
Они не разбрасываются, классический массив - это единый блок, не путай его с массивами-объектами, которые могут быть реализованы на чём угодно, включая списки. Но тогда каждый элемент будет хранить адрес следующего, а оператор ++ для указателя перегружается на копирование адреса следующего элемента из текущего.

Добавлено через 4 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
нет в С массивов как например в Фортране
есть указатель на область памяти где лежит массив
Массивы в c/c++ есть, просто они реализованы на указателях. Но
C++
1
2
3
4
5
6
7
int a[1000];
int *p=a;
std::cout<<sizeof(a); // выведет размер тысячи интов, а не указателя
std::cout<<std::endl;
std::cout<<sizeof(p);// выведет размер самого указателя
std::cout<<std::endl;
std::cout<<sizeof(a[0]);// выведет размер нулевого элемента
, в то же время
C++
1
2
int a[1000];
int *p=a; // здесь a - указатель и присвоено будет значение указателя указателю же
.
extremist38
 Аватар для extremist38
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 10:30  [ТС]     Указатели. Не понимаю #14
Цитата Сообщение от taras atavin Посмотреть сообщение
Но стандарт не гарантирует реализацию ссылок через указатели, вместо этого ссылка может быть реализована дублированием адреса в таблице переменных компилятора, а в готовом коде будет прямая адресация, то есть доступ по адресу в коде программы, а не в данном. Исключение - передаваемые по ссылкам параметры неинлайновых функций и передаваемые по ссылкам операнды неинлайновых перегруженных операторов, в этом случае альтернативные реализации не возможны и ссылка становится синтаксической надстройкой над указателем. Разыменование указателя есть операция доступа не к самому указателю, а к тому, чей адрес он хранит, на низком уровне разыменованию соответствует операция косвенной адресации.
Спасибо за объяснение. Тогда такой вопрос:
Будет ли реализация через ссылку
C++
1
2
3
4
void Dit(int &x)
{
    x *= 2;
}
являться грамотно написанной и работающей? Или это всё же лучше делать через указатели?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11838 / 6817 / 771
Регистрация: 27.09.2012
Сообщений: 16,910
Записей в блоге: 2
Завершенные тесты: 1
19.12.2012, 10:32     Указатели. Не понимаю #15
Цитата Сообщение от extremist38 Посмотреть сообщение
являться правильно написанной и гарантированно работающей? Или это всё же лучше делать через указатели?
Для этого их и придумали - чтобы не возится с указателями, как в Си, да и код выглядит понятнее
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
19.12.2012, 11:31     Указатели. Не понимаю #16
Цитата Сообщение от taras atavin Посмотреть сообщение
char s[16];
- массив.
Цитата Сообщение от ValeryS Посмотреть сообщение
нет в С массивов
Движенья нет, сказал мудрец брадатый.
Другой смолчал и стал пред ним ходить....
прежде чем продолжить этот спор(который достоин отдельной темы)
необходимо договорится, что такое массив
набор сущностный ( тогда есть)
другая сущность (тогда нету)
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
19.12.2012, 11:37     Указатели. Не понимаю #17
Позволю себе копипасту о массивах и указателях (источник - Стив Саммит "Язык Си в вопросах и ответах").

Кликните здесь для просмотра всего текста
2.1: В одном файле у меня есть описание char a[6] а в другом я объявил
extern char *a. Почему это не работает?

О: Декларация extern char *a просто не совпадает с текущим определением.
Тип "Указатель-на-тип-Т" не равен типу "массив-типа-Т". Используйте
extern char a[].

2.2: Но я слышал, что char a[] эквивалентно char *a.

О: Ничего подобного. (То, что Вы слышали, касается формальных параметров
функций, см. вопрос 2.4.) Массивы - не указатели. Объявление массива
"char a[6];" требует определенного места для шести символов, которое
будет известно под именем "a". То есть, существует место под именем
"a", в которое могут быть помещены 6 символов. С другой стороны,
объявление указателя "char *p;" требует места только для самого
указателя. Указатель будет известен под именем "p" и может указывать
на любой символ (или непрерывный массив символов).

Как обычно, лучше один раз увидеть, чем сто раз услышать.
Объявление

char a[] = "hello";
char *p = "world";

породит структуры данных, которые могут быть представлены так:

+---+---+---+---+---+---+
a: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+

+-----+ +---+---+---+---+---+---+
p: | *======> | w | o | r | l | d |\0 |
+-----+ +---+---+---+---+---+---+

Важно понимать, что ссылка типа х[3] порождает разный код в
зависимости от того, массив х или указатель. Если взять приведенную
выше декларацию, то, когда компилятор встречается с выражением а[3],
он генерирует код, позволяющий переместиться к месту под именем "a",
перемещается на три символа вперед и затем читает требуемый символ.
В случае выражения p[3] компилятор генерирует код, чтобы начать с
позиции "p", считывает значение указателя, прибавляет к указателю
3 и, наконец, читает символ, на который указывает указатель. В нашем
примере и a[3] и p[3] оказались равны 'l', но компилятор получает
этот символ по-разному. (Смотри также вопросы 17.19 и 17.20.)

2.3: Тогда что же понимается под "эквивалентностью указателей и массивов"
в С?

О: Большая часть путаницы вокруг указателей в С происходит от
непонимания этого утверждения. "Эквивалентность" указателей и
массивов не позволяет говорить не только об идентичности, но и
взаимозаменяемости.

"Эквивалентность" относится к следующему ключевому определению:

значение [см. вопрос 2.5] типа массив-Т, которое появляется
в выражении, превращается (за исключением трех случаев) в
указатель на первый элемент массива; тип результирующего
указателя - указатель-на-Т.

(Исключение составляют случаи, когда массив оказывается операндом
sizeof, оператора & или инициализатором символьной строки для
массива литер.)

Вследствие этого определения нет заметной разницы в поведении
оператора индексирования [], если его применять к массивам и
указателям. Согласно правилу, приведенному выше, в выражении типа
а[i] ссылка на массив "a" превращается в указатель и дальнейшая
индексация происходит так, как будто существует выражение с
указателем p[i] (хотя доступ к памяти будет различным, как описано в
ответе на вопрос 2.2). В любом случае выражение x[i], где х - массив
или указатель) равно по определению *((x)+(i)).

Смотри: K&R I Разд.5.3 c.93-6; K&R II Разд.5.3 c. 99; H&S
Разд.5.4.1 c. 93; ANSI Разд.3.2.2.1, Разд.3.3.2.1,
Разд.3.3.6 .
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
19.12.2012, 11:37     Указатели. Не понимаю #18
Цитата Сообщение от extremist38 Посмотреть сообщение
Будет ли реализация через ссылку
да будет реализована через ссылку
вопрос в том как в конкретном компиляторе реализована ссылка о чем и говорил
taras atavin,
будь то
Цитата Сообщение от taras atavin Посмотреть сообщение
как неявно разыменуемый при каждом обращении к нему указатель.
или
Цитата Сообщение от taras atavin Посмотреть сообщение
может быть реализована дублированием адреса в таблице переменных компилятора
или еще как
тебя это не должно волновать
в любом случае ты получишь корректный результат
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.12.2012, 18:05     Указатели. Не понимаю
Еще ссылки по теме:

C++ isdigit() не понимаю
C++ Не понимаю задания

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
19.12.2012, 18:05     Указатели. Не понимаю #19
Цитата Сообщение от extremist38 Посмотреть сообщение
Будет ли реализация через ссылку
C++
1
2
3
4
void Dit(int &x)
{
  x *= 2;
}
являться грамотно написанной и работающей? Или это всё же лучше делать через указатели?
Лучше указатель, или нет, может зависеть от различных внешних факторов. Может большинство фактических параметров - динамические данные, или элементы массива, перебираемого адресной арифметикой? Тогда указатель просто удобней синтаксически, так как в случае ссылки его придётся разыменовывать, а при передаче по указателю динамическое данное, или элемент массива, перебираемого адресной арифметикой, можно передавать без дополнительных операций:
C++
1
2
3
4
5
6
7
8
9
10
void Dit(int &x)
{
  x *= 2;
}
int a[1000];
int *p;
for (p=a+999; p>=a; --p)
{
 Dit(*p);
}
, но
C++
1
2
3
4
5
6
7
8
9
10
void Dit(int *x)
{
 *x *= 2;
}
int a[1000];
int *p;
for (p=a+999; p>=a; --p)
{
 Dit(p);
}
. В функции синтаксис указателя использован 1 раз, а таких циклов могут быть тысячи по всей программе. Или ты хочешь поддерживать nullptr? Тогда
C++
1
2
3
4
void Dit(int *x)
{
 if (x)*x *= 2;
}
, но ссылкой это сделать нельзя. А так
C++
1
2
3
4
void Dit(int &x)
{
  x *= 2;
}
вполне валидно.

Добавлено через 3 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
тебя это не должно волновать
в любом случае ты получишь корректный результат
Согласен.

Добавлено через 2 часа 56 минут
Цитата Сообщение от ValeryS Посмотреть сообщение
необходимо договорится, что такое массив
Массив есть составное данное, состоящее из однотипных элементов, каждый из которых адресуется по имени самого массива и уникальному индексу, или имени самого массива и уникальной комбинации индексов.
Где хоть слово о том, что это составное данное должно адресоваться не только по частям, но и целиком?
Yandex
Объявления
19.12.2012, 18:05     Указатели. Не понимаю
Ответ Создать тему
Опции темы

Текущее время: 16:13. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru