Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Указатель на массив


Автор: Alexey91 8.8.2010, 18:19
Здравствуйте!

Не могу понять как использовать указатель на массив (да и вообще в каких случаях это нужно)
Если смотреть по коду, то если x=a, программа будет виснуть почему не понимаю

Ведь а - это адрес начала массива
И я указателю на массив присваиваю адрес начала другого массива, но если написать амперсанд, то будет работать.


Код

#include <stdio.h>
#include <conio.h>

main()
{
 int (*x)[10];
 
 int *b;
 int a[10];
 
 int i;
 
 for(i=0; i < 10; i++)
 {
  a[i]=i; 
}        
 x=&a;
 b=a;
 
 printf("%d %d %d",a,x,b);
             
 getch();
 return 0;
}     
      


Автор: cmygeHm 9.8.2010, 08:27
я вообще не видел никогда такой конструкции:
Код

 int (*x)[10];

А где Вы ее вычитали?

Автор: Annihilator 9.8.2010, 08:37
Здесь будет различие в типах
int (*x)[10]; x - указатель на массив из 10 элементов типа int
int a[10]; a - указатель на первый элемент int-массива
т.е. в первом случае рассматривается адрес именно всего массива, т.е. в случае с переменной a адрес всего массива запишется как &a (именно то, что у тебя в коде)
ну а для компиляции выражения x=a надо чтобы a являлся 2-мерным массивом со второй размерностью, равной 10 в данном случае, т.е.
a[X][10]

Как-то так.

