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

работа с указателями - C++

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.65
G-Cat
16 / 16 / 1
Регистрация: 15.03.2009
Сообщений: 94
08.05.2009, 06:59     работа с указателями #1
небольшая проблемка, никак не могу разобраться с указателями. Я так понял что создавая массив лучше если сразу сдалешь на него указатель и будешь работать с ним, нежели с самим массивом, тип так экономичнее для ресурсов компа, я ведь правильно понял?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <cstdlib>
#include <iostream>
#include <stdio.h>
 
short int const n = 3;
 
using namespace std;
 
int main(int argc, char *argv[])
{
    int z[n];
    int *a = &z[0];
    
    
    for (short int i = 0; i < n; i++)
        cin >> *a++;
 
    for (short int i = 0; i < n; i++)
        cout << *a++ << endl;
    
    system("PAUSE");
    return EXIT_SUCCESS;
}
при вводе, например: 1, 2, 3, прога выводит: 2, 2293576, 1987762951. Я так понял указатель вышел за пределы массива и 2 - это последний элемент массива, т.к. у меня строгое < 3, а дальше просто изгаляется как хочет. В чем проблема, акромя кривизны моих рук?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.05.2009, 06:59     работа с указателями
Посмотрите здесь:

работа с указателями C++
C++ Работа с указателями
Работа с указателями C++
C++ Работа с указателями
Работа с указателями C++
Работа с указателями C++
Работа с указателями C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
08.05.2009, 07:45     работа с указателями #2
Во первых, имя массива и есть указатель на первый элемент. Во вторых, если так хочешь, то a = z; . И в третьих, *(a++).

Добавлено через 6 минут 44 секунды
Точнее в третьих *(a+i).
G-Cat
16 / 16 / 1
Регистрация: 15.03.2009
Сообщений: 94
08.05.2009, 07:48  [ТС]     работа с указателями #3
т.е. правильно будет выглядеть так?:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <cstdlib>
#include <iostream>
#include <stdio.h>
 
short int const n = 3;
 
using namespace std;
 
int main(int argc, char *argv[])
{
    int z[n];
    int *a = z;
    
    
    for (short int i = 0; i < n; i++)
        cin >> *(a++);
        
    a = z;  
 
    for (short int i = 0; i < n; i++)
        cout << *(a++) << endl;
    
    system("PAUSE");
    return EXIT_SUCCESS;
}
в чем тогда роль знака "&" в выражении *a = &z[0];? Зачем он вообще нужен в указателях?
Почему именно *(a++)? без скобок и так работает ведь. В них вроде же необходимость только если нужно записать какоее нибудь хитрое увеличение указателя, например: *(a+2^n)
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
08.05.2009, 08:32     работа с указателями #4
* имеет больший приоритет, те при *a++ сначала разименовывается указатель, потом инкремент. Далее я поправился, что указатель лучше не изменять, можно запутаться, применяй *(a+i).
Потом z - указатель, z[i] - переменная, &z[i] - ссылка на переменную(аналог указателя).
G-Cat
16 / 16 / 1
Регистрация: 15.03.2009
Сообщений: 94
08.05.2009, 08:42  [ТС]     работа с указателями #5
огромное СПАСИБО!
А как работать с двумерными массивами?...я вот тут накорябал, но не работает:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <cstdlib>
#include <iostream>
#include <stdio.h>
 
short int const n = 3;
short int const m = 4;
 
using namespace std;
 
int main(int argc, char *argv[])
{
        int z[n][m];
        int *a = z;
        
        for (short int i=0; i<n*m; i++)
             cin >> *(a+i);
                
        a = z;  
 
        for (short int j=0; j<n; j++)
        {
             for (short int i=0; i<n; i++)
                  cout << *(a+i) << "\t";
             cout << endl;
        }
        
    system("PAUSE");
    return EXIT_SUCCESS;
}
...или просто надо двумерный массив представлять одномерным и работать уже с ним?
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
08.05.2009, 09:21     работа с указателями #6
Зачем такие сложности?
CyBOSSeR
Эксперт C++
 Аватар для CyBOSSeR
2295 / 1665 / 86
Регистрация: 06.03.2009
Сообщений: 3,675
08.05.2009, 09:24     работа с указателями #7
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
 
const int n = 3;
const int m = 4;
 
using namespace std;
 
int main(int argc, char *argv[])
{
  int z[n][m]; // Имя любого массива (хоть двумерного, хоть 10-мерного) является указателем на первый элемент
 
  for(int i = 0; i < n; ++i)
    for(int j = 0; j < m; ++j)
      cin >> *(*(z + i) + j); //
  
 
  for (int i=0; i< n; i++)
  {
    for (int j=0; j < m; j++)
      cout << *(*(z + i) + j) << "\t";
    cout << endl;
  }
 
  system("PAUSE");
  return EXIT_SUCCESS;
}
Просто запомни что имя массива является указателем на первый элемент, следовательно ты можешь с именем массива обращаться как с указателем.
В случае с двумерным массивом он (массив) грубо говоря является массивом указателей на массивы чисел, т.е.
C++
1
2
3
4
5
int z[3][3] = {
  {1, 2, 3},
  {4, 5, 6},
  {7, 8, 9}
};
можно представить как:
z[1] указатель на {1, 2, 3}
z[2] указатель на {4, 5, 6}
z[3] указатель на {7, 8, 9}

