The user enters a string that is a quadratic equation, like this:

scanf("%s",string[80]); 

Enter, for example: 21x^2+3x+5=0 . It is necessary to consider a string in some way to take a, b, c from it, that is, 21,3,5, so that these numbers are of double type. And then solve the quadratic equation. The program can only use the stdio library and only one function from the math.h library is sqrt , nothing else is possible.

I can write the equation, but I don’t have a clue how to remove numbers from a string as a double.

  • Replace all non-digits with spaces, and then scan the numbers (1st, 3rd and 4th). - Akina
  • I understand the schema. But I don’t understand exactly how to use it to output three numbers into three different variables of type doble. If you could write . - Sergey
  • one
    @Akina It's not quite that simple, but they can (probably) enter 5+3x+21x^2=0 , and 21x^2+3x=-5 , and (surely) 21x^2+5=0 , and 21x^2+3x=0 ... And this is without taking into account the more exotic options such as 21x^2+2x+x+5=0 . - Yaant
  • one
    No, this is a primitive task, as it were) Should enter in the same way as in the example ax ^ 2 + bx + c = 0 - Sergey
  • one
    @ Sergey: And what, even so it is impossible to enter: 5x^2-3x-10=0 ? - AnT

2 answers 2

In this case, scanf() with one large format string, as suggested by @Sergey, will not work. Once the members of the equation can follow in any order, then the line must be read in parts.

Let the input have a string of the form S1+...+SN=0 or S1+...+SN=<нецелое_число> (where Si = <нецелое_число>x , or Si = <нецелое_число>x^<целое_число> ), and output - an array of coefficients, where the array index corresponds to the desired degree when the coefficient.

