Почему я получаю ошибку сегментации в своем коде, и можете ли вы объяснить передачу по ссылке, передачу по значению?

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

Я получаю ошибку сегментации / ошибку дампа ядра после выполнения цикла do while во второй раз. Что мне не хватает в петле?

Вот мой основной:

#include <stdio.h>
#include <stdlib.h>
#include <iomanip>
#include <iostream>

extern void CalculateTaxes(float gross,float defr, float *ft,float *st,float *ssit);
extern float calcGross(float hours, float payrate);
extern void InputEmplData(char *lastname, char *firstname, float *hours, float *payrate, float *defr);
extern void InitAcc(float *totreg, float *totovt, float *totrate, float *totgross, float *totfed, float *totstate, float *totssi, float *totdef,  float *totnet);
extern void AddDetail2Acc(float reghrs, float *totreg, float ovthrs, float *totovt, float pr, float *totpayrate, float theGross, float *totgross,float ft, float *totfed, float st, float *totstate, float ssit, float *totssi, float defr, float *totdef, float net, float *totnet);

int main(void)
{
   float fedtax,statetax,ssitax;
   float theGross;
   //int  counter=0;
   char answer;
   char lastname, firstname;
   float hours, payrate, defr, reghrs, ovthrs, net, numemps;
   float totgross, totpayrate, totreg, totovt, totrate, totfed, totstate, totssi, totdef, totnet;

/*
   FILE * reportFile; // 1) declare a FILE * variable

   reportFile = fopen("./report.txt","wt");
   // 2) open a report file with access mode "write-text"
   if (reportFile == NULL)
   {
     printf("  Report file open failed ...\n");
     fflush(stdin);
     getchar();
     exit(-10); // terminate w/ failure code -10; reqs <stdlib>
   }
*/
   printf("  Welcome to the Employee Tax Program\n");
   printf("  Please enter the number of employees taxes will be calculated:");
   scanf (" %f", numemps);
   InitAcc(&totreg, &totovt, &totrate, &totgross, &totfed, &totstate, &totssi, &totdef, &totnet);

   do 
   {
     InputEmplData(&lastname, &firstname, &hours, &payrate, &defr);   
     theGross = calcGross(hours, payrate); // call 3.4
     CalculateTaxes(theGross,defr,&fedtax,&statetax,&ssitax); // 3.5
     net=(theGross-defr)-fedtax-statetax-ssitax;
     AddDetail2Acc(reghrs, &totreg, ovthrs, &totovt, payrate, &totpayrate, theGross, &totgross,fedtax, &totfed, statetax, &totstate, ssitax, &totssi, defr, &totdef, net, &totnet);
     printf("    Fedtax    = %8.2f",fedtax);
     //fprintf(reportFile,"    Fedtax    = %8.2f",fedtax);
     //fprintf(stdout,"    Fedtax    = %8.2f",fedtax);
     printf("    Statetax  = %8.2f",statetax);
     //fprintf(reportFile,"    Statetax  = %8.2f",statetax);
     //fprintf(stdout,"    Statetax  = %8.2f",statetax);
     printf("    SSItax    = %8.2f\n",ssitax);
     //fprintf(reportFile,"    SSItax    = %8.2f\n",ssitax);
     //fprintf(stdout,"    SSItax    = %8.2f\n",ssitax);
     //printf(" %f %f %f %f %f %f %f %f", totreg, totovt, totrate, totfed, totstate, totssi, totdef, totnet);
     printf("  Do you have another employee(YES = 1 / No = 2) ==> ");
     fflush(stdin);
     scanf (" %c", answer);
     answer = getchar();
     getchar(); // removes '\n' from response

   } while (answer == 'y' || answer == 'y');

   //fclose(reportFile); // 4) close the file
   printf(" Press any key ... ");
   fflush(stdin);
   getchar();
   return 0;
}

Вот мои функции:

#include <stdio.h>

void InputEmplData (char *lastname, char *firstname, float *hours, float *payrate, float *defr);

