2014-10-13 15 views
-3

Вот мой код, в котором я получаю ошибку seg. Я почти уверен, что это связано с передачей по ссылке, но меня это смущает, и я не уверен, что я делаю это правильно.Почему я получаю ошибку сегментации? C программирование

#include <math.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include "utils.h" 
#define PI 3.1415926535897932384626433832795 

int circleStatistics(double radius, double *diameter, double *circumference, double *area){ 
    *diameter = radius * 2; 
    *circumference = PI * radius * 2; 
    *area = PI * radius * radius; 
    if (radius <= 0 || diameter == NULL || circumference == NULL || area == NULL) 
    printf("An error has occured\n"); 
    return 1; 
    }else{ 
    return 0; 
    } 
} 

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

#include "utils.h" 
#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char **argv){ 
    // Tests circleStatistics 
    double radius = 3; 
    double *diameter = NULL, *circumference = NULL, *area = NULL; 
    circleStatistics(radius, diameter, circumference, area); 
    printf("Expected output: radius = 3, diameter = 6, circumference ~= 18.849555, area ~= 28.2743339\n"); 
    printf("Actual output: radius = %.0f, diameter = %.0f, circumference ~= %.7f, area ~= %.7f\n", radius, *diameter, *circumference, *area); 
} 
+0

показать весь код – Haris

+0

показать код, где функция circleStaistics называется – karim

+0

Вы считаете, что проблема заключается в том, как вы передаете параметры, но вы предпочитаете пропустить эту часть? Вы также проверяете, что указатели являются «NULL», но после того, как вы их отменили? –

ответ

1

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

#include <math.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include "utils.h" 
#define PI 3.1415926535897932384626433832795 

int circleStatistics(double radius, double *diameter, double *circumference, double *area){ 
    if (radius <= 0 || diameter == NULL || circumference == NULL || area == NULL) 
    printf("An error has occured\n"); 
    return 1; 
    }else{ 
    /* now I know, that neither of the arguments point to NULL... */ 
    *diameter = radius * 2; 
    *circumference = PI * radius * 2; 
    *area = PI * radius * radius; 
    return 0; 
    } 
} 
+1

Это наивный ответ на вопрос. берет на себя вопрос по номиналу и отвечает на него, но было бы лучше критиковать дизайн. Требуются ли проверки для 'NULL'? Не лучше ли ожидать, что вызывающий абонент будет следовать контракту? сделайте это гораздо лучшим ответом. –

+0

@ Давид Хеффернан Интересная мысль. ИМО, код должен выполнять 'if (диаметр! = NULL) * диаметр = радиус * 2;' и аналогично для остальных 2, а затем возвращать 'void' – chux

+0

@chux Конечно, я открыт для обсуждения. Я бы взял стандартную библиотеку C в качестве моего руководства здесь. Он не будет проверять, чтобы пользователь не выполнял контракт на интерфейс. Поэтому 'strlen (NULL)' не вернет ошибку. Конечно, конструктор функций ld указывает, что параметры являются необязательными, указывается передачей «NULL». Но тогда реализация здесь была бы неправильной. –

0

Вы не показывать код вызова, но, скорее всего, вы проходите NULL для одного из указателей. Ваш текущий код сначала разыгрывает указатели, а затем проверяет, что они NULL. У вас это не так - вам нужно проверить до разыменования.

Однако, я думаю, что стоит рассмотреть весь дизайн. Это функция, которая передает одно входное значение и возвращает три выходных значения. Вам в идеале хотелось бы использовать возвращаемое значение функции, но не потому, что вам нужно вернуть три разных значения. Следовательно, указатели для имитации передачи по ссылке. И тогда вы начинаете беспокоиться о возможности прохода абонента NULL. Все это делает ваш код сложным.

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

Лично я бы обернуть три выходных значения в структуры и таким образом обойти большинство из этих вопросов:

struct CircleStats 
{ 
    double diameter; 
    double circumference; 
    double area; 
} 

struct CircleStats CalcCircleStats(double radius) 
{ 
    struct CircleStats stats; 
    stats.diameter = radius * 2; 
    stats.circumference = PI * radius * 2; 
    stats.area = PI * radius * radius; 
    return stats; 
} 

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