2013-12-08 4 views
6

C++ 11 Код:C & C++: В чем разница между указателем и адресом массива?

int a[3]; 
auto b = a;  // b is of type int* 
auto c = &a;  // c is of type int(*)[1] 

С Код:

int a[3]; 
int *b = a; 
int (*c)[3] = &a; 

Значения b и c являются одинаковыми.

В чем разница между b и c? Почему они не одного типа?

UPDATE: Я изменил размер массива от 1 до 3.

+0

'auto' не играет хорошо с указателями, обычно это не подлежит проверке с помощью таких типов. – user2485710

+1

@ user2485710 Можете ли вы подробно остановиться на этом? Любые ссылки/цитаты? – Domi

+0

'auto' отлично работает с указателями, нет подсказки, где вы получили эту идею. –

ответ

7

В sizeof операторе должен вести себя по-разному, например, в особенности, если вы измените объявление a к различному числу целых чисел, таким как int a[7] :

int main() 
{ 
    int a[7]; 

    auto b = a; 
    auto c = &a; 

    std::cout << sizeof(*b) << std::endl; // outputs sizeof(int) 
    std::cout << sizeof(*c) << std::endl; // outputs sizeof(int[7]) 

    return 0; 
} 

Для меня, это печатает:

4 
28 

Это потому, что два указателя очень разные. Один - это указатель на целое число, а другой - указатель на массив из 7 целых чисел.

Второй действительно имеет тип указателя на массив. Если вы разыграете его, конечно, в большинстве случаев это будет decay to a pointer, но на самом деле это не указатель на указатель на int. Первый - это указатель-на-int, потому что распад произошел при назначении.

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

int main() 
{ 
    int a[7]; 
    int b[9]; 

    auto aa = &a; 
    auto bb = &b; 

    aa = bb; 

    return 0; 
} 

Это зарабатывает мне сообщение об ошибке:

xx.cpp: In function ‘int main()’: 
xx.cpp:14:8: error: cannot convert ‘int (*)[9]’ to ‘int (*)[7]’ in assignment 
    aa = bb; 

Этот пример, однако, работает, потому что разыменования bb позволяет ему распадаться на указатель к междунар:

int main() 
{ 
    int a; 
    int b[9]; 

    auto aa = &a; 
    auto bb = &b; 

    aa = *bb; 

    return 0; 
} 

Обратите внимание, что распад не происходит в левой части задания. Это не работает:

int main() 
{ 
    int a[7]; 
    int b[9]; 

    auto aa = &a; 
    auto bb = &b; 

    *aa = *bb; 

    return 0; 
} 

Он приносит вам это:

xx2.cpp: In function ‘int main()’: 
xx2.cpp:14:9: error: incompatible types in assignment of ‘int [9]’ to ‘int [7]’ 
    *aa = *bb; 
+0

'sizeof' также отбрасывает часть' const' для вашего второго 'cout' с' c' переменная. Вот почему они приводят к одинаковой производительности. – user2485710

+0

@ user2485710: Что приводит к идентичному выходу? Мои две строки 'cout' выводят два разных номера. 'const' вообще не входит в картину. Я не могу выровнять свой комментарий с чем-либо в своем сообщении. –

+0

Отличный ответ. Выделяет целую кучу концепций, о которых я не думал раньше! Я, вероятно, должен чаще использовать типы массивов в пользу типов указателей! – Domi

6

Идентичность любого объекта в C++ определяется пары ее типа и его адрес.

В вашем примере есть два разных объекта с одним и тем же адресом: сам массив и первый элемент массива. Первый тип имеет тип int[1], второй тип int. Два разных объекта могут иметь один и тот же адрес, если один является подобъектом другого, как в случае с элементами массива, членами класса и подобъектами класса.

Ваш пример будет понятнее, если Вы писали:

int a[5]; 
int (*ptr_to_array)[5] = &a; 
int * ptr_to_array_element = &a[0]; 

Но вы воспользовались тем, что Ид выражение a для массива затухает на указатель на первый элемент массива, так a имеет то же значение, что и &a[0] в вашем контексте.

+0

Спасибо! Я добавил немного измененную версию вашего кода на мой вопрос. – Domi

1

Рассмотрим следующий пример:

#include<stdio.h> 

int main() 
{ 
    int myArray[10][10][10][10]; //A 4 Dimentional array; 

    //THESE WILL ALL PRINT THE SAME VALUE 
    printf("%d, %d, %d, %d, %d\n", 
      myArray, 
      myArray[0], 
      myArray[0][0], 
      myArray[0][0][0], 
      &myArray[0][0][0][0] 
     ); 

    //NOW SEE WHAT VALUES YOU GET AFTER ADDING 1 TO EACH OF THESE POINTERS 
    printf("%d, %d, %d, %d, %d\n", 
      myArray+1, 
      myArray[0]+1, 
      myArray[0][0]+1, 
      myArray[0][0][0]+1, 
      &myArray[0][0][0][0]+1 
     ); 
} 

Вы увидите, что все 5 значений, напечатанных в первом случае все равны. Потому что они указывают на то же начальное местоположение.

Но когда вы увеличиваете их на 1, вы видите, что разные указатели теперь прыгают (точки) в разные местоположения. Это связано с тем, что myArray[0][0][0] + 1 будет прыгать на 10 целых значений, что составляет 40 байт, тогда как myArray[0][0] + 1 будет прыгать на 100 целых значений i.e на 400 байт. Аналогично myArray[0] + 1 перескакивает на 1000 целых значений или 4000 байт.

Значения зависят от того, что уровень указателя Вы имеете в виду.

Но теперь, если я использую указатели для обозначения всех из них:

#include<stdio.h> 

int main() 
{ 
    int myArray[10][10][10][10]; //A 4 Dimentional array; 

      int * ptr1 = myArray[10][10][10]; 
      int ** ptr2 = myArray[10][10]; 
      int *** ptr3 = myArray[10]; 
      int **** ptr4 = myArray; 

    //THESE WILL ALL PRINT THE SAME VALUE 
    printf("%u, %u, %u, %u\n", ptr1, ptr2, ptr3, ptr4); 

    //THESE ALSO PRINT SAME VALUES!! 
    printf("%d, %d, %d, %d\n",ptr1+1,ptr2+1,ptr3+1,ptr4+1); 
} 

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

Смежные вопросы