Автор: Alexey91 9.8.2010, 14:53
Annihilator Думал, думал и никак не понял фразу "адрес всего массива". Как я понимаю массив представляет собой на носителе несколько ячеек памяти одного типа, адрес начала массива первая ячейка памяти. А вот адрес всего массива.. где он находится, к чему он конкретно относится? Не понятно(

А по поводу A[x][10] я понял так, что если присвоить x=A, то у x будет адрес элемента A[0][адрес всего массива]

но что такое адрес всего массива я никак понять не могу((

Автор: Annihilator 9.8.2010, 16:02
Цитата(Alexey91 @  9.8.2010,  18:53 Найти цитируемый пост)
Annihilator Думал, думал и никак не понял фразу "адрес всего массива". Как я понимаю массив представляет собой на носителе несколько ячеек памяти одного типа, адрес начала массива первая ячейка памяти. А вот адрес всего массива.. где он находится, к чему он конкретно относится? Не понятно(

Я имел в виду что при таком объявлении:
int (*x)[10]
x - "указатель на массив из десяти int", т.е. имеет тип int (*)[10]
а если так:
int x[10], то x имеет тип "int[10]"

т.е. если в первом случае инкрементировать x, то мы не попадем на следующий элемент массива, значение x увеличится на 10*sizeof(int), а не на sizeof(int)
т.е. x - имеет тип "указатель на массив из 10 целых чисел"

Типы разные, в этом все дело

Кстати, http://pw1.netcom.com/~tjensen/ptr/ch8x.htm

Автор: baldina 9.8.2010, 17:13
Код

int A[10]; // A - массив из 10 элементов int (не указатель!). здесь компилятор выделяет память под 10 элементов типа int
int *p; // p - указатель на int (может в том числе указывать на какой-либо элемент в каком-либо массиве. здесь компилятор выделяет память под переменную-указатель, p хранит адрес.
p = A; // присваиваем p адрес начала массива, он же - адрес элемента c индексом 0. А в данном случае (неявно) преобразуется в тип "указатель на челое"
p = &A[0]; // то же самое

A = p; // Error: А не является l-value. Ему нельзя присваивать значения.


т.е. имя массива в контексте похоже на указатель, потому что неявно приводится к типу указателя. но не является указателем.

зачем нужно:
1. перебрать все элементы в коллекции
Код

const int N=10;
int A[N];
for (int *p = A; p != A+N; ++p)
{
  // *p - текущий элемент массива
}


2. Передать адрес начала массива в функцию:
Код

void print_array (int *array, int size)
{
   for (int i=0; i < size; ++i)
     std::cout << array[i] << std::endl;

/*
   или:
   for (int *p=array; p != array+size; ++p)
     std::cout << *p << std::endl;
*/
}

int main ()
{
  const int N=10;
  int A[N] = {0,1,2,3,4,5,6,7,8,9};
  print_array (A, N);
}


Автор: Alexey91 9.8.2010, 17:49
Annihilator 
Угу!
Мне как раз компилятор и выдал:
16 cannot convert `int[10]' to `int (*)[10]' in assignment 
А я никак понять не мог.

Только не понимаю почему нужно перед а ставить апмерсанд, ведь при а и &а будет выводится один и тот же адрес.
Где происходит различие, что одно является адреса начала, а другое адресом всего массива)

т.е. амперсандом мы как бы получаем &int[10]

Я понял все, что ты сказал по аналогии с обычными переменными:

int d,*e;

d=1;
e=&d;

также с массивами

int (*a)[10], b[10];

b[10]={0,1,2,3,4,5,6,7,8,9};
a=&b;
Код


#include <stdio.h>
#include <conio.h>
main()
{
 int (*x)[10];
 int a[10];
 int i;
 for(i=0; i < 10; i++)
 {
  a[i]=i; 
}        
 x=&a;
 printf("%d %d %d",x,*x,**x);
             
 getch();
 return 0;
}     


Хм.. а почему я получаю значение элемента а[0] только после двойного разыменования?
Если не трудно, можешь написать.. если мы берем х, то получаем
если мы берем *x
... **х

 smile 


Baldina, спасибо !  smile 


Автор: boostcoder 9.8.2010, 17:56
не занимайтесь велоизобретательством, используйте контейнеры.

Автор: Annihilator 9.8.2010, 18:43
Цитата(Alexey91 @  9.8.2010,  21:49 Найти цитируемый пост)
Только не понимаю почему нужно перед а ставить апмерсанд, ведь при а и &а будет выводится один и тот же адрес

Адрес один, да типы разные.
Цитата(Alexey91 @  9.8.2010,  21:49 Найти цитируемый пост)
Где происходит различие, что одно является адреса начала, а другое адресом всего массива)

Если ты опреляешь переменную как массив
int a[10] - здесь a еще не указатель

иначе говоря a является указателем, при использовании без скобок [], допустим как аргумент функции
(в соответствии с п.4.2.1 Стандарта)
На лицо одномерный масив,
и с помощью такого указателя мы можем двигаться поэлементно

если же мы объявляем
int (*x)[10];
то в этом объявлении x - уже указатель, а если его использовать без [] - получается что x становится указателем на указатель
и мы можем двигать не поэлементно а "помассивно", т.е. можем использовать для построчного считывания 2d-массива

Код

    int a[3][4];
    for(int i=0; i < 3; i++)
    {
        for (int j=0; j < 4; j++)
            a[i][j]=i*2+j*3; 
    } 

    int (*x)[4];
    x=a;
    ++x; //перепрыгиваем строку

   int a_2_1 = *(*(x+1)+1) // двойное разыменовывание


Объяснил как мог...

Автор: toxx 9.8.2010, 20:24
Цитата

не занимайтесь велоизобретательством, используйте контейнеры. 

если пользоваться сразу контейнерами, не будешь знать множество ньюансов их создания.имхо

Автор: boostcoder 9.8.2010, 21:57
Цитата(toxx @ 9.8.2010,  20:24)
Цитата

не занимайтесь велоизобретательством, используйте контейнеры. 

если пользоваться сразу контейнерами, не будешь знать множество ньюансов их создания.имхо

ок. перефразирую: не занимайтесь велоизобретательством в реальных программах.

Автор: baldina 10.8.2010, 11:00
Alexey91, при объявлении
Код
int A[10];
выражения A и &A - синонимы и значения их равны &A[0]. 
Код

int x; // переменная типа int, хранит значение типа int. для получения адреса переменной используется &x
int *x; // указатель на int. хранит адрес. для доступа к значению по этому адресу используется разыменование *x
int **x; // указатель на указатель на int. хранит адрес, по которому расположен указатель. для доступа к значению int используется **x

про это в книжках пишут, почитай...
http://www.realcoding.net/articles/chast-v-ukazateli-i-massivy.html, например, пункт 5.3

Автор: Alexey91 12.8.2010, 10:40
Извиняюсь, за свое отсутствие

Annihilator, чувствую что понял (хотя чувства обманчивы )...

Переменная x является указателем на указатель, и при добавлении к переменной a амперсанда мы получаем адрес, который является указателем на адрес начала массива. И при увеличении адреса х, мы переместимся не на элемент массива, а на весь массив.

Кстати, чтобы не путаться адрес и указатель означают же одно и то же?

Есть переменная-указатель, которая хранит адрес 
это же аналогично
Есть переменная-указатель, которая хранит указатель?

И.. если у нас массивы любые, двумерные, n-мерные располагаются последовательно в памяти (т.е. например вызов элемента массива a[3][4] означает то же самое, что и a[0][12]). То зачем тогда были введены все эти размерности???

Baldina
Цитата


Alexey91, при объявлении
Код
int A[10];
выражения A и &A - синонимы и значения их равны &A[0]. 
Код

int x; // переменная типа int, хранит значение типа int. для получения адреса переменной используется &x
int *x; // указатель на int. хранит адрес. для доступа к значению по этому адресу используется разыменование *x
int **x; // указатель на указатель на int. хранит адрес, по которому расположен указатель. для доступа к значению int используется **x

про это в книжках пишут, почитай...
http://www.realcoding.net/articles/chast-v-ukazateli-i-massivy.html, например, пункт 5.3



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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)