Вы не нужен тип данных, который может содержать различные типы данных: операторы и целые числа, может быть, даже числа с плавающей точкой или имен переменных (или функций).
Общим подходом в C является использование union
, который может содержать несколько типов в одном и том же пространстве. Вы можете использовать только один из этих типов за раз, поэтому вам нужно указать, какой из типов активен, что можно сделать с помощью enum
. Затем оберните enum
и union
в struct
, чтобы они были аккуратно рядом друг с другом.
Ниже приведен пример реализации такого типа данных.Он не выполняет никаких операций, он только анализирует строку и печатает токены.
Как и в вашем примере, все токены должны быть разделены пробелом, так что strtok
может их найти. Если вы хотите распознать 5/2
в качестве трех токенов, вы можете построить лексер, как предложил Серж Балеста в его очень систематическом ответе. Нижеприведенная реализация не распознает отрицательные числа, такие как -1
. Обработка ошибок также очень проста.
Этот код может еще служить вам в качестве отправной точки для решения:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
enum Type { /* enumeration of possible types */
Operator,
Integer,
Float,
Name,
Illegal
};
struct Token {
enum Type type; /* token type */
union { /* mutually exclusive data fields */
long long int l; /* ... for Integer */
double x; /* ... for Float */
char name[20]; /* ... for Name and Operator */
} data;
};
struct Token illegal(const char *str)
{
struct Token tk = {Illegal};
snprintf(tk.data.name, 20, "%s", str);
return tk;
}
struct Token parse(const char *str)
{
struct Token tk = {Illegal};
if (strchr("+-*/%", *str)) {
if (str[1]) return illegal("Overlong operator");
tk.type = Operator;
strcpy(tk.data.name, str);
return tk;
}
if (isdigit(*str)) {
double x;
long long l;
char *end;
l = strtoll(str, &end, 0);
if (end != str && *end == '\0') {
tk.type = Integer;
tk.data.l = l;
return tk;
}
x = strtod(str, &end);
if (end != str && *end == '\0') {
tk.type = Float;
tk.data.x = x;
return tk;
}
return illegal("Illegal number");
}
if (isalpha(*str)) {
const char *p = str;
while (*p) {
if (!isalnum(*p++)) return illegal("Illegal name");
}
tk.type = Name;
snprintf(tk.data.name, 20, "%s", str);
return tk;
}
return illegal("Illegal character");
}
int split(struct Token tk[], int max, char *str)
{
int n = 0;
char *p;
p = strtok(str, " \t\n");
while (p) {
struct Token curr = parse(p);
if (curr.type == Illegal) {
fprintf(stderr, "Parse error: %s.\n", curr.data.name);
return -1;
}
if (n < max) tk[n] = curr;
n++;
p = strtok(NULL, " \t\n");
}
return n;
}
void print(struct Token tk)
{
switch (tk.type) {
case Operator: printf("operator %c\n", tk.data.name[0]);
break;
case Integer: printf("integer %lld\n", tk.data.l);
break;
case Float: printf("float %g\n", tk.data.x);
break;
case Name: printf("name \"%s\"\n", tk.data.name);
break;
default: printf("illegal token\n");
}
}
int main()
{
char line[] = "- + 2 * alpha beta/12.0 6";
struct Token tk[20];
int i, n;
n = split(tk, 20, line);
for (i = 0; i < n; i++) {
print(tk[i]);
}
return 0;
}
Вы спрашиваете 2 разные вопросы в одном: как разобрать в строки ввода и отдельных символов из цифр (первый вопрос в тексте) и как сохранить это в массиве (второй вопрос в заголовке). И вы не даете достаточно контекста для правильного ответа на первый вопрос. Что ** ** ** ваши спецификации для ввода? Только 4 оператора и десятичные целые числа? Любая многочленная функция ('inv' для 1/x или sqrt)? Любые круглые скобки ('' ')')? Любые десятичные числа (1.25)? Или это действительно обратный полис 4 операции целочисленного калькулятора? И вы принимаете несколько пробелов, вкладок, ...? –
На самом деле я хочу реализовать что-то вроде префиксного анализатора выражений. В котором я не хочу использовать круглые скобки, я просто хочу различать операнды с использованием индекса массива. как и в моем примере 12, нужно сохранить во втором последнем индексе, а 6 - в последнем индексе массива. Теперь я просто рассматриваю целые числа, но было бы здорово, если бы вы могли предложить способ для чисел с плавающей запятой. да, я использую только 5 операторов. + - */и% –