I want to create an array in which i can store run time supplied input such as - + 2 * 3 4 / 12 6 (total 9 elements here). Suppose none of input instances require more than 50 indices in array. I'm thinking of an integer array for this purpose but i'm not getting any format specifier which can be used in scanf() for taking input (terminated at return/Enter keypress ) so that i can distinguish latter in the program whether particular index was a char or int and what was its value.
If i use %c or even getchar() function I'm facing trouble to handle integers more than one digit.
if i use %d chars such as * + - / are not getting stored. so on and so forth.
So kindly suggest some way to do it if it is feasible.
When I learned programming (long time ago ...) my teacher said "never begin to code until it is clear what you want to achieve with a correct analysis". If I correctly understood, you are building a calculator, with only five operators (+-/*%) that follows following grammar :
expr : number
| operator expr expr
with the following lexical tokens :
operator: single character among +-*/%
number: consecutive sequence of decimal digits ([0-9]*)
not printing characters (space, tab, \r, \n) are used as delimiters or otherwise ignored
any other character causes an error.
Ok : that's your current specs, if you later want to use decimal numbers you just have to change the number definition to allow one optional decimal point.
Written like that, it would be easy to use lex and yacc, but for such a simple grammar, it is certainly overkill.
Even if we defined spaces as separator, it is not possible to use scanf to get tokens, because it would silently eat + signs : +12 is same as 12.
So you must build a simple lexer using getc that returns tokens, and then a parser that recursively compute expressions. No need for storing anything in arrays :
typedef struct _token {
enum {OPERATOR, INT, END, ERROR } type;
union {
int ival;
char op;
} value;
} TOKEN;
TOKEN getToken(FILE *fdin) {
static const char valid_op[] = "+-*/%";
static const char spaces[] = " \t\r\n";
int c;
TOKEN tok;
int val = 0;
int isval = 0;
while ((c = getc(fdin)) != EOF) {
if ((c >= '0') && (c <= '9')) {
val = 10 * val + (c - '0');
isval = 1;
}
else if (isval != 0) {
tok.type = INT;
tok.value.ival = val;
ungetc(c, fdin);
return tok;
}
else if (strchr(valid_op, c)) {
tok.type = OPERATOR;
tok.value.op = c;
return tok;
}
else if (! strchr(spaces, c)) {
tok.type = ERROR;
return tok;
}
}
tok.type = END;
return tok;
}
int parse(FILE *fdin, int *typ) {
int i, j;
*typ = INT;
for(;;) {
TOKEN tok = getToken(fdin);
if (tok.type == INT) {
return tok.value.ival;
}
else if (tok.type == OPERATOR) {
i = parse(fdin, typ);
if (*typ != INT) {
*typ = ERROR;
return 0;
}
j = parse(fdin, typ);
if (*typ != INT) {
*typ = ERROR;
return 0;
}
switch(tok.value.op) {
case '+': return i+j;
case '-': return i-j;
case '*': return i*j;
case '/': return i/j;
case '%': return i * j / 100;
}
}
else {
*typ = tok.type;
return 0;
}
}
}
You need a data type that can hold various types of data: operators and integers, maybe even floating-point numbers or names (of variables or functions).
A common approach in C is to use a union, which can hold several types in the same space. You can only use one of these types at a time, so you need a way to indicate which of the types is active, which can be done with an enum. Then wrap the enum and the union in a struct to have them tidily alongside each other.
Below is an example implementation of auch a data type. It doesn't do any operations, it only parses a string and prints the tokens.
As in your example, all tokens must be separated by white space, so that strtok can find them. If you want to recognize 5/2 as three tokens, you can build a lexer as Serge Ballesta suggested in his very systematic answer. The implementation below doesn't recognize negative numbers such as -1. Error handling is also very basic.
This code might still serve you as starting point for a solution:
#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;
}
Use
fgets() to read till end of line.
Parse the line and break the line into tokens using strtok() with space as delimiter.
Check whether each token is char or digit. There are multiple ways to check whether the token is digit or not. Use strtol() to convert tokens to integers this will help you to find difference between 0 and character also
Related
So this is my issue, I have to create a program that implements the shunting yard algorithm in C. For this I first need to parse the given mathematical expression into it's component parts. So I figured a simple for loop over a given string would do the trick.
char *math_exp = "2 + 4";
for (int i = 0; (unsigned) i < strlen(math_expr); i++) {
printf("%c", math_expr[i]);
}
> 2 + 4
But this quickly runs into an issue when a string contains a number with more digits than 1.
for (int i = 0; (unsigned) i < strlen(math_expr); i++) {
// skip if char is a space
if ((int) math_expr[i] == 32) {
continue;
}
printf("%c ", math_expr[i]);
}
> 2 2 + 4
The 22 is now treated as two separate numbers. So I tried to loop over all tokens in the string by splitting the string using the delimiter SPACE.
char math_expr[] = "22 + 4";
char *token = strtok(math_expr, " ");
while (token != NULL) {
printf("%s ", token);
token = strtok(NULL, " ");
}
> 22 + 4
This seemed to work but quickly ran into the issue of what to do when there's a bracket in the expression. e.g.:
char math_expr[] = "(22 + 2)";
char *token = strtok(math_expr, " ");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, " ");
}
> (22
> +
> 2)
And now I'm stuck, is there a way to circumvent this issue? I need to be able to extract every operator and number (with all possible digits) furthermore I also need to be able to distinguish brackets from numbers they are attached to. I hoped there was some easy way to do this. Any help is appreaciated.
Tokenization is the first step towards syntactic analysis. As such, it is probably a good idea to encapsulate it into a layer of abstraction, a function that yields one token at a time. This function also discards white space and combines consecutive digits into numbers. It is hard to delegate these steps to strtok(). Finally, the function may rewrap single characters into more structured information.
#include <ctype.h>
#include <stdio.h>
#define T_NUMBER 0
#define T_OPERATOR 1
#define T_BRACKET 2
typedef struct {
int type;
int value;
} token;
/* Reads the next token from stdin. Returns 1 on success, 0 on EOL. */
int next_token(token *t) {
char c;
/* discard spaces silently */
do {
c = getchar();
} while (c == ' ');
if (isdigit(c)) {
t->type = T_NUMBER;
t->value = 0;
do {
t->value = t->value * 10 + (c - '0');
c = getchar();
} while (isdigit(c));
ungetc(c, stdin); /* save the non-digit for next time */
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
t->type = T_OPERATOR;
t->value = c;
} else if (c == '(' || c == ')') {
t->type = T_BRACKET;
t->value = c;
} else if (c == '\n') {
ungetc(c, stdin); /* make sure we always return 0 from now on */
return 0;
} else {
/* handle illegal character */
}
return 1;
}
int main() {
token t;
while (next_token(&t)) {
switch (t.type) {
case T_NUMBER: printf("number %d\n", t.value); break;
case T_OPERATOR: printf("operator %c\n", t.value); break;
case T_BRACKET: printf("bracket %c\n", t.value); break;
}
}
return 0;
}
Sample run:
(22+ 37 * ( 1534-9)) + 18
bracket (
number 22
operator +
number 37
operator *
bracket (
number 1534
operator -
number 9
bracket )
bracket )
operator +
number 18
I've been trying to come up with solution for reading input which contains string and then brackets with array of numbers (I don't know how many numbers will be inputed.
Input could look like:
sacrifice (1, 2, 4, 2)
I am wondering if it is possible to achieve with scanf. I've been looking for different functions such as getline, sscanf, fgets and so on. But I couldn't come up with solution.
My code looks like this:
scanf("%[^(]", command);
while ( ( c = getchar() ) != ')' )
{
scanf("%d", weights[pos]);
pos++;
}
Which should read string until the bracket is found and then I tried to load the numbers in array as long as it doesn't reach the ')'. Yet it doesn't seem to work.
Is scanf viable to achieve this? Could anyone point me in better direction if not please?
I think it would be simpler to read the complete line from stdin and then parse it by hand using strtok or strcspn. Something like below could be done.
Disclaimer: This is just some sample code and doesn't handle all possible inputs and will crash with invalid input, it is just to give you an idea about how to do it. If you want to go this way, you would have to handle various error conditions, such as:
checking return value of malloc/getline/realloc
instead of atoi using a better function like strtol (which allows error checking),
handling white spaces in the input and
handling input which does not contain any parenthesis
Those are some of the many things which you would have to think about.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int *parse_numbers(char *numstr, size_t *size)
{
char *p;
char *s = numstr;
char *last;
size_t array_size = 10;
int *numbers = malloc(sizeof(int) * array_size);
size_t offset = 0;
for (p = strtok_r(s, ",", &last); p; p = strtok_r(NULL, ",", &last)) {
if (offset == array_size) {
array_size *= 2;
numbers = realloc(numbers, sizeof(int) * array_size);
//TODO do error check
}
numbers[offset++] = atoi(p); //strtol would be a better choice
}
*size = offset;
return numbers;
}
int main()
{
char *s = NULL;
char *p;
char *last;
int i = 0;
int *numbers;
size_t size;
size_t linesize = 0;
getline(&s, &linesize, stdin);
for (p = strtok_r(s, "(", &last); p; p = strtok_r(NULL, "(", &last)) {
if (i++ == 0) {
//This is the part of the string before '('
cmd = p;
} else {
// This is the part of the string after '('
numbers = parse_numbers(p, &size);
}
}
for (i = 0; i < size; i++) {
printf("%d\n", numbers[i]);
}
free(numbers);
free(s);
return 0;
}
Separate input from parsing. Far easier to handle the various issues of command processing. Concerning "don't know how many numbers will be inputed", IMO, a reasonable upper bound should be established. Else code is susceptible to overwhelming memory resources due to user input - a hacker exploit.
char command[1000];
while (fgets(command, sizeof command, stdin)) {
Now process the command using sscanf(), strtok() or your own code. The best method depends on maybe things not posted by OP, especially error handling.
int cmd_start;
int cmd_end;
int n = 0;
// sacrifice (1, 2, 4, 2, ...)
// +----------------- skip optional white space
// |+---------------- record scan position
// || +-------------- scan, but not save, lower case letters
// || | +------- record scan position
// || | | +----- skip optional white space
// || | | |+---- scan (
// || | | ||+--- skip optional white space
// || | | |||+-- record scan position
sscanf(command, " %n%*[a-z]%n ( %n", &cmd_start, &cmd_end, &n);
if (n == 0) {
printf("Invalid command '%s'\n", command);
continue;
}
int x[sizeof command / 2];
int x_count = 0;
char *p = &command[n]; // pick up where previous scan ended.
char sep[2] = {0};
while (sscanf(p, "%d %1[,)] %n", &x[x_count], sep, &n) == 2) {
x_count++;
p += n;
if (sep[0] == ')') break;
}
if (*p || sep[0] != ')') {
printf("Invalid separator '%s'\n", command);
continue;
}
// Use command
command[cmd_end] = '\0';
Process_Command(&command[cmd_start], x, x_count);
}
scanf("%d", weights[pos]); --> scanf("%d", &weights[pos]); – BLUEPIXY
That's indeed adequate to make the code work, provided a sufficiently dimensioned weights array.
Another starter question.
int counterConstant;
int x;
for(x = 0; x<20; x++){
if("bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSVWXYZ".IndexOf(tempString[x]) >= 0){
counterConsonant++;
}
}
But I get an error:
"error: member reference base type 'char [42]' is not a structure or union"
Is there another way I could do this?
(I'm doing this inside a for that checks each char on the string.)
There are no objects in C, so there are no "methods" and you can't call IndexOf on a string literal. A string is nothing more than an array of characters in C.
With that in mind, let's see how you can actually loop over the characters of a string:
for (const char *p = tempString; *p != '\0'; ++p) {
/* loop body */
char c = *p; // *p is the current letter
}
This will create a pointer to the first element of the string, and then loop over all of the following characters, if you'd really prefer to use indexes, you could do
for (size_t i = 0, len = strlen(tempString); i < len; ++i) {
char c = tempString[i];
}
As far as checking each letter for consonant-ness, that you can write a helper function for
int is_consonant(char c) {
c = tolower(c); // #include <ctype.h>
if (!isalpha(c)) return 0; // if not a letter, return false
switch (c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return 0;
default:
return 1;
}
}
now back to your loop, use this function to check each character.
int consonant_count = 0; // the =0 is important!
for (const char *p = tempString; *p != '\0'; ++p) {
if (is_consonant(*p)) {
++consonant_count;
}
}
If you don't initialize to 0, the initial value of consonant_count is unpredictable, so make sure you do.
If you are working on C (as it was specified in tags), strchr() method is used to search a char in a string, and strstr() is used to search a string in a string. We will use strchr() here because tempString[x] is a char. Also, don't forget to give your int variable an initial value. Try this code:
int main()
{
int counterConsonant = 0;
int x;
const char* tempString = "12345678901234567890";
for (x = 0; x<20; x++){
if (strchr("bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSVWXYZ", tempString[x]) != NULL){
counterConsonant++;
}
}
return 0;
}
C is a structured procedural language, so it doesn't have member functions/methods like a "true" object-oriented programming language such as C#. You could use a combination of strspn and strcspn like below to count sequences of consonants and non-consonant characters respectively, based on a predefined list of consonant characters:
#include <string.h>
size_t
count_consonants (const char *s)
{
size_t n;
size_t total = 0;
const char *consonants = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
/* While we haven't reached the end of the string,
execute the code in the body of the loop. */
while (*s != '\0')
{
/* Count the number of consonants starting at the current string position. */
n = strspn (s, consonants);
/* Add the number of consonants counted to
the total number of consonants found. */
total += n;
/* Advance the character pointer to the next character
that IS NOT a consonant, based on the number of consonants
stored in `n'. */
s += n;
/* Advance the character pointer to the next character
that IS a consonant (`strcspn' = skip the characters in
`s' that don't appear in `consonants'). */
s += strcspn (s, consonants);
}
return total;
}
char temp[20];
scanf("%s",temp);
int i,j, consonantsCounter=0;
char consonants[]={'b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z','B','C','D','F','G','H','J','K','L','M','N','P','Q','R','S','V','W','X','Y','Z'}
for(i=0;i<20;i++){
for(j=0;j<(sizeof consonants) / (sizeof consonants[0]);j++){
if(temp[i]==consonants[j]){
consonantsCounter++;
}
}
}
I have an unsigned char array unsigned char* name = malloc(nameLength); - how can I print it with printf? %sdoes not seem to work correctly, neither does %u (seeing random icons).
Here's how I create the data I want to print:
__int32 nameLength;
ReadProcessMemory(hProcess, (LPCVOID)(classNamePtr + 0x0004), &nameLength, sizeof(__int32), 0); //Reads nameLength to be 13 in this case
unsigned char* name = malloc(nameLength+5); //Add 5 for good measure, it is null terminated
ReadProcessMemory(hProcess, (LPCVOID)(nameStrPtr), name, nameLength, 0);
name[nameLength] = 0; //null terminate
printf("%s", name); //Outputs single character strange characters, like an up icon
When one detects a non-printable char, output an escape sequence or hexadecimal value
#include <ctype.h>
#include <string.h>
#include <stdio.h>
int printf_ByteArray(const unsigned char *data, size_t len) {
size_t i;
int result = 0;
for (i = 0; i < len; i++) {
int y;
int ch = data[i];
static const char escapec[] = "\a\b\t\n\v\f\n\'\"\?\\";
char *p = strchr(escapec, ch);
if (p && ch) {
static const char escapev[] = "abtnvfn\'\"\?\\";
y = printf("\\%c", escapev[p - escapec]);
} else if (isprint(ch)) {
y = printf("%c", ch);
} else {
// If at end of array, assume _next_ potential character is a '0'.
int nch = i >= (len - 1) ? '0' : data[i + 1];
if (ch < 8 && (nch < '0' || nch > '7')) {
y = printf("\\%o", ch);
} else if (!isxdigit(nch)) {
y = printf("\\x%X", ch);
} else {
y = printf("\\o%03o", ch);
}
}
if (y == EOF)
return EOF;
result += y;
}
return result;
}
If data contained one of each byte, sample follows:
\0...\6\a\b\t\n\v\f\xD\xE\xF\x10...\x1F !\"#$%&\'()*+,-./0123456789:;<=>\?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F...\xFE\o377
The selection of escape sequences will vary with code goals. The set above attempts to conform to something a C parser would accept.
Note: With the last else, always outputting a 3-digit octal sequence has scanning advantages, but folks are more accustomed to hexadecimal than octal.
Adjusted to conditionally print in hex depending on the following character.
It's quite bothering when reading unknown number of integers within a pair of parenthesis.
For example:
(1, 2, 3)
But We don't how many integers there are.
Rather than reading them entirely as a string, can anyone have any other ideas to fix that?
Many thanks.
It is terribly unclear what you really want from the posted question. But if you're talking about variable length arguments to a function, then:
Look into Variable arguments in C.
If you are talking about reading unknown no. of integers from input buffer, then you'll have to make your own function to read character by character, parsing the input for numbers, parenthesis and commas: A basic parser to do that is below(note, its not tested and can contain bugs) - understand and modify it accordingly. You can read in any no. of integers with this program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef enum { START, OPAREN, CPAREN, COMMA, DIGIT, EOF_S,UNKNOWN }Token;
int c;
unsigned char state = 0;
int numbers[100];
Token getToken(FILE *f)
{
while(isspace(c = fgetc(f)));
if(c == EOF) return EOF_S;
if(c == '(') return OPAREN;
if(c == ',') return COMMA;
if(c == ')') return CPAREN;
if(isdigit(c)) return DIGIT;
return UNKNOWN;
}
int getNumber(FILE *f)
{
int returnNumber = 0;
Token tok = START;
while(tok != DIGIT){
tok = getToken(f);
if(tok == UNKNOWN){ state = 1; return 0x0FFFFFFF;}
if(tok == EOF_S) { state = 2; return 0x0FFFFFFF;}
}
if(tok == DIGIT){
while(tok == DIGIT){
returnNumber = returnNumber * 10 + (c - '0');
tok =getToken(f);
}
}
return returnNumber;
}
int getNumbers(FILE *f, int *numbers_0)
{
int number;
int no_counter = 0;
while(((number = getNumber(f)) != 0x0FFFFFFF) && (state == 0)){
numbers_0[no_counter++] = number;
}
return no_counter; //returns no. of numbers between ( and ), separated by ','
}
int main(int argc, char *argv[])
{
int no, i;
no = getNumbers(stdin,numbers);
if(no > 100) no = 100;
for(i = 0; i < no; i++){
printf("%d\n",numbers[i]);
}
return 0;
}
Here after a simple C code to do it
#include <stdio.h>
int main(int argc, char **argv)
{
int x; char c='\0';
scanf("%*[(]");
while (c != ')' && scanf("%d %c", &x, &c)==2){
if (c!=',' && c != ')') {
printf ("format error in the input\n");
break;
}
printf("Number: %d\n", x);
}
}
If your input stream is stdin then use scanf as indicated in the above code
If your input stream is a file then use fscanf
if u need only read ( and processing right now) u can
read char C until C=='('
read char C if it space/tab/CR/LF continue step 2 else step 3
if C==')' End of reading list
so if u here c is a digit so u can getback char( use ungetc(C,stdin) ) and reread all number as integer .here u can opirate with intger as u wish. continue to 2.
If list is syntax correct above algo enogh else add where read C test on EOF and on step 4 test on alpha.
I think u can rewrite algo using C without goto.
I hope you are looking for a function implementation with variable arguments, below snippet will help you.
int add(int *total, int count, ...)
{
int i = 0;
va_list numbers;
va_start(numbers, count);
for (i = 0; i < count; i++)
{
*total += va_arg(numbers, int);
}
va_end(numbers);
}
You can call this function like
...
int result = 0;
add(&result, 3, 10, 20, 30);
...