Т.е. z[i] есть указатель на i-ую строку в массиве.

Когда ты пишешь z[i][j] идет обращений к j-му элементу i-ой строки.

Теперь давай разберемся с последовательностью выполнения такого вот оператора: *(*(z + i) + j) (который полностью эквивалентен оператору z[i][j])
1. z + i -получаем указатель типа int** на i-ую строку
2. *(z + i) - получаем строку (которая по сути является одномерным массивом), т.е. указатель типа int*
3. *(z + i) + j - получаем указатель на j-ый элемент i-ой строки, т.е. указатель типа int*
4. *(*(z + i) + j) - собственно получаем сам j-ый элемент i-ой строки, т.е. int.

И еще совет: не пользуйся типами short int, long double без необходимости, т.к. когда ты пишешь
C++
1
short int n = 4;
4 рассматривается как тип int, а следовательно компилятору приходится эту четверку преобразовывать к типу short int, везде где можно используй стандартный типы:
C++
1
bool, char, int, double
Deicider
 Аватар для Deicider
96 / 52 / 1
Регистрация: 18.03.2009
Сообщений: 273
08.05.2009, 09:28     работа с указателями #8
Такой код действительно не будет работать. В одномерном массиве переменная хранит адрес первого элемента. Двумерный массив представляет собой массив указателей, каждый из которых указывает на первый элемент соответствующего одномерного массива. Переменные *(a+i) хранят как значения элементов массивов, так и указатели на их начало, поэтому записывая произвольные значения в *(a+i), ты меняешь значения указателей и они уже не указывают на реальный массив в памяти.
G-Cat
16 / 16 / 1
Регистрация: 15.03.2009
Сообщений: 94
08.05.2009, 10:11  [ТС]     работа с указателями #9
Огромное спасибо всем, очень понятно и по делу проконсультировали. В который раз рад что зарегистрировался здесь =)
Rififi
 Аватар для Rififi
2332 / 1047 / 43
Регистрация: 03.05.2009
Сообщений: 2,656
08.05.2009, 11:21     работа с указателями #10
G-Cat,
... имя массива и есть указатель на первый элемент ...
... Имя любого массива (хоть двумерного, хоть 10-мерного) является указателем на первый элемент ...
... запомни что имя массива является указателем на первый элемент ...
... Двумерный массив представляет собой массив указателей ...

а теперь - правильный ответ. (((Ж

имя массива - это не указатель ни на первый элемент, ни на последний, ни на какой-либо еще, и никогда им не было.
Фраза про то, что двумерный массив = массив указателей особенно жгуча.
массив - это сущность языка c/c++, которая характеризуется двумя параметрами: тип и размер. всё.

а всё, что тут ту услышал про "указатели" - это от незнания Стандарта, в частности правила Array-to-pointer conversion

Я так понял что создавая массив лучше если сразу сдалешь на него указатель и будешь работать с ним, нежели с самим массивом, тип так экономичнее для ресурсов компа, я ведь правильно понял?
для "ресурсов компа" особой разницы нет - адрес он и в Африке адрес. А при операциях адресной арифметики указатель может быть удобнее.
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
08.05.2009, 12:40     работа с указателями #11
Массивы и указатели в С++ тесно связаны и могут быть использованы почти эквивалентно. Имя массива можно понимать как константный указатель. Указатели можно использовать для выполнения любой операции, включая индексирование масива.
Предположим, что объявлены массивы целых чисел b[5] и целая переменная указатель bPtr. Поскольку имя массива(без индекса) является указателем на первый элемент массива, мы можем задать указателю bPtr адреспервого элемента массива b с помошью оператора
bPtr = b;
Это эквивалентно присваиванию адреса первого элемента массива следующим образом
bPtr = &b[0]
Сослаться на элемент массива b[3] можно с помощью выражения указателя
*(bPtr + 3)
В приведенном выражении 3 является смещением указателя. Когда указатель указыает на начало массива, смещение показывает, на какой элемент массива должна быть ссылка, так что значение ссмещения эквивалентно индексу массива. Предыдущую запись называют записью указатель-смещение. Скобки необходимы, потому что приоритет * выше, чем приоритет +. Без скобок верхнее выражение прибавило бы 3 к значению выражения *bPtr (т.е. 3 было бы прибавленно к b[0] в предположении, что bPtr указывает на начало массива). Поскольку элемент массива может быть указан указателем выражением, адрес
&b[3]
может быть записан также выражением указтелем
bPtr + 3
Сам массив можно рассматривать как указатель и использовать в арифметике указателей. Например, выражение
*(b + 3)
тоже ссылается на элемент массива b[3]. Вообще все выражения с индексами массива могли бы быть записаны с помощью указателей и смещений. В этом случае запись указатель-смещение применялась бы к имени массива как к указателю. Заметим, что предыдущий оператор никоим образом не модифицирует имя массива; b продолжает указывать на первый элемент массива.


Источник: Х.Дейтел, П.Дейтел "Как программировать на С++"
Rififi, и где мы переврали?
G-Cat
16 / 16 / 1
Регистрация: 15.03.2009
Сообщений: 94
08.05.2009, 14:13  [ТС]     работа с указателями #12
странно, у меня тоже книга Дейтелов (пятое малое издание), но там не так понятно и доходчиво объяснено...

пока вы тут все не разбежались. Я не понимаю как передавать массив или указатель в функцию. Не могли бы помочь?
stolyars
10 / 10 / 1
Регистрация: 24.12.2008
Сообщений: 32
08.05.2009, 14:20     работа с указателями #13
C++
1
int search(int*ptr,int array[]);//прототип
G-Cat
16 / 16 / 1
Регистрация: 15.03.2009
Сообщений: 94
08.05.2009, 14:22  [ТС]     работа с указателями #14
...ток хотел исправить свой предыдущий меседж

я хотел спросить не как одномерный массив передать, а двумерный...ну или более.
stolyars
10 / 10 / 1
Регистрация: 24.12.2008
Сообщений: 32
08.05.2009, 14:27     работа с указателями #15
раз уж тема про указатели дабы не плодить еще тем хочу спросить:
C++
1
cin >> *(a++)
и
C++
1
cin>>a[i]
("а"-это указатель).чем отличается в работе?ведь так и так работает...вопрос касаемо указателей на массив...

Добавлено через 2 минуты 11 секунд
как и одномерный ток размер одного индекса указать нужно
C++
1
int search(int array[10][]);
если не ошибаюсь
Rififi
 Аватар для Rififi
2332 / 1047 / 43
Регистрация: 03.05.2009
Сообщений: 2,656
08.05.2009, 14:28     работа с указателями #16
kazak,
Rififi, и где мы переврали?
Покажи мне, как это выглядит в оригинале, и я тебе отвечу.
А вникать в пёрлы наших переводчиков - как-то нет особого желания...
Про массивы и указатели - сначала читать 8.3.4, чтобы понять что это в принципе такое, потом - 4.2 (даст представление о том, "чё ващще происходит")

а пока ответь на такой простой вопрос.
если имя массива - это указатель, то в данном примере

C++
1
2
int a[10];
&a;
вторая строчка - она допустима с точки зрения спецификации языка? что она означает?

После этого можно попытаться ответить на следующий вопрос: всё тоже самое, но
C++
1
&a + 1;
G-Cat
Я не понимаю как передавать массив или указатель в функцию. Не могли бы помочь?
указатель - как и любую другую переменную - по значению, по указателю, по ссылке.
массив можно передать только через указатель или ссылку.
Gravity
 Аватар для Gravity
556 / 550 / 39
Регистрация: 29.01.2009
Сообщений: 1,274
08.05.2009, 14:42     работа с указателями #17
Вот вам из K&R отрывок про указатели и массивы (5.3).
The correspondence between indexing and pointer arithmetic is very close. By definition, the value of a variable or expression of type array is the address of element zero of the array. Thus after the assignment

pa = &a[0];

pa and a have identical values. Since the name of an array is a synonym for the location of the initial element, the assignment pa=&a[0] can also be written as

pa = a;
"...имя массива является синонимом расположения его начального элемента..."
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.05.2009, 15:14     работа с указателями
Еще ссылки по теме:

C++ Работа с указателями
Работа с указателями C++
Работа с указателями C++
Работа с указателями C++

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

Или воспользуйтесь поиском по форуму:
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
08.05.2009, 15:14     работа с указателями #18
Rififi, убедил , признаю свою неправоту - указатель и имя массива это не одно и тоже, различия все таки есть
G-Cat, прототипы функций для одномерного массива :
<Type1> Function(<Type2> array[], int arraySize)
<Type1> Function(<Type2> *array, int arraySize) оба прототипа работают идентично, второй параметр не обязателен, но всетаки желателен.
Прототип для двумерного массива:
<Type1> Function(<Type2>array[][columnSize], int rowSize)
columnSize параметр обязательный, причем компилятор должен знать его числовое значение при компиляции, поэтому он задается непосредственно числом или именованной константой, которая должна быть объявлена до прототипа.
Type1 и Type2 могут совпадать а могут и нет.
Yandex
Объявления
08.05.2009, 15:14     работа с указателями
Ответ Создать тему
Опции темы

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