Ошибка ошибки сегмента при доступе к глобальному указателю из функции

Почему возникает ошибка сегментации, когда я присваиваю значение указателю в функции.

source_1.c

int *p = NULL;

func(int **y)
{
    *y = (int *) malloc(sizeof(int));
    *y = 1;
}

int main()
{
    func(&p);
    printf("%d\n",*p);
}    

source_2.c

int *p = NULL;

func(int **y)
{
    *y = (int *) malloc(sizeof(int));
    *y = 1;
}

int main()
{ 
    int *t = p;
    func(&t);
    printf("%d\n",*t);
}        

что не так в определении указателя и передаче адреса?


person sagar    schedule 09.07.2017    source источник
comment
См. этот вопрос: Указатель на уточнение указателя   -  person Mark Benningfield    schedule 09.07.2017
comment
*y = 1; присваивает 1 указателю. Конечно УБ. Вы хотели **y = 1?   -  person chux - Reinstate Monica    schedule 09.07.2017
comment
есть несколько проблем с опубликованным кодом. Начиная с у них отсутствуют необходимые операторы #include для stdio.h и stdlib.h   -  person user3629249    schedule 10.07.2017
comment
om C. при вызове любой из функций выделения кучи (malloc, calloc, realloc) 1) всегда проверяйте (!=NULL) возвращаемое значение, чтобы убедиться, что операция прошла успешно. 2) возвращаемый тип — void*, поэтому его можно назначить любому указателю. Приведение просто загромождает код, затрудняя его понимание, отладку и т. д.   -  person user3629249    schedule 10.07.2017
comment
эта строка: *y = 1; перекрывает указатель, который был только что установлен с помощью вызова malloc() со значением 1. Т.е. код теперь имеет утечку памяти, и DE-ссылка на этот указатель попытается прочитать с адреса 1 (который не является адресом, принадлежащим программе, И не выровнен должным образом для значения int. Возможно, вы имели в виду: *(*y) = 1;   -  person user3629249    schedule 10.07.2017
comment
при кодировании на C код всегда должен объявлять возвращаемый тип для каждой функции. Подпись для main() может быть int main( void ) или int main( int argc, char *argv[] ). Обратите внимание, что в обеих допустимых подписях тип возвращаемого значения — int. Для функции func() она ничего не возвращает, поэтому тип возвращаемого значения должен быть void.   -  person user3629249    schedule 10.07.2017
comment
*y = 1; — это ошибка, вы должны увидеть вывод компилятора для этой строки.   -  person M.M    schedule 10.07.2017
comment
Когда я печатаю значение * y внутри функции, она печатает «1», но это хорошее предложение от тех, кто писал о ** y @M.M.   -  person sagar    schedule 10.07.2017


Ответы (1)


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

В Windows и в Visual Studio IDE используйте встроенный отладчик, чтобы увидеть ошибки кодирования.

В среде Linux на компиляторе GCC попробуйте скомпилировать исходный код (в моем случае t.c) с помощью этой команды

gcc -Wall t.c -o t

gcc выдает эти предупреждения

t.c:8:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 func(int **y)
 ^
t.c: In function ‘func’:
t.c:11:8: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     *y = 1;
        ^
t.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
 }

Очевидно, что назначение *y = 1; неверно.

Спасибо Марку Беннингфилду за полезную ссылку на использование указателя на указатель

измените свой код на что-то вроде этого, чтобы решить вашу проблему

#include <stdio.h>


int *p = NULL;

void func(int **y)
{
    *y = malloc(sizeof(int));
    **y = 1;
}


int main()
{

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

}

Сначала для функции, которая не возвращает никакого значения, используйте void в качестве возвращаемого типа. Во-вторых, если мы попытаемся передать указатель на указатель функции в качестве аргумента, например, func(int **y), поскольку y может содержать адрес указателя, мы должны вызвать его с помощью func (&p). p — целочисленный указатель.

Наконец, рекомендуется не приводить результат malloc() к чему-то вроде

(int *)malloc(sizeof(int))

приведение результата malloc?

person EsmaeelE    schedule 09.07.2017
comment
Приведение не требуется в *y = (int *) malloc(sizeof(int));. Рекомендую *y = malloc(sizeof(int));, а еще лучше *y = malloc(sizeof **y); - person chux - Reinstate Monica; 09.07.2017
comment
Объясните, пожалуйста, в чем разница между ними? или просто ввести ссылку о них? - person EsmaeelE; 09.07.2017
comment
Я просто копирую коды сагара в свой ответ. но я думаю, что, поскольку malloc() возвращает пустоту *, лучше ее использовать. Также эта ссылка не приводится в примерах. en.cppreference.com/w/c/memory/malloc - person EsmaeelE; 09.07.2017
comment
См. stackoverflow.com/q/605845/2410359 Ваша ссылка en.cppreference.com предназначена для C++, а не для C, как это сообщение. - person chux - Reinstate Monica; 09.07.2017
comment
@chux моя ссылка en.cppreference.com/w/c/memory/malloc речь идет о malloc на языке C, хотя доменное имя CPP. рассмотрите адрес ссылки c/memory/malloc и используйте stdlib в примере, который используется только в исходном коде C, если это C++, необходимо использовать cstdio. спасибо, что рассмотрели мой пост и дали хорошую ссылку о приведении указателей, в которых я не очень разбираюсь. - person EsmaeelE; 09.07.2017
comment
Правда, эта ссылка относится к справочнику по языку C. - person chux - Reinstate Monica; 09.07.2017