Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/9: Рейтинг темы: голосов - 9, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
1

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

19.12.2012, 03:27. Показов 1851. Ответов 18
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Разбираю указатели, слегка запнулся на одном месте.

У меня есть функция:
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 указывал именно на следующий элемент в массиве, а не в памяти? И гарантированно ли он будет указывать?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.12.2012, 03:27
Ответы с готовыми решениями:

не совсем понимаю код *указатели
изучаю указатели, столкнулся с кодом не совсем могу понять что происходит в функции *g_s, особенно...

Правильно ли я понимаю ссылки и указатели. Работу с ними. Я сам прокомментировал код. Скажите правильно или нет.
#pragma once namespace Casper { class Cat { private: unsigned int age; float weight;

Указатели и указатели на указатели, а также типы данных
Недавно начал изучать Си, перешел с Delphi. Много непонятного и пока процесс идет медленно....

Через указатели на указатели посчитать сумму двух чисел и записать в третье
1. Через указатели на указатели посчитать сумму двух чисел и записать в третье. 2. Написать...

18
3 / 3 / 1
Регистрация: 25.06.2012
Сообщений: 13
19.12.2012, 03:35 2
Цитата Сообщение от extremist38 Посмотреть сообщение
И я не могу понять, почему это работает.
Судя по книжке, которую я читаю, & - взятие адреса. То есть получается, я передаю в функцию адрес. А внутри её использую как обычную переменную. При попытке написать что-то в стиле "*x *= 2;" компилятор пишет, что неверно. Почему так?
на сколько я знаю, знак амперсанда используется не только для взятия адреса, а и для работы с ссылочными типами данных.

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

Добавлено через 41 секунду
Цитата Сообщение от extremist38 Посмотреть сообщение
p = &arr;
Взятие адреса указателя на нулевой элемент массива.
0
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 03:51  [ТС] 5
Цитата Сообщение от 0x10 Посмотреть сообщение
Функция, принимающая целочисленный аргумент по ссылке.
То есть получается, что я не ссылку принимаю? Или всё же ссылку?
0
3 / 3 / 1
Регистрация: 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)
при вызове

описал на сколько я себе это представляю.
1
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 секунду

Взятие адреса указателя на нулевой элемент массива.
Всё же, всегда ли элементы массива идут друг за дружкой? Что происходит, если невозможно выделить массив одним куском?
0
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
19.12.2012, 04:14 8
Цитата Сообщение от extremist38 Посмотреть сообщение
Я прекрасно понимаю, как работает второй вариант. Только с первым непонятки. Если я передаю значение, почему тогда переменная изменяется? Или я передаю значение вместе с ссылкой? (то есть саму переменную??...)
Создается ссылка, которая инициализируется объектом.

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

Цитата Сообщение от extremist38 Посмотреть сообщение
Что происходит, если невозможно выделить массив одним куском?
Предполагаю, что происходит пичалька. (объяснил, да? =) )
2
0 / 0 / 0
Регистрация: 19.12.2012
Сообщений: 6
19.12.2012, 04:17  [ТС] 9
Цитата Сообщение от 0x10 Посмотреть сообщение
Предполагаю, что происходит пичалька. (объяснил, да? =) )
Понятно, что примерно выходит )
Следующий вопрос будет: как можно предусмотреть такую ситуацию и предотвратить печальку? )
0
~ Эврика! ~
1256 / 1005 / 74
Регистрация: 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 или прибить программу, если она облажалась с высвобождением.
1
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
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
0
OhMyGodSoLong
19.12.2012, 09:16
  #12

Не по теме:

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

0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
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 - указатель и присвоено будет значение указателя указателю же
.
1
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;
}
являться грамотно написанной и работающей? Или это всё же лучше делать через указатели?
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
19.12.2012, 10:32 15
Цитата Сообщение от extremist38 Посмотреть сообщение
являться правильно написанной и гарантированно работающей? Или это всё же лучше делать через указатели?
Для этого их и придумали - чтобы не возится с указателями, как в Си, да и код выглядит понятнее
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
19.12.2012, 11:31 16
Цитата Сообщение от taras atavin Посмотреть сообщение
char s[16];
- массив.
Цитата Сообщение от ValeryS Посмотреть сообщение
нет в С массивов
Движенья нет, сказал мудрец брадатый.
Другой смолчал и стал пред ним ходить....
прежде чем продолжить этот спор(который достоин отдельной темы)
необходимо договорится, что такое массив
набор сущностный ( тогда есть)
другая сущность (тогда нету)
0
836 / 343 / 67
Регистрация: 20.11.2012
Сообщений: 795
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 .
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
19.12.2012, 11:37 18
Цитата Сообщение от extremist38 Посмотреть сообщение
Будет ли реализация через ссылку
да будет реализована через ссылку
вопрос в том как в конкретном компиляторе реализована ссылка о чем и говорил
taras atavin,
будь то
Цитата Сообщение от taras atavin Посмотреть сообщение
как неявно разыменуемый при каждом обращении к нему указатель.
или
Цитата Сообщение от taras atavin Посмотреть сообщение
может быть реализована дублированием адреса в таблице переменных компилятора
или еще как
тебя это не должно волновать
в любом случае ты получишь корректный результат
1
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
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 Посмотреть сообщение
необходимо договорится, что такое массив
Массив есть составное данное, состоящее из однотипных элементов, каждый из которых адресуется по имени самого массива и уникальному индексу, или имени самого массива и уникальной комбинации индексов.
Где хоть слово о том, что это составное данное должно адресоваться не только по частям, но и целиком?
1
19.12.2012, 18:05
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.12.2012, 18:05
Помогаю со студенческими работами здесь

Почему Лафоре использует указатели на указатели, вместо обмена значениями указателей?
Доброго времени суток! Задался теоретическим вопросом. Читал пример из книги Лафоре...

Указатели на указатели с числами. Почему можно присвоить число в 4-ый элемент, если массив из 2 элементов?
Есть массив int **mas; mas=new int*; // выделил место под пять строк, верно ? mas=new int;//...

Есть три переменные. Используя указатели на указатели, поменять значение максимальной и минимальной переменной
Мой код. #include &lt;iostream&gt; #include &lt;stdlib.h&gt; #include&lt;iomanip&gt; using namespace std; ...

Зачем нужны все эти указатели (или не указатели)
Зачем надо DWORD, HANDLE, LPVOID?


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

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru