Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Tempermental C code crashing after input of 24 or greater characters!?

Tempermental C code crashing after input of 24 or greater characters!?
Thread Tools
Ghoser777
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status: Offline
Reply With Quote
Jun 15, 2002, 05:11 PM
 
Okay, so I found this very basic regular math expression parser, and it works great!... except that if you enter an expression long enough (about 25 characters in length) it dies. The code isn't that complicated, but I can't see where the crash is happening.

Anyone see what's wrong?

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">
/* file calcu.c */
/* (c) Donald Axel GPL - license */
/* ANSI - C program demonstration, command line calculator */
/* Recursive descent parser */
/* Improve: Make a HELP command. Add more variables. */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;math.h&gt;
#include &quot;calcu.h&quot;

#define stricmp strcasecmp
#define strnicmp strncasecmp

#define MAXL 8196
char gs[MAXL];
char *cp;
char *errorp;
double oldval;


int nextchar()
{
++cp;
while (*cp == ' ')
++cp;
return *cp;
}


int eatspace()
{
while (*cp == ' ')
++cp;
return *cp;
}


/* More local prototypes. This could, of course, be a separate file. */
double expression();
double product();
double potens();
double signedfactor();
double factor();
double stdfunc();


int evaluate(char *s, double *r)
{
cp = s;
eatspace();
*r = expression();
eatspace();
if (*cp == '\n' &amp;&amp; !errorp)
return (0);
else
return (cp - s) + 11;
}


double expression()
{
double e;
int opera2;

e = product();
while ((opera2 = *cp) == '+' &#0124;&#0124; opera2 == '-') {
nextchar();
if (opera2 == '+')
e += product();
else
e -= product();
}
eatspace();
return e;
}


double product()
{
double dp;
int ope;

dp = potens();
while ((ope = *cp) == '*' &#0124;&#0124; ope == '/') {
nextchar();
if (ope == '*')
dp *= potens();
else
dp /= potens();
}
eatspace();
return dp;
}


double potens()
{
double dpo;

dpo = signedfactor();
while (*cp == '^') {
nextchar();
dpo = exp(log(dpo) * signedfactor());
}
eatspace();
return dpo;
}


double signedfactor()
{
double ds;
if (*cp == '-') {
nextchar();
ds = -factor();
} else
ds = factor();
eatspace();
return ds;
}


double factor()
{
double df;

switch (*cp) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
df = strtod(cp, &amp;cp);
break;
case '(':
nextchar();
df = expression();
if (*cp == ')')
nextchar();
else
errorp = cp;
break;
case 'X':
nextchar();
df = oldval;
break;

default:
df = stdfunc();
}

eatspace();
return df;
}


char *functionname[] =
{
&quot;abs&quot;, &quot;sqrt&quot;, &quot;sin&quot;, &quot;cos&quot;, &quot;tan&quot;, &quot;asin&quot;, &quot;acos&quot; &quot;atan&quot;, &quot;log&quot;, &quot;exp&quot;, &quot;sinh&quot;, &quot;cosh&quot;,
&quot;tanh&quot;, &quot;\0&quot;
};

double stdfunc()
{
double dsf;
char **fnptr;
int jj;

eatspace();
jj = 0;
fnptr = functionname;
while (**fnptr) {
if (strncmp(*fnptr, cp, strlen(*fnptr)) == 0)
break;

++fnptr;
++jj;
}
if (!**fnptr) {
errorp = cp;
return 1;
}
cp += (strlen(*fnptr) - 1);
nextchar();
dsf = factor();
switch (jj) {
case 0: dsf = abs(dsf); break;
case 1: dsf = sqrt(dsf); break;
case 2: dsf = sin(dsf); break;
case 3: dsf = cos(dsf); break;
case 4: dsf = tan(dsf); break;
case 5: dsf = asin(dsf); break;
case 6: dsf = acos(dsf); break;
case 7: dsf = atan(dsf); break;
case 8: dsf = log(dsf); break;
case 9: dsf = exp(dsf); break;
case 10: dsf = sinh(dsf); break;
case 11: dsf = cosh(dsf); break;
case 12: dsf = tanh(dsf); break;
default:{
errorp = cp;
return 4;
}
}
eatspace();
return dsf;
}


