Reputation: 39
I have a problem with visual code, everything works fine on the online compiler, but while trying it on stm32 nucleo it doesn't return NULL
, where is the problem? It cannot break the while
loop.
#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);
}
Upvotes: 2
Views: 409
Reputation: 144923
Your program has multiple problems:
strtok()
modifies the string pointed to by its first argument, which is a nasty side effect and in your case loses important information such as the sign of the next constant./
array
has just 2 entries, causing undefined behavior for most equations that have more terms.Here is a modified version that uses strtod()
and manual parsing:
#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;
}
Upvotes: 2
Reputation: 154130
Array too small - by two.*1
I made array[]
much larger and added 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
}
The output was
0 '2x^2'
1 'x/5'
2 '2'
3 '0'
So apparently array[]
needed to be at least array[4]
.
Recommend to add protection when parsing or use a different approach.
if (i+1 >= sizeof array/sizeof array[0]) {
// Handle/report error somehow
}
array[i++] = ptr;
Aside: If using float
variables, might as well use float
functions.
// float root1 = (-b + sqrt(d)) / (2 * a);
// ---------------------v
float root1 = (-b + sqrtf(d)) / (2 * a);
*1
Post had changed from "2x+2=0"
to "2x^2+x/5+2=0"
Upvotes: 1
Reputation: 223101
Given skai
pointing to an array of char
containing “2x+2=0”, a sequence of calls to strtok
with delimiters “+-=” is expected to return first a pointer to (the first character of) “2x”, then “2”, then “0”, then a null pointer. The code as written attempts to store these values in array[0]
, array[1]
, and array[2]
. However, array
has no element 2 since it was defined with only two elements. So the program overflows the array, and the resulting behavior of the program is not defined by the C standard. It may be the program is then overwriting memory in such a way as to cause strtok
to misbehave.
Change the definition of array
to be larger, and, inside the loop calling strtok
, monitor the value of i
: If it reaches the limit of the array size, print an error message and terminate the function (or the entire program).
Upvotes: 3