C и массивы: назначение [Warning] делает указатель из целого без литья

У меня возникают проблемы с указателями и массивами в C. Здесь код:

#include<stdio.h>


int *ap;
int a[5]={41,42,43,44,45};
int x;

int main()
{
    ap = a[4];
    x = *ap;
    printf("%d",x);
    return 0;
}

Когда я компилирую и запускаю код, я получаю это предупреждение:

[Предупреждение] присваивание делает указатель из целого без литья [включено по умолчанию]

Для строки номер 9 (ap = a [4];) и сбой терминала. Если я изменю строку 9, чтобы не включать позицию (ap = a;), я не получаю никаких предупреждений, и она работает. Почему это происходит? Я чувствую, что ответ очевиден, но я просто не вижу его.

Ответ 1

В этом случае a[4] - это 5th целое число в массиве a, ap - указатель на целое число, поэтому вы присваиваете целое число указателю и этому предупреждению.
Таким образом, теперь ap имеет значение 45 и когда вы пытаетесь отменить ссылку на него (выполняя *ap), вы пытаетесь получить доступ к памяти по адресу 45, который является недопустимым, поэтому ваша программа падает.

Вы должны сделать ap = &(a[4]); или ap = a + 4;

В c имен массивов распадается на указатель, так что a указывает на 1 - й элемент массива.
Таким образом, a эквивалентно &(a[0]).

Ответ 2

Что вы делаете: (я использую байты вместо того, чтобы лучше читать)

Вы начинаете с int *ap и т.д., поэтому ваша память (ваши компьютеры) выглядит так:

-------------- memory used by some one else --------
000: ?
001: ?
...
098: ?
099: ?
-------------- your memory  --------
100: something          <- here is *ap
101: 41                 <- here starts a[] 
102: 42
103: 43
104: 44
105: 45
106: something          <- here waits x

Давайте посмотрим, что произойдет, когда (напечатайте короткий текст для... print ( "$ d",...)

print a[0]  -> 41   //no surprise
print a     -> 101  // because a points to the start of the array
print *a    -> 41   // again the first element of array
print a+1   -> guess? 102
print *(a+1)    -> whats behind 102? 42 (we all love this number)

и т.д., поэтому a [0] совпадает с * a, a [1] = * (a + 1),....

a [n] просто читается легче.

теперь, что происходит в строке 9?

ap=a[4] // we know a[4]=*(a+4) somehow *105 ==>  45 
// warning! converting int to pointer!
-------------- your memory  --------
100: 45         <- here is *ap now 45

x = *ap;   // wow ap is 45 -> where is 45 pointing to?
-------------- memory used by some one else --------
bang!      // dont touch neighbours garden

Таким образом, "предупреждение" - это не просто предупреждение, это серьезная ошибка.

Ответ 3

int[] и int* представляются одинаково, за исключением того, что int [] выделяет (IIRC).

ap является указателем, поэтому его значение целое является опасным, так как вы понятия не имеете, что по адресу 45.

когда вы пытаетесь получить к нему доступ (x = *ap), вы пытаетесь получить доступ к адресу 45, который вызывает сбой, поскольку он, вероятно, не является частью памяти, к которой вы можете получить доступ.