2014-12-29 2 views
0

Это двумерный массив. Я понимаю, что имя массива указывает на первый элемент массива, то есть & массив [0] [0]. Но когда я пытаюсь напечатать, имя массива, адрес массива и значение массива все одинаковы.Почему имя массива, адрес массива и значение массива одинаковы?

#include <stdio.h> 
int main(void) 
{ 
    int array[4][2]={1,2,3,4,5,6,7,8}; 
    printf("%d %d\n", 
      &array[0][0], array[0][0]); 
    printf("%d %d %d %d\n", 
      array, &array, *array, **array); 
} 

ВЫВОД

2686704 1 
2686704 2686704 2686704 1 
+0

Вы должны добавить языковой тег. – csmckelvey

+0

Можете ли вы поделиться выходом. Используйте gdb для отладки. Это очень полезно – Jigar

+0

У меня есть выборка в моем ответе. (И я знаю, что использование% u для указателей является nono :) – eckes

ответ

0

У вас нет переменной указателя. Это массив (выражение), который внутренне преобразован в адрес первого элемента в большинстве контекстов.

Указатель будет int (*arrptr)[4][2] = &array;. Разница довольно хорошо объяснено в C FAQ

int array[4][2]={1,2,3,4,5,6,7,8}; 
int (*ptr1)[4][2]=&array; 
static int (*ptr2)[4][2]; 
ptr2=&array; 
printf("%p     %d\n", 
     &array[0][0], array[0][0]); 
printf("%p %p  %p  %d\n", 
     array,&array, *array,**array); 
printf("%p %p  %p  %d\n", 
     ptr1, &ptr1, *ptr1, ***ptr1); 
printf("%p %p  %p  %d\n", 
     ptr2, &ptr2, *ptr2, ***ptr2); 

0xbfbfec24        1 
0xbfbfec24 0xbfbfec24 0xbfbfec24 1 
0xbfbfec24 0xbfbfec20 0xbfbfec24 1 
0xbfbfec24 0x804970c  0xbfbfec24 1 
         ^^ 

Здесь вы видите, что указатель другой адрес в стеке и статический указатель еще более разные адреса в куче.

+1

с использованием '% u' для печати указателей вызывает неопределенное поведение (по крайней мере, используйте'% p', строго говоря, указатель также должен быть переведен в 'void *'). –

+0

@MattMcNabb Я знаю (я написал это в своем комментарии выше), я просто не хотел слишком сильно выводить из оригинального примера. – eckes

+2

Отклонение от исходного примера, чтобы исправить это, всегда уместно. Особенно, когда исходный пример даже не использовал '% u'. –

-3

Внутреннее представление массива выглядит следующим образом. Массивы - это не что иное, как постоянные указатели. Они представлены как места непрерывной памяти.

Sample example

Так что, если мы получить доступ к массиву, как A[1] он превращается в *(A + 1)A здесь то есть указывает на адрес первого элемента и 1 представляет собой смещение. Если массив имеет тип int, то 1 представляет sizeof int, например, например, размер int как 4B. Таким образом, 4 байта добавляется к A, который теперь будет указывать на второй элемент в массиве A. Таким образом, в 2D-массиве он будет представлен как *(*(A + i) + j), где i является строкой, а j - столбец. Так что на его основе вы получите выход, как уже упоминалось выше

+1

Массивы не являются указателями (постоянными или нет). –

+0

Часть 'A + i' вашей' * (* (A + i) + j) 'арифметики фактически полагается на указатели и массивы, которые не являются одинаковыми. Если 'i' было измерено в терминах' sizeof (int) 'или даже' sizeof (int *) ', то вам повезло бы получить тот элемент, который вы использовали. –

1

В коде (исправлено):

#include <stdio.h> 
int main(void) 
{ 
    int array[4][2] = {1,2,3,4,5,6,7,8}; 
    printf("%p %d\n", 
      (void *) &array[0][0], array[0][0]); 
    printf("%p %p %p %d\n", 
      (void *) array, (void *) &array, (void *) *array, **array); 
} 

