2016-07-20 1 views
0

Я пишу программу для одного из упражнений в книге ANSI C, и программа падает, когда я достигаю эту линию:программа C падает из-за присвоение указателя

*pmonth = i; 

в функции month_day.

#include <stdio.h> 

void month_day(int year, int yearday, int *pmonth, int *pday); 

int main(int argc, char *argv[]){ 
    int year = 1994; 
    int *month; 
    int yearday = 288; 
    int *day; 
    month_day(year, yearday, month, day); 
    printf("Month = %d, day = %d", *month, *day); 
    return 1; 
} 

static char daytab[2][14] = { 
     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 
}; 

void month_day(int year, int yearday, int *pmonth, int *pday){ 
    int i, leap; 

    leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; 
    char *p = &daytab[leap][1]; 
    for(i = 1; yearday> (int) *p; i++){ 
     yearday -= *p++; 
    } 
    *pmonth = i; /*CRASHES HERE*/ 
    *pday = yearday; 
} 

Любые идеи, почему это происходит? Я относительно новичок в указателях, поэтому я мог легко совершить глупую ошибку. Заранее спасибо.

EDIT Благодарим вас, ребята, за ответы и терпение, пытаясь получить винт указателей.

+1

'INT месяц, день,' '.. month_day (год, yearday, и месяц, &day);' ' – BLUEPIXY

+0

* pmonth = i' есть ** не ** присвоение указателя – tofro

+0

Большинство компиляторов должны выдавать предупреждения о коде в. вопрос, некоторые по умолчанию. gcc и clang нужно, например, опция '-Wall'. Тогда вопрос, надеюсь, будет о том, что делать с предупреждением:« месяц »используется неинициализированным в этой функции. warning –

ответ

2

Указатель pmonth не инициализирован. Так что вы не должны разыгрывать его. Вы должны назначить действительный адрес указателю. Для этого вы можете назначить переменный адрес оператору & или позвонить по телефону malloc(1).

Поскольку вы не кажется, нужно указатели в вашей основной функции, ваш код должен быть:

int main(int argc, char *argv[]){ 
    int year = 1994; 
    int month; 
    int yearday = 288; 
    int day; 
    month_day(year, yearday, &month, &day); 
    printf("Month = %d, day = %d", month, day); 
    return 1; 
} 

В этом коде мы даем pmonth и pday Адреса переменных month и day. Эти переменные существуют в этом контексте, поэтому их адреса действительны. Таким образом, pmonth и pday указывают на действительную память.

Если вам действительно нужны указатели в вашей основной функции, позвоните malloc(1), чтобы выделить память вашей программе и сохранить адрес этого фрагмента памяти в указателе.

+0

@Ben: да, конечно , спасибо за обзор. – blatinox

+0

Хороший ответ, Плюс 1. –

+0

Я вижу, спасибо. Проблема в том, что я не знаком с указателями. – Slavvio

1

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

Что-то вроде этого будет достаточно:

int month; // Some actual memory. 
int *pmonth = &month; // pmonth now points to something real. 

Но опять же, точка функции month_day является предоставление выходных параметров, так что даже это будет достаточно:

int month, day; 

month_day(..., &month, &day) 
0

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

Вы определили функцию void month_day(int year, int yearday, int *pmonth, int *pday), для которой необходимо передать два указателя на int (pmonth and pday). Вы правильно указали на int и компилятор успешно скомпилировал вашу программу, но эти указатели не указывают на правильность адресов памяти. Когда вы обращаетесь к адресу, указанному вашим неинициализированным указателем (который может быть недействительным или не принадлежит вам), вы получаете Segmentation Fault.

Ошибка сегментации - это особая ошибка, вызванная доступом к памяти, которая «не принадлежит вам.«Это вспомогательный механизм, который мешает вам разлагать память и вводить жесткие ошибки памяти.

Существует много способов получить segfault. Обычный способ получения Segfault является разыменования нулевого указателя:

int *p = NULL; 
*p = 1; 

Чтобы решить проблему, ваш код должен быть как приведенному ниже

int main(int argc, char *argv[]) 
{ 
    int year = 1994; 
    int month; 
    int yearday = 288; 
    int day; 

    month_day(year, yearday, &month, &day); 
    printf("Month = %d, day = %d", month, day); 

    return 0; 
} 

Или

Вы можете позвонить malloc Функция динамически распределяет память и присваивает адрес, возвращаемый функцией malloc, переменным указателя. Remember, to call free function to release memory allocated dynamically when you no longer need the memory.

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