void InputEmplData (char *lastname, char *firstname, float *hours, float *payrate, float *defr)
{   
   printf("  Please enter your lastname: ");
   scanf (" %s", lastname);
   fflush(stdin);

   printf("  Please enter your firstname: ");
   scanf (" %s", firstname);
   fflush(stdin);

   printf("  Please enter the hours you have worked including overtime: ");
   scanf (" %f", hours);
   while (hours < 0)
   {
    printf(" Please enter a valid number. Must be between 0.");
    scanf (" %f", hours);
   }
   printf("  Please enter your payrate(15.00): ");
   scanf (" %f", payrate);
   while (payrate <= 0)
   {
    printf(" Please enter a valid number. Must be above 0.");
    scanf (" %f", payrate);
   }
   printf("  Please enter the amount exempt from taxes: ");
   scanf (" %f", defr);

   while (defr <= 0)
   {
    printf(" Please enter a valid number. Must be above 0.");
    scanf (" %f", defr);
   }
}

CalculateTaxes функция:

#include "./taxrates.h" //user defined header for tax rates

void CalculateTaxes(float gross,float defr, float *ft,float *st,float *ssit);
float calcFed(float gross, float defr);
float calcState(float ft);
float calcSSI(float gross,float defr);

void CalculateTaxes(float gross,float defr, float *ft,float *st,float *ssit)
{
  *ft = calcFed(gross,defr);
  *st = calcState(*ft);
  *ssit = calcSSI(gross,defr);
}

float calcFed(float gross, float defr)
{
  return (gross-defr)*FEDTAXRATE;
}

float calcState(float ft)
{
  return ft * STATETAXRATE;
}

float calcSSI(float gross,float defr)
{
  return (gross-defr)*SSITAXRATE;
}


float calcGross(float h, float pr);

float calcGross(float h, float pr) 
{
  return h <= 40? h * pr : 40 *h + (h-40)*1.5*pr;
}

Функция для инициализации счетчиков:

void InitAcc(float *totreg, float *totovt, float *totrate, float *totgross, float *totfed, float *totstate, float *totssi, float *totdef,  float *totnet);

void InitAcc(float *totreg, float *totovt, float *totrate, float *totgross, float *totfed, float *totstate, float *totssi, float *totdef, float *totnet)
{
  *totreg = 0;
  *totovt = 0;
  *totrate = 0;
  *totgross = 0;
  *totfed = 0;
  *totstate = 0;
  *totssi = 0;
  *totdef = 0;
  *totnet = 0;
}

Функция использования счетчиков (незавершенная):

#include <stdio.h>

 void AddDetail2Acc(float reghrs, float *totreg, float ovthrs, float *totovt, 
            float pr, float *totpayrate, float theGross, float *totgross,
            float ft, float *totfed, float st, float *totstate, float ssit, float *totssi, 
            float defr, float *totdef, float net, float *totnet);

 void AddDetail2Acc(float reghrs, float *totreg, float ovthrs, float *totovt, 
            float pr, float *totpayrate, float theGross, float *totgross,
            float ft, float *totfed, float st, float *totstate, float ssit, float *totssi, 
            float defr, float *totdef, float net, float *totnet)
{
    *totgross+= theGross;
    *totreg += reghrs;
    *totovt += ovthrs;
    *totpayrate += pr;
    *totfed += ft;
    *totstate += st;
    *totssi += ssit;
    *totdef += defr;
    *totnet += net;

}

Makefile:

calc.obj:   calctaxes.cpp taxrates.h
    g++ -c calctaxes.cpp -o calc.obj

main2.exe:  main2.cpp calc.obj cGross.obj InputEmplData.obj InitAcc.obj
    g++ main2.cpp calc.obj cGross.obj InputEmplData.obj InitAcc.obj AddDetail2Acc.obj -o main2.exe

cGross.obj: calcGross.cpp InputEmplData.obj
    g++ -c calcGross.cpp -o cGross.obj

InputEmplData.obj:  InputEmplData.cpp
    g++ -c InputEmplData.cpp -o InputEmplData.obj

InitAcc.obj:    InitAcc.cpp InputEmplData.obj
    g++ -c InitAcc.cpp InputEmplData.obj -o InitAcc.obj

AddDetail2Acc.obj:  AddDetail2Acc.cpp
    g++ -c AddDetail2Acc.cpp InitAcc.obj -o AddDetail2Acc.obj