/* end calcu.c */</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">This is how I was using it:

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">+(NSString *)evaluateExpressionNSString *)string
{
char gs;
int rv;
double oldval;

[string getCString:&amp;gs];
rv = evaluate(&amp;gs, &amp;oldval);

return [NSString stringWithFormat:@&quot;%g&quot;, oldval];
}</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">Thanx in advance,
F-bacher
     
SpotBug
Fresh-Faced Recruit
Join Date: Sep 2001
Status: Offline
Reply With Quote
Jun 15, 2002, 06:38 PM
 
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">Originally posted by Ghoser777:
<strong></font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">+(NSString *)evaluateExpressionNSString *)string
{
char gs;
int rv;
double oldval;

[string getCString:&amp;gs];
rv = evaluate(&amp;gs, &amp;oldval);

return [NSString stringWithFormat:@&quot;%g&quot;, oldval];
}</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif"></strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">I could be very wrong (I have limited Objective-C experience), but this doesn't look right to me. You're trying to pass the address of the passed-in NString's buffer to evaluate(), but I don't see how you're getting that address. &gs certainly isn't the address of the string's buffer, it's the address of the single char you've got on the stack. My guess is you're call to evaluate() is trouncing on the stack.
     
Detrius
Professional Poster
Join Date: Apr 2001
Location: Asheville, NC
Status: Offline
Reply With Quote
Jun 15, 2002, 06:51 PM
 
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">Originally posted by SpotBug:
<strong> </font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">Originally posted by Ghoser777:
<strong></font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">+(NSString *)evaluateExpressionNSString *)string
{
char gs;
int rv;
double oldval;

[string getCString:&amp;gs];
rv = evaluate(&amp;gs, &amp;oldval);

return [NSString stringWithFormat:@&quot;%g&quot;, oldval];
}</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif"></strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">I could be very wrong (I have limited Objective-C experience), but this doesn't look right to me. You're trying to pass the address of the passed-in NString's buffer to evaluate(), but I don't see how you're getting that address. &gs certainly isn't the address of the string's buffer, it's the address of the single char you've got on the stack. My guess is you're call to evaluate() is trouncing on the stack.</strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">I would agree with this. You are passing the address of a single character instead of a string. Thus, you are writing over memory that you shouldn't be. gs is globally defined in the code given, and it is a HUGE array. I would recommend removing YOUR definition of gs, as this is creating a local gs that overrides the global gs. The other option is to make your local declaration of gs into a large array, somewhat like this:

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;"> char gs[5120]; </pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">then you can put 5k of text in to be evaluated.
ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
     
Ghoser777  (op)
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status: Offline
Reply With Quote
Jun 15, 2002, 07:02 PM
 
Excellent. Thank you so much! My C knowledge just grew

F-bacher
     
lindberg
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
Jun 16, 2002, 12:51 AM
 
Is there any reason this wouldn't work?

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">+(NSString *)evaluateExpressionNSString *)string
{
int rv;
double oldval;

rv = evaluate([string cString], &amp;oldval);

return [NSString stringWithFormat:@&quot;%g&quot;, oldval];
}</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">At any rate, yes, -getCString assumes that you have allocated storage for it to put the c-string into. You want to make sure that the storage size is at least [string length]+1 long, or do something like:

char gs[1024];

...

[string getCString:gs maxLength:sizeof(gs)-1];

otherwise the getCString method will write into unknown memory locations if the length is longer than you were expecting. [This is what was happening in your original code btw.]
     
   
 
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Top
Privacy Policy
All times are GMT -4. The time now is 05:09 AM.
All contents of these forums © 1995-2017 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.8 © 2000-2017, Jelsoft Enterprises Ltd.,