I am creating a program that will calculate first degree equations. My issue is that, because an equation will include characters and operands, I need to store date on a string and then pass them to integers via atoi(). Yet, the answer value never changes from 0 (set value). Why is that?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main()
{
char equation[10];
scanf("%s", equation);
int length = strlen(equation);
char operands[7];
int op_index[7];
int op_amount = 0;
for(int i = 0; i < length; i++){
if(equation[i] == '*' || equation[i] == '/' || equation[i] == '+' || equation[i] == '-'){
operands[op_amount] = equation[i];
op_index[op_amount] = i;
op_amount++;
}
}
char nums1[3];
char nums2[3];
int i = op_index[0] - 1;
int j = 3;
int ans = 0;
while(isdigit(equation[i]) != 0){
nums1[j] = equation[i];
j--;
i--;
}
i = op_index[0] + 1;
j = 0;
while(isdigit(equation[i]) != 0){
nums2[j] = equation[i];
j++;
i++;
}
if(operands[0] == '*'){
ans = atoi(nums1) * atoi(nums2);
}
else if(operands[0] == '/'){
ans = atoi(nums1) / atoi(nums2);
}
else if(operands[0] == '+'){
ans = atoi(nums1) + atoi(nums2);
}
else if(operands[0] == '-'){
ans = atoi(nums1) - atoi(nums2);
}
printf("ans = %d", ans);
}
You are working too hard. Or, rather you're making the computer work too hard. You don't need (or want) to "store date on a string". You do not need to copy that data around. atoi is a broken tool (undefined behavior if the input cannot be represented by an integer), but it is able to mostly do what you want. Instead of copying the data around, just pass it the first character of the string you are interested in. The following code does not handle invalid data very well (ie, the string "5 + + + 10" will be treated the same as "5 + 0" and "1foo +3x" is the same as "1+3"), but adding the logic to validate the input is left as an exercise for the reader. (hint: validating the input is a lot easier if you use strtol instead of atoi.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char **argv)
{
char equation[1024];
int ans;
if( 1 != scanf("%1023[^\n]", equation) ){
fprintf(stderr, "No data avaialable\n");
return 1;
}
char *operator = equation + strcspn(equation, "*/+-");;
char *operand = operator + 1;
switch( *operator ){
case '*': ans = atoi(equation) * atoi(operand); break;
case '/': ans = atoi(equation) / atoi(operand); break;
case '+': ans = atoi(equation) + atoi(operand); break;
case '-': ans = atoi(equation) - atoi(operand); break;
default:
fprintf(stderr, "No operator found\n");
return 1;
}
printf("ans = %d\n", ans);
if( fflush(stdout) ){
perror("stdout");
return 1;
}
return 0;
}
Note that scanf is absolutely the wrong way to get input here, and it would make more sense to take the argument as a command line parameter. If you do read from the input stream, it would make more sense to use fgets. But I keep scanf here to demonstrate two thing: you must use a width modifier on %s and %[ conversions to prevent buffer overflow, and you should always check the return value.
Related
Here's a question from the last year's first "Intro to programming" exam at my uni:
Using the getchar() function read an input sequence consisting of
numbers, + and - signs. The output should be the result of those
arithmetical operations.
For example, if the input is 10+13-12+25-5+100, the output should be 131.
Now, given that I have a little bit of C experience before attending uni, this problem seems easy to solve using pointers, arrays, etc.
But here's the catch: on the exam you can only use things that the students were taught so far. And given that this exam is only like a month after the start of the school year, your options are fairly limited.
You can only use variables, basic input/output stuff, operators (logical and bitwise), conditional statements and loops, functions.
That means no: arrays, strings, pointers, recursion, structures, or basically any other stuff that makes this easy.
How in the hell do I do this? Today is the second time I've spent 3 hours trying to solve this. I have solved it successfully, but only after "cheating" and using arrays, string functions (strtol), and pointers. It's important for me to know how to solve it by the rules, as I'll have similar stuff on the upcoming exam.
Edit: my attempts so far have amounted to using the while loop combined with getchar() for input, after which I just get stuck. I don't have the slightest idea of what I should do without using more "tools".
The solution is quite simple, but it might not be obvious for a beginner. I will not provide a complete program, but rather outline the steps needed to implement this with only a few variables.
First of all, it's important to notice two things:
Your input can only contain one of -, + or any digit (0123456789).
The getchar() function will read one character of input at a time, and will return EOF when the end of the input is reached or an error occurs.
Now, onto the solution:
Start by reading one character at a time, in a loop. You will only stop if you reach end of input or if an error occurs:
int c;
while ((c = getchar()) != EOF) {
// logic here
}
Start with an accumulator set to 0, and "add" digits to it every time you encounter a digit.
// outside the loop
int acc = 0;
// inside the loop
if (/* c is a digit */)
acc = acc * 10 + (c = '0');
Hint: that /* c is a digit */ condition might not be simple, you can put this in the else of the check for - and +.
Every time you encounter either - or +, remember the operation, and each time you encounter an operator, first perform the previous operation and reset the accumulator.
// outside the loop
int op = 0;
int result = 0;
// inside the loop
if (c == '+' || c == '-') {
if (op) {
// there already is a previous operation to complete, do it
if (op == '+')
result += acc;
else
result -= acc;
} else {
// first operation encountered, don't do anything yet
result = acc;
}
acc = 0; // reset
op = c; // remember the current operation for the future
}
When you reach the end of the input (i.e. you exit the loop), perform the last operation (same logic inside the if from point 3).
Output the result:
You would normally write something like:
printf("%d\n", result);
However, if you cannot use string literals ("%d\n") or the printf() function, you will have to do so manually using putchar(). This is basically the opposite of what we did before to scan numbers into an accumulator.
Print the sign first if needed, and make the value positive:
if (result < 0) {
putchar('-');
result = -result;
}
Find the maximum power of 10 that is lower than your number:
int div = 1;
while (result / div / 10)
div *= 10;
Use the power to extract and print each digit by division and modulo by 10:
while (div) {
putchar('0' + ((result / div) % 10));
div /= 10;
}
Note: the '0' + at the beginning is used to convert digits (from 0 to 10) to the relative ASCII character.
End with a newline:
putchar('\n');
When writing a parser, I typically find myself that I "buffer" the next operation that "will be done". When the input changes state - you are reading digits, but then you read an operation - then you execute the "buffered" action and buffer the next operation that will be done in the future.
Example:
10+13-12
^^ - we read 10
^ - result=10 - we buffer that we *will* have to do + in the future
^^ - reading 13
^ - och we stopped reading numbers!
we execute _buffered_ operation `+` , so we do result += 13
and buffer `-` to be done in the future
^^ - we read 12
^ - och, EOF! we execute buffered operation `-` , so we do result -= 12
- etc.
The code:
#include <stdio.h>
int main() {
int result = 0; // represents current result
int temp = 0; // the temporary number that we read into
int op = 0; // represents the _next_ operation that _will_ be done
while (1) {
int c = getchar();
switch (c) {
// we read an operation, so we should calculate _the previous_ operation
// or this is end of our string
case '+': case '-': case EOF:
if (op == 0) {
// we have nothing so far, so start with first number
result = temp;
} else if (op == '+') {
result += temp;
} else if (op == '-') {
result -= temp;
}
// the next operation we will do in future is stored in op
op = c;
// current number starts from 0
temp = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
// read a digit - increment temporary number
temp *= 10;
temp += c - '0';
break;
}
// we quit here, the result for last operation is calculated above
if (c == EOF) {
break;
}
}
printf("%d\n", result);
// As I see it was mentioned that "%d\n" is a string,
// here's the simplest algorithm for printing digits in a number.
// Extract one digit from the greatest position and continue up
// to the last digit in a number.
// Take negative numbers and throw them out the window.
if (result < 0) {
putchar('-');
result = -result;
}
// Our program currently supports printing numbers up to 10000.
int divisor = 10000;
// 000100 should print as 100 - we need to remember we printed non-zero
int was_not_zero = 0;
while (divisor != 0) {
// extract one digit at position from divisor
int digit = result / divisor % 10;
// if the digit is not zero, or
// we already printed anything
if (digit != 0 || was_not_zero) {
// print the digit
putchar(digit + '0');
was_not_zero = 1;
}
// the next digit will be to the right
divisor /= 10;
}
putchar('\n');
}
#include <string.h>
#include <stdio.h>
void operate(int * sum, int * n, char todo) {
if (todo == 1) *sum += *n;
else if (todo == -1) *sum -= *n;
printf("%s %d\n", todo == 1 ? "ADD :" : "SUB :", *n);
*n = 0;
}
int main()
{
char * problem = "10+13-12+25-5+100";
int len = strlen(problem);
int i=0;
char c;
int n = 0;
int sum = 0;
char todo = 1;
while(i < len)
{
c = problem[i++];
if (c < 48 || c >= 58)
{
// Adds or subtracts previous and prepare next
operate(&sum, &n, todo);
if (c == '+') todo = 1;
else if (c == '-') todo = -1;
}
else
{
// Collects an integer
if (n) n *= 10;
n += c - 48;
}
}
operate(&sum, &n, todo); // Last pass
printf("SUM => %d\n", sum); // => 131
return 0;
}
#include <stdio.h>
void do_operation(char next_operation, int * result, int * number){
if (next_operation == '+'){
*result += *number;
*number = 0;
} else if (next_operation == '-'){
*result -= *number;
*number = 0;
} else {
printf("Unknown operation error.");
}
}
int main(int argc, char *argv[]){
char c;
int number = 0;
int result = 0;
char next_operation = '+';
do {
c = getchar();
if( c >= '0' && c <= '9' ){
number = number * 10 + c - 48;
} else if (c == '+'){
do_operation(next_operation, &result, &number);
next_operation = '+';
} else if (c == '-'){
do_operation(next_operation, &result, &number);
next_operation = '-';
} else {
do_operation(next_operation, &result, &number);
}
} while (c != '\n');
printf("%d", result);
}
I need to verify that String passed via scanf() are only numbers and "." and "," should be also acceptable with "-" as a negative number representation.
I have written this code:
int main(void)
{
char cFloatNum[100];
float fNum;
scanf("%[[+-]?[0-9]*[.,]?[0-9]+]", &cFloatNum);
fNum = atof(cFloatNum);
printf("%f", fNum);
return EXIT_SUCCESS;
}
I don't know why, but my output always seems to be 0.000000 no matter what numbers I write. I tried testing my regex on various regex website and it matched perfectly.
After writing something to the console, if it's valid it should be printed on the console via printf. For conversion from String to Float, I need to use atof() function.
Examples of valid numbers would be:
-44.276
44,546
56,657675
-77.2435235
only numbers and "." and "," should be also acceptable with "-" as a negative number representation
So write exactly that. For example:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
int check_your_condition(float *result) {
int ret = 0;
*result = 0;
bool seen_minus = false;
bool first_character = true;
bool seen_dot = false;
float div = 10;
for (int c; (c = getchar()) != EOF; first_character = false) {
if (first_character == true && seen_minus == false && c == '-') {
seen_minus = true;
continue;
}
if (seen_dot == false && (c == '.' || c == ',')) {
seen_dot = true;
continue;
}
if (!isdigit((unsigned char)c)) {
ret = -1;
// TODO handle error properly
break;
}
const short num = c - '0';
if (seen_dot == false) {
*result *= 10;
*result += num;
} else {
const float numf = num / div;
div *= 10;
*result += numf;
}
}
if (seen_minus) {
*result *= -1;
}
return ret;
}
int main() {
float a;
check_your_condition(&a);
printf("%f\n", a);
}
This is not a "ready to use"(TM) program, as still the newline character on multiple lines is just "ignored" in the input stream (ie. the isdigit(c) will just fail). A proper solution should call ungetc there and include proper logic what to do with the rest of the input.
scanf("%[[+-]?[0-9]*[.,]?[0-9]+]"
is completely wrong. No scanf does not support regexes.
For conversion from String to Float, I need to use atof() function.
Most probably you are asked to read the input as a single line and then apply atof function on the result:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main() {
char buf[200];
if (fgets(buf, sizeof(buf), stdin) == NULL) abort();
errno = 0;
const float a = atof(buf);
if (errno) abort();
printf("%f\n", a);
}
In such solution if . or , will be understood as the decimal separator is locale dependent. And the part of the input string after the string will be just ignored.
Reposting because my first post was no good. I have a question that I'm not really sure how to do. I know the process I'm going for, but am not totally sure how to scan a string into an array so that each character/integer is scanned into a independent element of the array. I'll post the question and the code I have so far, and any help would be appreciated.
Question:
Assume that we have a pattern like the following: ([n][letter])+ in which n is an integer number and letter is one of the lowercase letters from a-z. For example, 2a and 3b are valid expressions based on our pattern. Also, “+” at the end of the pattern means that we have at least one expression (string) or more than one expression attached. For instance, 2a4b is another valid expression which is matched with the pattern. In this question, we want to convert these valid expressions to a string in which letters are repeated n times.
o Read an expression (string) from user and print the converted version of the expression in the output.
o Check if input expression is valid. For example, 2ab is not a valid expression. If the expression is not valid, print “Invalid” in the output and ask user to enteranother expression.
o Sample input1 = “2a”, output = aa
o Sample input2 = “2a3b”, output = aabbb
o You will receive extra credit if you briefly explain what concept or theory you can use to check whether an expression is valid or not.
What I have so far:
#include <stdio.h>
int main()
{
int size, i, j;
char pattern[20];
char vowel[20];
int count[20];
printf("Please enter your string: ");
gets(pattern);
size = strlen(pattern);
for(i=0; i<size; i++)
if((i+1)%2 == 0)
vowel[i] = pattern[i];
else if((i+1)%2 != 0)
count[i] = pattern[i];
for(i=0; i<size/2; i++);
for(j=0; j<count[i]; j++)
printf("%s", vowel[i]);
}
I assumed you want to write the "invalid\n" string on stderr. If not just change the file descriptor given to write.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INPUT_SIZE 20
int
check_input(char *input)
{
while (*input)
{
if (*input < '0' || *input > '9')
{
write(2, "invalid\n", 8);
return 1;
}
while (*input >= '0' && *input <= '9')
input++;
if (*input < 'a' || *input > 'z')
{
write(2, "invalid\n", 8);
return 1;
}
input++;
}
return 0;
}
void
print_output(char *input)
{
int i;
while (*input)
{
i = atoi(input);
while (*input >= '0' && *input <= '9')
input++;
for (; i > 0; i--)
write(1, input, 1);
input++;
}
write(1, "\n", 1);
}
int
main()
{
char input[MAX_INPUT_SIZE];
do
{
printf("Please enter your string: ");
fgets(input, MAX_INPUT_SIZE, stdin);
input[strlen(input) - 1] = '\0';
}
while (check_input(input));
print_output(input);
return 0;
}
The steps are:
Read pattern
Check if pattern is valid
Generate output
Since the input length is not specified you have to assume a maximum length.
Another assumption is n is a single digit number.
Now you may read the whole expression with fgets() or read it char by char.
The latter allows you to check for validity as you read.
Lets use fgets() for convenience and in case the expression needs to be stored for later use.
char exp[100]; // assuming at most 50 instances of ([n][letter])
int len;
printf("Input: ");
fgets(exp, 100, stdin);
len = strlen(exp) - 1; // Discard newline at end
An empty input is invalid. Also a valid expression length should be even.
if (len == 0 || len%2 != 0) {
printf("Invalid-len\n");
return 1;
}
Now parse the expression and separately store numbers and letters in two arrays.
char nums[50], letters[50];
invalid = 0;
for (i = 0, j = 0; i < len; i += 2, j++) {
if (exp[i] >= '1' && exp[i] <= '9') {
nums[j] = exp[i] - '0';
} else {
invalid = 1;
break;
}
if (exp[i+1] >= 'a' && exp[i+1] <= 'z') {
letters[j] = exp[i+1];
} else {
invalid = 1;
break;
}
}
Notice that in each iteration if first char is not a number or second char is not a letter, then the expression is considered to be invalid.
If the expression is found to be invalid, nothing to do.
if (invalid) {
printf("Invalid\n");
return 1;
}
For a valid expression run nested loops to print the output.
The outer loop iterates for each ([n][letter]) pattern.
The inner loop prints n times the letter.
printf("Output: ");
for (i = 0; i < len/2; i++) {
for (j = 0; j < nums[i]; j++)
printf("%c", letters[i]);
}
This is a rather naive way to solve problems of this type. It is better to use regular expressions.
C standard library doesn't have regex support. However on Unix-like systems you can use POSIX regular expressions.
like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define prompt "Please enter your string: "
void occurs_error(const char *src, const char *curr){
printf("\nInvalid\n");
printf("%s\n", src);
while(src++ != curr){
putchar(' ');
}
printf("^\n");
}
bool invalid(char *pattern){
char *p = pattern;
while(*p){
if(!isdigit((unsigned char)*p)){//no number
occurs_error(pattern, p);
break;
}
strtoul(p, &p, 10);
if(!*p || !islower((unsigned char)*p)){//no character or not lowercase
occurs_error(pattern, p);
break;
}
++p;
}
return *p;
}
int main(void){
char pattern[20];
while(fputs(prompt, stdout), fflush(stdout), fgets(pattern, sizeof pattern, stdin)){
pattern[strcspn(pattern, "\n")] = 0;//chomp newline
char *p = pattern;
if(invalid(p)){
continue;
}
while(*p){
int n = strtoul(p, &p, 10);
while(n--)
putchar(*p);
++p;
}
puts("");
}
}
First question: Can I send the type to a function?
Example if I write a generic function that works for any type.
And the second question:
I want to write a function to make sure that I read one of the following data types: int, float, double, long long.
Here's how I want it to work if I read an int:
If I enter "abcd" the function will print a message asking to enter a valid int number.
If I enter "123abc" the function will print a message asking to enter a valid int number.
The only valid cases are :
If I enter "123"
or
If I enter "123 456" in this case the function will read only the first number letting the second one in buffer.
Here is my code for this function:
int citesteNumar(char mesaj[])
{
char c;
int nr=0;
int semn = 1;
int cifre = 0;
bool ok = false;
while(1)
{
nr = 0;
while(1)
{
c = getchar();
if(c == ' ' && !ok)
continue;
if((((c < '0') || ('9' < c)) && (c != '-')) || (c == '\n'))
{
if(c != ' ')
fflush(stdin);
if((c != '\n') && (c != ' ') && ok)
ok = false;
break;
}
else if(c == '-')
{
if(!ok)
semn = -1;
else
{
fflush(stdin);
break;
}
}
else
{
nr = nr*10 + (c - '0');
ok = true;
cifre ++;
if(cifre == 10)
break;
}
}
if(!ok)
printf("%s",mesaj);
else return semn*nr;
}
return -1;
}
Can I write a generic function to read this types: int, float, double, long long ?
The first invalid case it can be solved using the value returned by scanf function but I don't know how to solve the second case (only with the method above).
And the function needs to be portable.
#include <stdio.h>
#include <stdlib.h>
#define PROC(type) \
if(*endp){\
printf("enter a valid " #type " number.\n");\
return NULL;\
}\
if(ret = malloc(sizeof(v)))\
*(type*)ret = v;\
/**/
void *GetNumber(const char *type){
void *ret = NULL;
char temp[32], *endp;
scanf("%31s", temp);
if(strcmp("int", type)==0){
int v = strtol(temp, &endp, 10);
PROC(int)
} else if(strcmp("long long", type)==0){
long long v = strtoll(temp, &endp, 10);
PROC(long long)
} else if(strcmp("float", type)==0){
float v = strtod(temp, &endp);
PROC(float)
} else if(strcmp("double", type)==0){
double v = strtod(temp, &endp);
PROC(double)
}
return ret;
}
int main(){
int *vi;
float *vf;
while((vi = GetNumber("int")) == NULL)
;
printf("%d\n", *vi);
free(vi);
if(vf = GetNumber("float"))
printf("%f\n", *vf);
free(vf);
return 0;
}
No you can't send the type, but you can send an enum :
typedef enum {
MY_NONE,
MY_INT,
MY_FLOAT,
MY_DOUBLE,
MY_LL
} Mytype;
In your function, use a switch on the enum. Plus, use sscanf on your buffer, with the corresponding format. You will get troubles to read an int with a blank inside; perhaps look at the locale, you might find solutions.
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);
...