person CowboyBebopFan    schedule 24.04.2011    source источник
comment
слишком много кода и слишком мало информации о том, где код дает сбой. пожалуйста, попробуйте сократить его до небольшого фрагмента, который является правильным и имеет поведение. Это может помочь вам решить эту проблему самостоятельно.   -  person Mat    schedule 24.04.2011


Ответы (1)


Здесь действительно много кода, но вот первая ошибка, которую я вижу:

//...
extern void InputEmplData(char *lastname, char *firstname, float *hours, float *payrate, float *defr);
//...

    char lastname, firstname;

//...
    InputEmplData(&lastname, &firstname, &hours, &payrate, &defr);

//...
void InputEmplData (char *lastname, char *firstname, float *hours, float *payrate, float *defr)
{   
   printf("  Please enter your lastname: ");
   scanf (" %s", lastname);
   fflush(stdin);

   printf("  Please enter your firstname: ");
   scanf (" %s", firstname);
   fflush(stdin);

Если вы не предполагаете, что длины lastname и firstname равны 1, то вот ваша первая ошибка. Вы получаете ошибку сегментации, потому что вы записываете строку с длиной более 1 в char.

Возможная коррекция заключается в определении:

char lastname[NAME_LENGTH], firstname[NAME_LENGTH];

/...
InputEmplData(lastname, firstname, &hours, &payrate, &defr);

При этом вы добьетесь желаемого эффекта. Я использовал массивы символов для lastname и firstname, но вы можете динамически выделять память для lastname и т. д. с помощью malloc, но я бы не рекомендовал вам делать это без четкого понимания того, что вы делаете.

Также у меня есть несколько небольших советов, не считая ошибки сегментации:

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

void AddDetail2Acc(float reghrs, float *totreg, float ovthrs, float *totovt, 
            float pr, float *totpayrate, float theGross, float *totgross,
            float ft, float *totfed, float st, float *totstate, float ssit, float *totssi, 
            float defr, float *totdef, float net, float *totnet);

что-то вроде этого:

void AddDetail2Acc(AccStruct *in_out_sourceAcc, AddDataStruct in_addData);

Это более читабельно и менее подвержено ошибкам.

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

person beduin    schedule 24.04.2011
comment
В данный момент я нахожусь далеко от своего компьютера, но когда я устанавливаю массив для (строковых) имен, я получаю еще одну ошибку, которую я опубликую, когда доберусь до своего компьютера. Я попробую еще раз, когда вернусь домой. Я разместил весь код, потому что понятия не имел, в чем может быть проблема. После того, как я закончу базовую программу, я буду реализовывать структуру и массив для всей программы. Своего рода задание из двух частей. Думаю, я мог бы использовать целые числа, но я подумал, что когда у вас есть какие-либо десятичные числа, вы должны использовать двойные или плавающие числа? - person CowboyBebopFan; 25.04.2011
comment
Конечно, опубликуйте свою ошибку. Что касается операций с плавающей запятой, вы можете прочитать это обсуждение. - person beduin; 25.04.2011
comment
Я попытался добавить массив для строк, и я все еще получаю ошибку сегментации, но я думаю, что ошибка связана с чем-то другим. Я добавлял строку, чтобы спросить пользователя о количестве сотрудников, но как только я ввожу любое число, я получаю ошибку ошибки сегмента, поэтому я удалил ее. printf(" Please enter the number of employees taxes will be calculated:"); scanf (" %f", numemps); Извините, что продолжаю писать. Пока что все ошибки, которые я получаю, - это ошибки seg. - person CowboyBebopFan; 25.04.2011
comment
Это довольно просто. Вы должны предоставить scanf переменную address. Это означает, что вы должны написать scanf("%f", &numemps). Посмотрите пример здесь. Он показывает, как использовать scanf для ввода целочисленных типов. - person beduin; 25.04.2011
comment
Бедуин спасибо. Я переписываю этот код на C++, потому что знаю его лучше. Я могу сказать, что мне снова нужен обзор C. Не волнуйся, я вернусь. Еще раз спасибо. - person CowboyBebopFan; 25.04.2011