Почему моя функция не возвращает нулевой указатель? - PullRequest
2 голосов
/ 19 марта 2020

У меня проблема с визуальным кодом, все работает нормально на онлайн-компиляторе, но при попытке его на ядре stm32 он не возвращает NULL, в чем проблема? Он не может сломать while l oop.

#include <string.h>
#include <stdio.h> 
#include <stdlib.h>
#include <math.h>
#include <ctype.h>

int funk(char *skai) {
    char delim[] = "+-=";
    int i = 0;
    float x, d = 0;
    char *array[2];
    char *ptr = strtok(skai, delim);
    while (ptr != NULL) {
        array[i++] = ptr;
        ptr = strtok(NULL, delim); // <---- doesnt return null, endless loop
    }
    int a = atoi(array[0]);
    float b = atof(array[1]);
    int c = atoi(array[2]);
    if (c != 0) {
        d = b * b - 4 * a * c;
        if (d > 0) {
            float root1 = (-b + sqrt(d)) / (2 * a);
            float root2 = (-b - sqrt(d)) / (2 * a);
            if (root1 > root2) {
                x = root1;
            } else {
                x = root2;
            }
        } else {
            x = -b / (2 * a);
        }
    } else {
        x = b / a;
    } //printf("%0.3f\n", x);
    return x;
}

int main(void) {
    char rxd[20] = "2x^2+x/5+2=0";
    funk(rxd);
}

Ответы [ 3 ]

3 голосов
/ 19 марта 2020

Учитывая skai, указывающий на массив char, содержащий «2x + 2 = 0», ожидается, что последовательность вызовов strtok с разделителями «+ - =» вернет первый указатель на (первый символ) «2x», затем «2», затем «0», затем нулевой указатель. Написанный код пытается сохранить эти значения в array[0], array[1] и array[2]. Однако array не имеет элемента 2, поскольку он был определен только с двумя элементами. Таким образом, программа переполняет массив, и результирующее поведение программы не определяется стандартом C. Может быть, тогда программа перезаписывает память таким образом, что это приводит к неправильной работе strtok.

Измените определение array на большее, и внутри l oop вызовите strtok, контролировать значение i: если оно достигает предела размера массива, распечатать сообщение об ошибке и завершить функцию (или всю программу).

2 голосов
/ 19 марта 2020

В вашей программе несколько проблем:

  • вам следует стараться не изменять строку аргумента: strtok() изменяет строку, на которую указывает ее первый аргумент, что является неприятным побочным эффектом и в вашем case теряет важную информацию, такую ​​как знак следующей константы.
  • вы не обрабатываете /
  • array имеет только 2 записи, вызывая неопределенное поведение для большинства уравнений, которые имеют больше терминов .

Вот модифицированная версия, которая использует strtod() и ручной анализ:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int funk(const char *exp, double *x1, double *x2) {
    double coef[3] = { 0, 0, 0 };
    double d, e, a, b, c, sign, part;
    int n;
    const char *p = exp;
    char *q;

    part = 1;
    for (;;) {
        p += strspn(p, " \t\r\n"); // skip whitespace
        if (!*p)
            break;
        if (*p == '=') {
            p++;
            if (part < 0)
                return -1;
            part = -1;
            continue;
        }
        d = 1;
        sign = part;
        if (*p == '+') {
            p++;
        } else
        if (*p == '-') {
            sign = -1;
            p++;
        }
        if (*p != 'x') {
            d = strtod(p, &q);
            if (p == q)
                return -1;
            p = q;
        }
        d *= sign;
        n = 0;
        if (*p == '/') {
            p++;
            e = strtod(p, &q);
            if (p == q)
                return -1;
            p = q;
            d /= e;
        }
        if (*p == 'x') {
            p++;
            n = 1;
            if (*p == '^') {
                p++;
                n = strtol(p, &q, 10);
                if (p == q)
                    return -1;
                p = q;
                if (n < 0 || n > 2)
                    return -1;
            }
        }
        if (*p == '/') {
            p++;
            e = strtod(p, &q);
            if (p == q)
                return -1;
            p = q;
            d /= e;
        }
        coef[n] += d;
    }
    a = coef[2];
    b = coef[1];
    c = coef[0];
    d = b * b - 4 * a * c;
    if (a > 0 || a < 0) {
        /* quadratic equation */
        if (d < 0) {
            return -2;
        } else
        if (d > 0) {
            *x1 = (-b + sqrt(d)) / (2 * a);
            *x2 = (-b - sqrt(d)) / (2 * a);
            return 2;
        } else {
            *x1 = -b / (2 * a);
            return 1;
        }
    }
    if (b < 0 || b > 0) {
        /* first order equation */
        *x1 = 0 + -c / b;
        return 1;
    }
    /* constant equation */
    if (c > 0 || c < 0) {
        return 0;
    } else {
        return 3;
    }
}

void solve(const char *exp) {
    double x1, x2;
    switch (funk(exp, &x1, &x2)) {
    case 0:
        printf("%s -> no solution\n", exp);
        break;
    case 1:
        printf("%s -> single root x=%g\n", exp, x1);
        break;
    case 2:
        printf("%s -> two roots x1=%g, x2=%g\n", exp, x1, x2);
        break;
    case -2:
        printf("%s -> two imaginary roots\n", exp);
        break;
    case 3:
        printf("%s -> true for all x\n", exp);
        break;
    default:
        printf("not a quadratic equation: %s\n", exp);
        break;
    }
}

int main(int argc, char *argv[]) {
    if (argc > 1) {
        for (int i = 1; i < argc; i++)
            solve(argv[i]);
    } else {
        solve("2x^2+x/5+2=0");
        solve("x^2+2x+1=0");
        solve("x^2=49");
        solve("x=49");
        solve("x=0");
        solve("2=2");
        solve("1=0");
    }
    return 0;
}
1 голос
/ 19 марта 2020

Массив слишком мал - на два. * 1

Я сделал array[] намного больше и добавил printf("%d '%s'\n", i, ptr)

char *array[20];
char *ptr = strtok(skai, delim);
while (ptr != NULL) {
  printf("%d '%s'\n", i, ptr);
  array[i++] = ptr;
  ptr = strtok(NULL, delim); // <---- doesnt return null, endless loop
}

Вывод был

0 '2x^2'
1 'x/5'
2 '2'
3 '0'

Так что, очевидно, array[] должно быть не менее array[4].

Рекомендовать добавить защиту при разборе или использовать другой подход.

if (i+1 >= sizeof array/sizeof array[0]) {
  // Handle/report error somehow
}
array[i++] = ptr;

В сторону: при использовании переменных float можно также использовать функции float.

// float root1 = (-b + sqrt(d)) / (2 * a);
// ---------------------v
float root1 = (-b + sqrtf(d)) / (2 * a);

* 1

Сообщение изменено с "2x+2=0" на "2x^2+x/5+2=0"

...