в последнем printf() вызова:

  • array является двумерный массив int, но в этом контексте имя массива распадается на указатель на его первый элемент. Его первый элемент array[0], не array[0][0], о чем свидетельствует тот факт, что:

    int * p = array; 
    

    должно дать вам предупреждение, в то время как:

    int (*p)[2] = array; 
    

    не должен.

    Из-за способа массивы располагаются в памяти, она, тем не менее, также верно, что адрес array такой же, как адрес array[0], который является таким же, как адрес array[0][0].

  • &array - это адрес массива, который совпадает с адресом его первого элемента ... и так далее.

  • *array эквивалентен array[0]. Тип array[0] - это массив int размера 2. Так как array[0] сам по себе является массивом, он также здесь распадается на указатель на его первый элемент, который, как объясняется, имеет тот же адрес, что и &array, и тот же адрес array распадается на, здесь.

  • **array эквивалентно array[0][0], которые, в конечном счете, является фактическим int, а не массив, и поэтому не гниет на какой-либо адрес, это просто значение 1.

Именно поэтому первые три выражения оцениваются по одному и тому же адресу.

Обратите внимание, что %p для указателей, а также потому, что printf() является VARIADIC функции, компилятор не может неявно преобразовать указатели void * как это обычно, потому что он не знает, printf() ожидает void * для %p спецификатора, так вы должны явно указать их на void *. На самом деле вы, вероятно, будете долго искать современный настольный компьютер, где void *, int *, int (*)[2] и int (*)[4][2] не имеют точного представления, но правильность правильнее, чем неправильная.

0

Это не одно и то же.

Массив - это объект, состоящий из последовательности одного или нескольких смежных элементов, одинакового типа. 2-мерный массив - это не что иное, как массив массивов.

имя из массива - это выражение. Как и любое выражение типа массива, он в большинстве, но не во всех контекстах неявно преобразуется в указатель на первый элемент массива. Исключения составляют, когда это операнд sizeof (sizeof arr дает размер объекта массива, а не размер указателя), и когда он является операндом унарного & (&arr дает адрес всего массива).

Адрес адрес массива подобен адресу любого объекта. Он относится к определенному адресу памяти и имеет тип: указатель на тип массива. Например, учитывая:

int arr[10]; 

выражение arr (если это не операнд & или sizeof) дает адрес arr[0], и имеет тип int*. Выражение &arr дает адрес всего массива; это то же место памяти, но оно имеет тип int (*)[10], или «указатель на массив из 10 int s».

Значение значения из массива, как правило, не является тем, о чем вы можете напрямую обратиться. Он состоит из значений элементов массива.

Теперь давайте посмотрим на вашу программу:

#include <stdio.h> 
int main(void) 
{ 
    int array[4][2]={1,2,3,4,5,6,7,8}; 

Это более четко написано, как:

int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}}; 


printf("%d %d\n", 
      &array[0][0], array[0][0]); 

array[0][0] является int объектом, так &array[0][0] является его адрес, и это o f тип int*. Правильный способ печати адреса (значение указателя) заключается в использовании формата %p; он ожидает аргумент типа void*, поэтому вы должны его преобразовать.

printf("%p %d\n", (void*)&array[0][0], array[0][0]); 

    printf("%d %d %d %d\n", 
      array, &array, *array, **array); 

array является выражение типа массива, поэтому она «распады» до указателя на первый элемент этого массива. Этот элемент имеет тип int[2], поэтому указатель имеет тип int(*)[2]. Опять же, вы должны использовать %p и конвертировать в void*.

&array - адрес всего массива. Это тип int(*)[4][2].

В *array подвыражение array распадается на указатель. *, затем разыгрывает этот указатель, который дает нам объект типа int[2] (первый элемент массива). Это выражение типа массива, поэтому оно снова отклоняет указателю на первый элемент этого массива. Это тип int*.

В **array, *array оценивается, как указано выше; это указатель на объект int. Следующие * разыменовывают этот указатель, давая значение int.

Все значения указателя, которые вы напечатали, указывают на один и тот же адрес памяти, но они различаются по типу int*, int(*)[2] или int(*)[2][4]. Каждый из этих указателей, при преобразовании в void*, дает то же значение, и все они

} 

Сведя вместе, вот исправленная версия вашей программы:

#include <stdio.h> 
int main(void) 
{ 
    int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}}; 
    printf("%p %d\n", 
      (void*)&array[0][0], array[0][0]); 
    printf("%p %p %p %d\n", 
      (void*)array, (void*)&array, (void*)*array, **array); 
} 

Выход на мой (64-битная) система:

0x7fffc5070b30 1 
0x7fffc5070b30 0x7fffc5070b30 0x7fffc5070b30 1 

взаимосвязь между массивами и указателями в C может ввести в заблуждение. Большая часть путаницы может быть устранена путем чтения раздела 6 раздела comp.lang.c FAQ.

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