Related
I tried to make calculator supporting brackets, but
I have no idea how to deal if the user's input includes expression with spaces, for example:
input: (2 + 3) * 2
i got: 2
If it's normally get (2+3)*2, it counts 10
.
My code:
#include <stdio.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
scanf("%s", str);
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
`
str ++; /* point to the next character of the expression */
}
`
printf("%d\n",operand[0]); /*output result*/
return 0;
I tried to count the equation even if there is a space in it. Can someone please help?
Solving the problem by removing spaces:
So if you're working with equation as string you can simply remove spaces with function like this (there will be probably better way or function in library string.h but this was first guess):
char* DeleteSpaces( char* stringWithSpaces, size_t lengthOfString)
{
char* stringWithoutSpaces = (char*)calloc(lengthOfString + 1, sizeof(char));
if( !stringWithoutSpaces )
return NULL;
for( unsigned int x = 0, y = 0; x <= lengthOfString; x++, y++ )
{
if( stringWithSpaces[x] == ' ' ) // if the character is space
{
while( stringWithSpaces[x] == ' ' && x < lengthOfString ) // skip all the spaces OR go away before you hit '\0'
x++;
stringWithoutSpaces[y] = stringWithSpaces[x]; // then copy next character into new string
}
else // if there's no space just copy the character
stringWithoutSpaces[y] = stringWithSpaces[x];
}
return stringWithoutSpaces;
}
This will basically remove all spaces from your received equation. If you really need the smallest possible memory requirement you can use realloc() at the end of the function for more optimal memory usage.
Here's simple example of how to use the function so you can test it:
int main()
{
char firstString[] = "H e l l o w o r l d\0";
char* secondString;
secondString = DeleteSpaces( firstString, strlen(firstString) );
if( !secondString )
return -1;
printf( "%s", secondString );
free( secondString );
return 0;
}
Don't forget to use free(SecondString). I hope I helped you atleast a little :)
As with the previous answer, I added in a function to remove any spaces from the entered formula in order to process the requested calculation. Also, coupled with that, I revised the "scanf" input to read in all of the entered characters which looked to be another symptom you were facing. With that, following is a refactored version of your program with the additional space compression function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Testing out your sample formula with some additional spacing to ensure the compression function was working properly, following was the terminal output.
#Vera:~/C_Programs/Console/Calculate/bin/Release$ ./Calculate
(2 + 3) * 2
10
Give that a try and see if it meets the spirit of your project.
As pointed out in the comments and other answers, the solution may be to simply "compact" the spaces out of the string before trying to analyse the string's content.
This doesn't require a lot of code:
#include <stdio.h>
char *stripSP( char *src ) {
for( char *d = src, *s = src; ( *d = *s ) != '\0'; s++ )
d += *d != ' ';
return src;
}
int main( void ) {
char *s[] = { "Hello", "H e l l ooo", "(2 + 5) * 3" };
for( int i = 0; i < 3; i++ ) {
printf( "From '%s' ", s[i] );
printf( "'%s'\n", stripSP( s[i] ) );
}
return 0;
}
From 'Hello' 'Hello'
From 'H e l l ooo' 'Hellooo'
From '(2 + 5) * 3' '(2+5)*3'
Even more compact would be to use array indexing:
char *stripSP( char s[] ) {
for( int f=0, t=0; (s[t] = s[f++]) != '\0'; t += s[t] != ' ' ) {}
return s;
}
I tried to make simple calculator supporting brackets and classic operators +,-,*,/ and I also need to eliminate division by zero in it. I may not be able to cope with it, I need to check if there is division by zero in the expression and if so function return 0. Now it returns Floating point exception. Can someone help?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Thanks for all answers
I would detect if the divisor is zero along these lines:
else if(oper[*top_oper] == '/')
{
value = num_1 ? num_2 / num_1 : 0;
}
or perhaps more verbose:
else if(oper[*top_oper] == '/')
{
if(num_1)
value = num_2 / num_1;
else
value = 0;
}
and example session:
1 / 2
0
I am Writing a simple calculator that accepts arguments from command line and evaluates the string.
Intentionally, it should accept the mathematical expression and evaluate it but it throws some errors while running it. However it gets compiled successfully.
It throws following errors:-
Segmentation fault
free(): double free detected in tcache 2
Aborted
realloc(): invalid next size
Aborted
Here is my calc.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include"replace.h"
#define EXPL 200 //expression lenght
#define MAXLEN 512
#define HAFLEN 256
void DisplayHelp(void);
int validate(char*);
int issign(char);
char* evaluate(char*);
long double calculate(char*);
long double getNext(char*);
long double getPrev(char*, char*);
int calcValidate(char*);
void operate(char*, char);
int issign(char);
long double strtonum(char*);
void DisplayHelp(){
char str[] = "calc <expression>\n"\
"expression: it is the mathematical expression that is to be calculated or evaluated.\n"\
"You can also use just 'calc' without any argument to start a calculator program.\n";
printf("%s\n",str);
}
int issign(char s)
{
char signs[8] = "-+/*^";
if(strchr(signs, s))
return 1;
return 0;
}
int validate(char *src)
{
char *init = src;
//check if all the characters are acceptable
while (*src){
if(
isdigit(*src)
|| *src == '(' || *src == ')'
|| *src == '.' || *src == '+'
|| *src == '-' || *src == '^'
|| *src == '/' || *src == '*'
)
src++;
else{
puts(init);
printf("Expression Contains Illegal Character at position %d.\n", (int)(src - init) + 1);
return 0;
}
}
//check if there is brace after operator
src = init;
if(strstr(src, "-)") || strstr(src, "+)")
|| strstr(src, "/)") || strstr(src, "*)")
|| strstr(src, "^)")){
printf("Expected a number after after operator. Got brace ')'\n");
return 0;
}
//check missing brackets
int hasBrace = 0;
if(strchr(src, '('))
hasBrace = 1;
src = init;
int brace = 0;
while(*src){
if(*src == '(')
++brace;
else if(*src == ')')
brace -= 1;
++src;
}
if(brace){
printf("%d Missing braces\n", brace);
return 0;
}
//check for missing operator after or before braces and add multiply operator in between
if(hasBrace){
//first count how many * should be inserted and store the index
src = init;
int insCount = 0;
int index[(int)strlen(src)];
// printf("%ld size of array, %ld\n", sizeof(index)/sizeof(int), strlen(init));
while(*src){
if(*src == '(' || *src == ')'){
if(*src == '('){
if(src != init) --src;
if(isdigit(*src)){
index[insCount] = (int)(src - init) + 1; // index of (
++insCount;
}
++src;
}
else if(*src == ')'){
++src;
if(isdigit(*src) || *src == '('){
index[insCount] = (int)(src - init);
++insCount;
}
--src;
}
}
++src;
}
//now insert * in the indexed position
src = init;
char *tmp = (char*)malloc(((int)strlen(src) + insCount + 1) * (int)sizeof(char)); //+1 for \0
if(tmp == NULL)
exit(-1);
strcpy(tmp, src);
//store how many * added as it will change the other stored index in the array
int added = 0;
for(int i = 0; i < insCount; ++i){
char *ret = insert(tmp, "*", index[i] + added);
strcpy(tmp, ret);
++added;
free(ret);
}
src = realloc(src, strlen(tmp) + 1);
strcpy(src, tmp);
free(tmp);
}
//check for empty braces
src = init;
if(hasBrace){
while(*src){
if(*src == '('){
++src;
if(*src == ')'){
printf("Empty braces.\n");
return 0;
}
--src;
}
src++;
}
}
//check if expression contains operators in invalid place
if(!calcValidate(init)){
puts("Got unexpected operator(s) at unexpected place");
return 0;
}
return 1;
}
char* evaluate(char *exp)
{
//since we will insert every result of evaluation in the exp, it may contain exp and resutl or brac exp like 3^4^3 so very long
exp = realloc(exp, MAXLEN);
if(!exp)
exit(-1);
char *init = exp;
long expl = strlen(exp);
//count total open brackets
int brace = 0;
while(*exp){
if(*exp == '(')
++brace;
++exp;
}
exp = init;
int isWholeInsideBrace = 0;
if(*exp == '(')
isWholeInsideBrace = 1;
if(brace){
for(int i = brace; i > 0; --i){
int bracth = 0; //nth brace e.g. 4th brace
char bracexp[MAXLEN] = "";
char curAns[MAXLEN] = ""; //store current ans, later replace bracexp in exp with it
char *bracclos = "";
while(*exp){
if(*exp == '('){
++bracth;
if(bracth != i){
++exp;
continue;
}
bracclos = strchr(exp, ')');
strncpy(bracexp, exp, bracclos - exp + 1); //copy from '(' to ')'
snprintf(curAns, MAXLEN, "%.256Lg", calculate(bracexp));
char *replExp = replace(init, bracexp, curAns, 1);
strcpy(init, replExp);
free(replExp);
// exit(0);
break;
}
++exp;
}
exp = init;
}
}
if(!isWholeInsideBrace){
snprintf(exp, MAXLEN, "%.256Lg", calculate(exp));
}
return exp;
}
long double calculate(char* expre)
{
char tmp[MAXLEN] = "";
long double ans = 0.0;
char* ptr = tmp;
//remove brace from if exist
while(*expre){
if(*expre != '(' && *expre != ')'){
*ptr = *expre;
++ptr;
}
++expre;
}
*ptr = '\0';
ptr = tmp;
if(strchr(tmp, '^'))
operate(tmp, '^');
if(strchr(tmp, '/'))
operate(tmp, '/');
if(strchr(tmp, '*'))
operate(tmp, '*');
// for + and - need to check if there is only one number, else infinite loop
if(strchr(tmp, '+') )
operate(tmp, '+');
if(strchr(tmp, '-') )
operate(tmp, '-');
//if the exp does not contain any signs means it if already calculated or it is single number
return atof(tmp);
}
void operate(char *temp, char sign)
{
long double num1 = 0;
long double num2 = 0;
char curExp[MAXLEN] = "";
char curAns[MAXLEN] = "";
char *replaced;
char *oper;
long double ans = 0;
while((oper = strchr(temp,sign))){
num1 = getPrev(temp, oper);
num2 = getNext(oper);
if(sign == '^')
ans = pow(num1, num2);
else if(sign == '/')
ans = num1 / num2;
else if(sign == '*')
ans = num1 * num2;
else if(sign == '+')
ans = num1 + num2;
else if(sign == '-')
ans = num1 - num2;
//if first letter is + or - , getPrev returns 0 so ignore it
//check and specify the format
char secfor[15] = "";
char ansfor[10] = "";
if(oper == temp && !isdigit(*oper))
snprintf(curExp, MAXLEN,((int)num2 == num2)? "%c%.0Lf" : "%c%.4Lf", *oper, num2);
else{
int a,b;
a = (int)num1;
b = (int)num2;
if(a == num1 && b == num2)
strcpy(secfor, "%.0Lf%c%.0Lf");
else if(a == num1)
strcpy(secfor, "%.0Lf%c%.4Lf");
else if(b == num2)
strcpy(secfor, "%.4Lf%c%.0Lf");
else
strcpy(secfor, "%.4Lf%c%.4Lf");
snprintf(curExp, MAXLEN, secfor, num1, *oper, num2);
}
snprintf(curAns, MAXLEN,((int)ans == ans)? "%.0Lf" : "%.4Lf", ans);
replaced = replace(temp, curExp, curAns, 1);
// printf("%s\n%s\t%s\n%s\n", temp, curExp, curAns, replaced);
strcpy(temp, replaced);
printf("new temp: %s\n\n", temp);
free(replaced);
//special cases:-
//if first letter is + or - and there is only one number, so break the loop
if(sign == '+' || sign == '-'){
char *ptr = temp;
if(sign == '+'){
if(strrchr(temp, '+') == ptr && !strchr(temp, '-'))
break;
}
else if(sign == '-'){
if(strrchr(temp, '-') == ptr)
break;
}
}
}
}
int calcValidate(char *val)
{
char *point = val;
char first = *point;
//take pointer to end of string
point = strchr(point, '\0');
--point;
char last = *point;
point = val;
if(!isdigit(first) && (first != '-' || first != '+'))
return 0;
else if(!isdigit(last) && last != '(' && last != ')')
return 0;
//check whether operators are doubled
int doubled = 0;
while(*point){
if(isdigit(*point) || *point == '(' || *point == ')')
doubled = 0;
else if(issign(*point)){
if(doubled)
return 0;
doubled = 1;
}
++point;
}
return 1;
}
long double getNext(char* pos)
{
char *tmp = pos;
//pos is the position of operator, ignore it, and return numbers from it to next operator
++tmp;
return strtonum(tmp);
}
long double getPrev(char* str, char* pos)
{
char *tmp = str;
char *tmpp = pos;
//if + or - is at first, return 0
if(tmpp == str)
return 0;
--tmpp;
while(tmpp != str && isdigit(*tmpp))
--tmpp;
//tmpp now is the position of operator , so get number between this operator to another operator i.e. pos
if(tmpp != str)
++tmpp;
return strtonum(tmpp);
}
long double strtonum(char* s)
{
char *ptr = s;
char sign = '\0';
long double beforeDecimal = 0.0;
float afterDecimal = 0.0;
float a, c = 10;
int exp = 1;
if(*ptr == '+' || *ptr == '-'){
sign = *ptr;
++ptr;
}
while(isdigit(*ptr)){
a = *ptr - '0';
beforeDecimal = beforeDecimal * c + a;
++ptr;
}
if(*ptr == '.'){
++ptr;
while(isdigit(*ptr)){
a = *ptr - '0';
afterDecimal = afterDecimal + a/pow(c, exp);
++exp;
++ptr;
}
}
beforeDecimal += afterDecimal;
if(beforeDecimal){
if(sign && sign == '-')
beforeDecimal = -beforeDecimal;
return beforeDecimal;
}
return 0;
}
int main(int argc, char const *argv[])
{
//parse and store the expression for calculation
char *exp = (char*)malloc(sizeof(char) * (EXPL +1)); // 1 is for null terminator \0
if(exp == NULL)
exit(-1);
int count = 1; //extra 1 will store \0
int i = 1, j = 1;
// check whether argument are supplied
if(argc < 2)
return 0;
//calculate the total size of arguments
while(j < argc){
count += strlen(argv[j]);
++j;
}
char *temp = malloc(sizeof(char) * count);
if(!temp) exit(-1);
//copy all arguments to temp
for(i = 1; i < argc; ++i)
strcat(temp, argv[i]);
//check if the expression contains whitespaces
//first check if it contains multiline argument and make it single line
//then remove whitespaces
if(strstr(temp," ") || strstr(temp, "\n")){
char *tmp = temp;
char *init = temp;
while(*temp != '\0'){
//remove all the \n
if(*temp != ' ' && *temp != '\n'){
*tmp = *temp;
++tmp;
}
++temp;
}
*tmp = '\0';
temp = init;
}
// check if the expression is within the limit i.e EXPL
if(count > EXPL){
printf("Expression is too long;\nMax %d digits.\nGiven %d\n ", EXPL, count);
return 1;
}
else
strcpy(exp, temp);
free(temp);
if(!validate(exp)){
free(exp);
return 1;
}
//since the expression is ready to be evaluated, let's evaluate it to produce the result
evaluate(exp);
puts(exp);
free(exp);
return 0;
}
here is replace.c
#include"replace.h"
char *replace(char *str,char *substr, char *seed, int recursive)
{
char *firstPos = strstr(str, substr);
if(!firstPos)
return NULL;
long size = 0;
long strS, substrS, seedS, occurance;
strS = substrS = seedS = occurance = 0;
//calculate length of substr, seed and str
strS = strlen(str);
substrS = strlen(substr);
seedS = strlen(seed);
//declare a __temp string variable
char *__tmp = malloc(strS + 1);
if(!__tmp){
puts("memory allocation failed!");
return NULL;
}
//calculate the size of string required to hold the replaced string and replace its occurence
if(!recursive){
size = strS + (seedS - substrS);
__tmp = realloc(__tmp, size + 1);
if(!__tmp)
return NULL;
//remove substr and store its index
long ind = (long)(firstPos - str);
strncpy(__tmp, str, ind);
__tmp[ind] = '\0';
strcat(__tmp, firstPos + substrS);
if(!seedS)
return __tmp;
return insert(__tmp, seed, ind);
}
else if(recursive){
//count the occurance of substr
strcpy(__tmp, str);
char* pos;
while((pos = strstr(__tmp, substr))){
size = strlen(__tmp) + (seedS - substrS);
long ind = (long)(pos - __tmp);
__tmp = realloc(__tmp, size + 1);
char *__temp = malloc(size + 1);
if(!__tmp || !__temp)
return NULL;
strcpy(__temp, __tmp);
// printf(">%s\n",__tmp);
strncpy(__tmp, __temp, ind);
__tmp[ind] = '\0';
// printf(">>%s\n",__tmp);
strcat(__tmp, __temp + ind + substrS);
// printf(">>>%s\n",__tmp);
free(__temp);
if(seedS){
__temp = insert(__tmp, seed, ind);
strcpy(__tmp, __temp);
free(__temp);
}
}
return __tmp;
}
return NULL;
}
char *insert(char *str, char *sed, int index)
{
int strl, sedl;
strl = (int)strlen(str);
sedl = (int)strlen(sed);
char *dest = (char*)malloc(sizeof(char) * (strl + sedl +1));
if(dest == NULL) return NULL;
strncpy(dest, str, index );
dest[index] = '\0';
strcat(dest, sed);
strcat(dest, str + index);
return dest;
}
and here is the test file
test.py
from ast import Return
import subprocess as sp
tests = ["243 + 45*3 -43 + 45/9 + 6^6",
"34 + 23 -54 + '6(76(32(56 + 45 -34(56- 34)) + 44)) *' 45 -7 ^ 5 - 4",
"43 + 3.543 - 543.36 - 56.84*23.456 + 18/5 - '45.465(56 + 45 -34(59- 24))63.86' + 34",
"5 ^ 3.543 - 543.36 - 56.84*23.456 + 18/5 - '45.465(56 + 45 -34(65- 41))63.86' + 3.345 ^ 4.65 + 456 - 29/3 ^ 2.34 - 11/4 ^ 3",
'''23 + 345- 240*4 + '6+ 4 * 4' - '(5-2) / (4+ (5-3))' *6 + "45 - 23 +24 * (3+(4+3))
+987543-45345+8635
6453354 --"''',
'''23*240*4 *'6+ 4 * 4 - (5-2) (4+ (5-3))' "45345 - 8(4+3) + 3(5-2)6 - (7+5)4 - 6(5+3^2)9 (5 * 4 -6)5 ^7" - 6 + "45 - 23 +24 * (3+(4+3))(6)"''',
" '54( 34 + 34 - 23 + 34/12 + 3 ^4)'",
" '5+54+( 34 + 34 - 23 + 256/16^2*8 + 34) - 32'",
" '69( 31 + 4 - 23 + 72/6^2*8 + 34) - 32'",
" '5+54+ 34 + 34 - 23 + (8) - 32'"
]
com = sp.run("gcc calc.c replace.c -o calc -lm", shell = True, capture_output = True, text = True)
if (com.returncode):
print(com.stderr)
exit(0)
print("~~~Compiled Successfully~~~")
for test in tests:
ret = sp.run("./calc " + test,shell=True, capture_output = True, text = True)
if(ret.stderr):
print(ret.stderr)
else:
print(ret.stdout)
Everything works fine, in the file replace.c, (tested it many time)
the error occurs in the function
evaluate()
calculate() and
operate()
in the calc.c file.
Compiles without warnings or errors, just the following code crashes when I try to either read from or write to the matrix constValues.
It needs to be passed to another function to be read from also; the function createOutputLine.
How can I point to the data held correctly so it can be modified and read from? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
void createOutputFile(FILE*, int, char**);
char createOutputLine(int, int, char*, char**);
int main(int argc, char **argv) {
int removeComments = 0;
FILE *file;
if (argc > 1 && strcmp(argv[1], "-i") == 0) {
if (argc > 2) {
if (!(file = fopen(argv[2], "r"))) {
printf("Error: file not found");
return -1;
}
}
else {
printf("Error: no file specified");
return -1;
}
}
else {
printf("Error: command requires -i");
return -2;
}
createOutputFile(file, argc, argv);
fclose(file);
}
void createOutputFile(FILE *file, int argc, char **argv) {
fseek(file, 0, SEEK_SET);
char *data = (char*)malloc(2000);
FILE *header;
char name[20];
char *token = strtok(argv[2], ".");
strcpy(name, strcat(token, ".o"));
FILE *output = fopen(name, "w");
char constNames[10][15];
char **constValues[10][10];
int constsStored = 0;
while (fgets(data, 2000, file) != NULL) {
for (int i = 0; i < strlen(data); i++) {
int c = i;
bool linePrinted = false;
if (data[i] == '#' && data[i + 1] == 'd') {
for (c = i; c <= i + 7; c++) {
data[c] = '\0';
} int ch = 0;
while (data[c] != ' ') {
constNames[constsStored][ch] = data[c];
data[c] = '\0';
ch++;
c++;
} ch = 0;
while (data[c] != '\n') {
**constValues[constsStored][ch] = data[c]; //this line crashes
data[c] = '\0';
ch++;
c++;
}
if (data[c] == '\n') data[c] = '\0';
constsStored++;
}
for (int ch = 0; ch <= constsStored; ch++) {
if (data[i] == constNames[ch][0]) {
int ch2 = i + 1;
int ch3 = 1;
bool isConst = false;
while (data[ch2] != ' ') {
if (data[ch2] == constNames[ch][ch3] && isConst == false) isConst = true;
ch2++;
ch3++;
}
if (isConst || data[i + 1] == ' ') {
char line[200];
line[200] = createOutputLine(i, ch, data, **constValues);
fprintf(output, "%c", line[200]);
linePrinted = true;
}
}
}
if (!linePrinted)
fprintf(output, "%c", data[i]);
}
}
fclose(output);
free(data);
}
char createOutputLine(int i, int constElem, char *data, char **constValues) {
int ch = i;
int ch2 = 0;
char temp[200];
while (data[ch] != '\n' && data[ch] != ' ' && data[ch] != ';') {
temp[ch2] = data[ch];
printf("%c", data[ch]);
ch++;
ch2++;
}
char line[200];
ch2 = 0;
for (ch = i; ch <= sizeof(data); ch++) {
line[ch2] = data[ch];
ch2++;
}
for (ch = 0; ch <= 10; ch++) {
line[ch2] = constValues[constElem][ch];
ch2++;
}
for (ch = 0; ch <= sizeof(temp); ch++) {
line[ch2] = temp[ch];
ch2++;
}
line[ch2 + 1] = '\n';
return line[200];
}
A pointer shall point to an object before it can be derefenced. Full stop.
char **constValues[10][10]; just declares an 2D array of pointers to pointers to characters. And as it is an automatic array (neither statically nor dynamically allocated), its pointers are just uninitialized.
When you late use **constValues[constsStored][ch] = data[c];, you try to dereference an uninitialized pointer which is explicitely Undefined Behaviour. You are lucky to get an immediate crash, because UB consequences can be apparently unrelated problems.
The normal way is to declare arrays of objects, and use the addresses of those objects for pointers.
That's not all: C arrays are not first class citizens. You cannot assign to array, nor return it from a function. So this is plain wrong:
char line[200];
line[200] = createOutputLine(i, ch, data, **constValues);
It just assigns the unique character returned by the function past the end of the array!
So is this:
char line[200];
...
return line[200];
It does not return an array (C does not allow it) but the value of the byte that happens to live past the array.
I am sorry, but there are too many errors for me to fix them is such a long program.
You may find C hard and ask for help. But build small code containing only what you want to work on. And only when those small pieces work correctly, try to assemble them in a larger program.
I have this code:
FILE *fr,*fr2,*fr3;
fr = fopen("med.txt","r");
fr2 = fopen("moje.txt","w");
fr3 = fopen("zaloha.txt","rw");
int pRadku, nc, inword, pMezery;
int pSlov = 0;
inword = 0;
pRadku = 1;
inword = 0;
int radky = 20;
int sloupce = 50;
nc = pMezery = 0;
int pocitadlo = 0;
int pocitadlo2 = 0;
int i,j;
char c;
int tex = 255;
char text;
for(i= 0; i<tex ;i++){
text[i]='\0';
}
char **pole;
int pocet = 1000;
char *p_pom1, *p_pom2, **p_nove;
pole = (char **)malloc(pocet * sizeof(char));
for(i=0; i<pocet; i++){
pole[i] = (char*)malloc(tex * sizeof(char));
}
while(( c=fgetc(fr)) != EOF){
++nc;
if(c == '\n'){
++pRadku;
}
if(c ==' '){
pMezery++;
}
if(c == ' ' || c == '\n' || c == '\t'){
inword = 0;
}else if(inword == 0){
inword = 1;
++pSlov;
}
if(pocitadlo >= (pocet-1)){
int pomPocet = pocet;
pocet+=1000;
pole = (char **)realloc(pole, pocet * sizeof(char));
}
if((c != ' ')){
if(c != '\0'){
if(c != '\n'){
if(c != '\t'){
if(c != '.'){
if(c != ','){
text[pocitadlo2]=c;
pocitadlo2++;
}
}
}
}
}
}
if((c == ' ')){
text[pocitadlo2] = '\0';
for(i=0;i<tex;i++){
pole[pocitadlo][i] = text[i];
}
for(i=0;i<tex;i++){
text[i]='\0';
}
pocitadlo2=0;
pocitadlo++;
}else if(c == '\0'){
text[pocitadlo2] = '\0';
for(i=0;i<tex;i++){
pole[pocitadlo][i] = text[i];
}
for(i=0;i<tex;i++){
text[i]='\0';
}
pocitadlo2=0;
pocitadlo++;
}else if(c == '\n'){
text[pocitadlo2] = '\0';
for(i=0;i<tex;i++){
pole[pocitadlo][i] = text[i];
}
for(i=0;i<tex;i++){
text[i]='\0';
}
pocitadlo2=0;
pocitadlo++;
}else if(c == '.'){
text[pocitadlo2] = '\0';
for(i=0;i<tex;i++){
pole[pocitadlo][i] = text[i];
}
for(i=0;i<tex;i++){
text[i]='\0';
}
pocitadlo2=0;
pocitadlo++;
}else if(c == ','){
text[pocitadlo2] = '\0';
for(i=0;i<tex;i++){
pole[pocitadlo][i] = text[i];
}
for(i=0;i<tex;i++){
text[i]='\0';
}
pocitadlo2=0;
pocitadlo++;
}
}
and my question is do I expand my 2 dimensional array properly? Or should do it some different way?
This program read 300 000 words from a file and saving them in to an array.
thx for your time.
EDIT**
int row = 5;
int column = 5;
int countr = 0;
int countr2 = 0;
int c;
int **array;
array = (int **)malloc(size * sizeof(int*));
for(i=0; i<row; i++){
pole[i] = (int*)malloc(column * sizeof(int*));
}
while(read letters form file (c=fgetc()) != EOF{
if(coutr>=(size-1)){
row+=10;
array = (int **)realloc(array, row * sizeof(int*));
}
array[countr][countr2] = c;
countr2++;
if(c == '\0' || c == ' '){
countr2=0;
countr++;
}
}
This code is so broken as to be impossible to diagnose what's wrong. As an example,
int tex = 255;
char texttex
for(i= 0; tex ;i++){
text[i]='\0';
}
is missing a semicolon after char texttex and is an infinite loop since tex is always 255. Please provide a complete minimal compilable code. If you expect others to spend time for you, you should start by spending some of your time for us. Thank you.
Wrong size is passed to malloc function: sizeof(char) that should be sizeof(char*):
pole = (char **)malloc(pocet * sizeof(*char));
sizeof(char) != sizeof(char*) and also don't use type cast for malloc().
And similar error I can see in your code in realloc :
error at: pole = (char **)realloc(pole, pocet * sizeof(char));
also a syntax error, ; is missing :
char texttex