СЦЕНАРИЙ 1
int *nums = {5, 2, 1, 4};
printf("%d\n", nums[0]);
Почему это один segfault?
Вы объявили nums
как указатель на int - nums
он должен хранить в памяти адрес одного целого числа.
Затем вы попытались инициализировать nums
массив из нескольких значений. Поэтому, если не вдаваться в подробности, это концептуально неверно - бессмысленно назначать несколько значений переменной, которая должна содержать одно значение. В этом отношении вы увидите точно такой же эффект, если сделаете это:
int nums = {5, 2, 1, 4};
printf("%d\n", nums);
В любом случае (назначьте несколько значений указателю или переменной типа int), тогда произойдет то, что переменная получит первое значение, которое 5
, а остальные значения игнорируются. Этот код соответствует требованиям, но вы получите предупреждения для каждого дополнительного значения, которого не должно быть в назначении:
warning: excess elements in scalar initializer
.
В случае присвоения нескольких значений переменной-указателю, программа перестает работать при доступе nums[0]
, что означает, что вы буквально отсылаете все, что хранится по адресу 5 . В этом случае вы не выделили допустимую память для указателя nums
.
Стоит отметить, что для случая присвоения нескольких значений переменной int нет segfault (здесь вы не разыменовываете какой-либо недопустимый указатель).
СЦЕНАРИЙ 2
int nums[] = {5, 2, 1, 4};
Это не segfault, потому что вы на законных основаниях размещаете в стеке массив из 4 целых чисел.
СЦЕНАРИЙ 3
int *nums = {5, 2, 1, 4};
printf("%d\n", nums);
Это не segfault, как ожидалось, потому что вы печатаете значение самого указателя - НЕ то, что он разыменовывает (что является недопустимым доступом к памяти).
Другие
Он почти всегда обречен на segfault всякий раз, когда вы жестко кодируете значение указателя, подобного этому (потому что это задача операционной системы - определить, какой процесс может получить доступ к какой области памяти).
int *nums = 5;
Итак, практическое правило - всегда инициализировать указатель на адрес некоторой выделенной переменной, например:
int a;
int *nums = &a;
или же,
int a[] = {5, 2, 1, 4};
int *nums = a;