Почему нижеприведенный printf вызывает ошибку сегментации?

Почему ниже printf вызывает ошибку сегментации?

#include <stdio.h>

int main()
{
    int *intp = {1,2,3,4,5};
    printf("%d", *intp);
    return 0;
}

Проверить это на onlinegdb.com

Итак, вы говорите нам, что ваш компилятор не выдавал предупреждения?

Sourav Ghosh 10.12.2018 06:07

Я изучал материал в Интернете и пробовал код в онлайн-компиляторах и получил это. Но даже если это опасно, почему это так?

anir 10.12.2018 06:08

Попробуйте int intp[].

Mateen Ulhaq 10.12.2018 06:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
92
1

Ответы 1

В вашем случае вы пытаетесь инициализировать указатель с помощью заключенного в скобки списка инициализаторов int, что является недопустимым.

int *intp = {1,2,3,4,5};

Если вы попытаетесь скомпилировать свой код с включенными правильными предупреждениями, вы увидите предупреждающие сообщения компилятора, например

source_file.c: In function ‘main’:
source_file.c:9:18: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     int *intp = {1,2,3,4,5};
                  ^
source_file.c:9:18: note: (near initialization for ‘intp’)
source_file.c:9:20: warning: excess elements in scalar initializer
     int *intp = {1,2,3,4,5};
                    ^
source_file.c:9:20: note: (near initialization for ‘intp’)
source_file.c:9:22: warning: excess elements in scalar initializer
     int *intp = {1,2,3,4,5};
                      ^
source_file.c:9:22: note: (near initialization for ‘intp’)
source_file.c:9:24: warning: excess elements in scalar initializer
     int *intp = {1,2,3,4,5};
                        ^
source_file.c:9:24: note: (near initialization for ‘intp’)
source_file.c:9:26: warning: excess elements in scalar initializer
     int *intp = {1,2,3,4,5};

Этот оператор в вашем коде является нарушением ограничения и не означает ничего значимого. Для скаляра инициализатор должен быть единственным выражением: как указано в C11, глава §6.7.9

The initializer for a scalar shall be a single expression, optionally enclosed in braces. [...]

Таким образом, список, заключенный в фигурные скобки, не является подходящим инициализатором для скаляра.

Вы можете изменить указатель на массив и инициализировать его с помощью оператора инициализатора, но не указателем.

Позже, когда вы пытаетесь разыменовать, вы, по сути, пытаетесь разыменовать память недействителен, которая вызывает неопределенное поведение.

Измените свой код на что-то вроде

 int intp[] = {1,2,3,4,5};

сделает свою работу.

Это действительно недействительный int *intp = {1,2,3,4,5}? Поскольку удаление printfне выдает ошибок.

anir 10.12.2018 06:27

Ага, пытаюсь их понять. Но тогда каков конечный результат int *intp = {1,2,3,4,5}? Ничего такого? Компилятор просто игнорирует строку из-за предупреждений или меняет значение адреса intp на что-то, и если да, то на что?

anir 10.12.2018 06:31

[.. продолжение из последнего комментария] Почему компилятор выдает предупреждения, а не ошибку времени компиляции? Особенно когда это: int *intp; ntp = {1,2,3,4,5}; выдает ошибку на 2-й строке. С какой целью разрешить int *intp = {1,2,3,4,5} с предупреждениями?

anir 10.12.2018 06:34

Потому что вы может создаете указатель из целого числа без приведения, а у вас может есть скалярный инициализатор с лишними элементами. Но выполнение как правило любого из них указывает на ошибку, и существуют предупреждения, чтобы проверить, что программист не сделал это намеренно для какой-то цели, которую компилятор не может определить.

paddy 10.12.2018 06:40

@paddy в скалярном инициализаторе не может быть лишних элементов, в стандарте C

M.M 10.12.2018 07:30

@paddy Я считаю, что мой первый вопрос остался без ответа: (1) «Но каков же конечный результат int *intp = {1,2,3,4,5}? Ничего? Компилятор просто игнорирует строку из-за предупреждений или меняет значение адреса intp на что-то, и если да, то на что? "

anir 10.12.2018 10:49

@paddy Также я не понял, что вы имеете в виду, говоря «вы можете создать указатель из целого числа без приведения». Любой пример? Также что вы имеете в виду под «у вас может быть скалярный инициализатор с лишними элементами». Это неопределенное поведение: char a[3] = {'h','e','l','l','o'};.

anir 10.12.2018 10:49

@ M.M можете ли вы ответить на Вопрос 1 и 2 выше: (2) Почему компилятор выдает предупреждения, а не ошибку времени компиляции? Особенно когда это: int *intp; ntp = {1,2,3,4,5}; выдает ошибку на 2-й строке. Какова цель разрешения int *intp = {1,2,3,4,5} с предупреждениями? Стоит ли мне задать для них новый вопрос?

anir 10.12.2018 10:51

@anir массив - это нет скалярного типа.

Sourav Ghosh 10.12.2018 11:06

Арифметические типы и типы указателей вместе называются скалярными типами. Типы массивов и структур вместе называются агрегатными типами.

Sourav Ghosh 10.12.2018 11:07

оххх хорошо, но я все еще не понимаю, были ли ответы на мои вопросы: Q1 и 2 квартал

anir 10.12.2018 11:22

@anir (1) включает самый высокий уровень предупреждений и обрабатывает все предупреждения как ошибки - ваш код не будет компилироваться. (Да, это параметры компилятора, и они существуют по какой-то причине - для использования) (2) То же самое.

Sourav Ghosh 10.12.2018 12:40

Re «Инициализатором для скаляра должно быть одно выражение»: это забавно, потому что инициализатор - это почти единственное выражение в C, которое не может быть выражение, как определено в грамматике. Потому что, конечно же, 1, 2, 3, 4, 5 - это выражение; он имеет значение 5 с использованием оператора запятой. Согласно грамматике, инициализатор на самом деле является присваивание-выражение, который обходит оператор запятой.

Eric Postpischil 10.12.2018 13:48

@anir: после отображения предупреждений большинство компиляторов, если они продолжат компиляцию, игнорируют лишние значения и преобразуют первое значение из целого числа в указатель. Делают ли они это на самом деле или нет, стандарт C.

Eric Postpischil 10.12.2018 13:50

@EricPostpischil Пробовал это: int *intp = {1,2,3,4,5}; printf("%u",intp);. Он печатает 1, подтверждающий то, что вы сказали: «игнорировать лишние значения и преобразовать первое значение из целого числа в указатель». (что несколько удивительно неочевидно) и расположение адреса 1 находится вне доступного сегмента, поэтому это вызывает ошибку сегментации. Итак, я чувствую, что в первой строке int *intp = {1,2,3,4,5}; нет ничего плохого (хотя то, что он делает [назначение 1 на intp], определенно неочевидно), просто это расположение адреса 1 просто недоступно, вызывая ошибку сегментирования. Правильно? @Sourav

anir 10.12.2018 18:00

[... продолжение из последнего комментария] Предупреждения, которые мы получаем, не имеют ничего общего с ошибкой сегментации. С int *intp = 5; printf("%d",*intp); я все еще получаю как ошибку сегментации, так и «предупреждение: инициализация делает указатель из целого числа без приведения». Хотя предупреждение не имеет ничего общего с ошибкой сегментации. Правильно?

anir 10.12.2018 18:30

@anir, вам следует узнать об этом у разработчиков gcc. Для меня это не имеет особого смысла.

M.M 10.12.2018 23:18

Другие вопросы по теме