Important note: since the number can be arbitrarily large, then in order to avoid overflowing the string buffer, we will read it in a small number. Well, since the string is complex, we use the state machine.

 #include <stdio.h> #define bool unsigned char #define true 1 #define false 0 enum States { // Конечные состояния Result_Success, // Успешное завершение Result_CoefficientCantBeStored, // Ошибка: массив outCoeffs слишком мал Result_UnexpectedSymbolInCoeff, // Ошибка: неожиданный символ в коэффициенте Result_UnexpectedEndOfPower, // Ошибка: После знака степени нет самой степени Result_UnexpectedEndOfRightSide,// Ошибка: не указана правая часть уравнения // Промежуточные состояния State_AtCoeffStart, // Первый символ коэффициента (+/-/цифра) State_AtCoeff, // Дальнейшие цифры коэффициента State_AtX, // Буква "икс" State_AtPowerCoeffStart, // Первый символ показателя степени члена State_AtPowerCoeff, // Показатель степени члена State_AtRightSideStart, // Первый символ справа от знака равенства State_AtRightSide, // Дальнейшие цифры справа от знака равенства // Первое неконечное состояние (используется при проверке на необходимость выхода) FirstInternalState = State_AtCoeffStart }; /** * Функция разбора строки с линейным уравнением и вычленения из неё коэффициентов. * * Переметры: * * in * Дескриптор входного символьного потока. * * outCoeffs * Указатель на массив, который будет принимать коэффициенты, считанные * из уравнения. Коэффициент для N-й степени идёт в outCoeffs[N]. * Если определённый коэффициент не указан в уравнении, то в соответствующий * элемент массива будет записан положительный ноль. * * coeffsCount * Количество элементов в массиве outCoeffs. Если очередная степень приводит * к записи за пределами outCoeffs, функция возвращает * Result_CoefficientCantBeStored. * * Возвращаемое значение: * * Константа из семейства States::Result_*. При возникновении ошибки происходит * возврат кода, отличного от Result_Success; массив outCoeffs при этом содержит * те коэффициенты, которые были успешно считаны целиком до возникновения ошибки. */ enum States parse(FILE* in, double* outCoeffs, size_t coeffsCount) { // Зануляем все указанные коэффициенты, вдруг не все из них будут указаны в уравнении for(size_t i = 0; i < coeffsCount; ++i) outCoeffs[i] = 0.0; enum States state = State_AtCoeffStart; size_t currentPowCoefficient = 0; bool isPositiveCoeff; double numBuffer = 0.0; bool metDecimalDot = false; size_t denomPower = 0; // Так как нам может потребоваться попридержать текущий символ до следующего // состояния, введём для него промежуточный буфер char ch = fgetc(in); while(state >= FirstInternalState) { // Считываем очередной символ и решаем, что с ним делать (решение принимаем // с помощью простенького конечного автомата). // // Да простят меня нелюбители switch-bases FSM, но пробрасывать // во вспомогательные функции все параметры и переменные — для учебного // примера это, пожалуй, перебор. switch(state) { case State_AtCoeffStart: // Сюда мы можем выйти при завершении предыдущего члена. // Поэтому именно здесь мы выдаём готовый коэффициент. if(coeffsCount > currentPowCoefficient) { // Чтобы сместить десятичную точку на denomPower позиций // вправо, мы могли бы воспользоваться pow(). Однако, // для этого потребуется зпрещённая math.h, а потому мы //вынуждены крутить цикл double decimalPointOffseter = 1.0; for(size_t i = 0; i < denomPower; ++i) decimalPointOffseter /= 10.0; outCoeffs[currentPowCoefficient] = numBuffer * (isPositiveCoeff ? 1.0 : -1.0) / decimalPointOffseter; } else state = Result_CoefficientCantBeStored; // Переходим непосредственно к чтению нового члена metDecimalDot = false; if(ch == '-') { numBuffer = 0.0; isPositiveCoeff = false; ch = fgetc(in); state = State_AtCoeff; } else if(ch == '=') { ch = fgetc(in); state = State_AtRightSideStart; } else if(ch == EOF) { state = Result_Success; } else { numBuffer = 0.0; isPositiveCoeff = true; state = State_AtCoeff; } break; case State_AtCoeff: if(ch >= '0' && ch <= '9') { numBuffer *= 10.0; numBuffer += (float)(int)(ch - '0'); ch = fgetc(in); ++denomPower; // Ничего не проверяем, всё равно будет сброс при точке } else if(ch == 'x') { state = State_AtX; ch = fgetc(in); } else if(ch == '+' || ch == '-' || ch == EOF) { // Окончание коэффициента с нулевой степенью. Придерживаем символ currentPowCoefficient = 0; state = State_AtCoeffStart; } else if(ch == '.') { metDecimalDot = true; denomPower = 0; } else state = Result_UnexpectedSymbolInCoeff; break; case State_AtX: // Подготавливаем аккумулятор для коэффициента currentPowCoefficient = 0; if(ch == '^') { ch = fgetc(in); state = State_AtPowerCoeffStart; } else { // Окончание коэффициента с первой степенью. Придерживаем символ currentPowCoefficient = 1; state = State_AtCoeffStart; } break; case State_AtPowerCoeffStart: state = (ch != EOF) ? State_AtPowerCoeff : Result_UnexpectedEndOfPower; break; case State_AtPowerCoeff: if(ch >= '0' && ch <= '9') { currentPowCoefficient *= 10.0; currentPowCoefficient += (size_t)(ch - '0'); ch = fgetc(in); } else state = State_AtCoeffStart; break; case State_AtRightSideStart: if(ch == '-') { numBuffer = 0.0; isPositiveCoeff = true; // Инверсия знака ch = fgetc(in); state = State_AtRightSide; } else if(ch == EOF) { state = Result_UnexpectedEndOfRightSide; } else { numBuffer = 0.0; isPositiveCoeff = false; // Инверсия знака state = State_AtRightSide; } break; case State_AtRightSide: if(ch == EOF) { currentPowCoefficient = 0; numBuffer = -numBuffer; // Переходим, чтобы сохранить коэффициент и сразу же выйти state = State_AtCoeffStart; } else if(ch == '.') { metDecimalDot = true; denomPower = 0; } else { numBuffer *= 10.0; numBuffer += (double)(int)(ch - '0'); ch = fgetc(in); ++denomPower; // Ничего не проверяем, всё равно будет сброс при точке } break; } } return state; } 
  • Arhad you are a god))))))) thank you very much - Sergey
  • @ Sergey: If the answer helped you, besides “thank you” it should also be ticked with a green checkmark on the left. - VladD
  • VladD I actually did it - Sergey
  • @ Sergey: Strange, but where is the tick? (It should be under the number of votes.) - VladD
  • @VladD when I mark a useful answer, the system writes that my vote is taken into account, but it does not affect the reputation since my points are less than 15) - Sergey
 scanf("%fx^2+%fx+%f=0", &a, &b, &c); 
  • From the comments to the question: @Akina Everything is not quite so simple, but they can (probably) enter 5+3x+21x^2=0 , and 21x^2+3x=-5 , and (surely) 21x^2+5=0 , and 21x^2+3x=0 ... And this is without taking into account the more exotic options like 21x^2+2x+x+5=0 . - ߊߚߤߘ
  • more exotic options - then you need to write an HMO generator. But I somehow doubt that this will be an adequate task for a first-year student. - Sergey
  • @Arhad: questioner: “No, this is a primitive task, as it were) should enter exactly the same way as in the example ax ^ 2 + bx + c = 0” - jfs
  • for double, you should use %lf , for example - jfs