I'm trying to write a program that evaluates a postfix arithmetic expression. The program sends a character string to my function evaluatePostfix, which proceeds to identify operands and operators and come up with an integer solution. I am manipulating stacks in this program by pushing the scanned character as it is identified and of course doing the appropriate pop functions when needing to evaluate. Right now though, I'm having a problem with the program hanging in what appears to be an infinite loop. I guess I'm not really sure how to tell the function to proceed to the next character in the string after it has evaluated the first character. Another thing to note is that the user puts a space in-between each operand and operator. Here is my function:
int evaluatePostfix(char *postfixStr)
{
stack * s;
int x, y;
stackInit(&s);
do {
if(isOperand(postfixStr) == 1) {
stackPush(&s, postfixStr);
}
if(isOperator(postfixStr) == 1) {
y = atoi(stackPop(s));
x = atoi(stackPop(s));
char *str = malloc(10 * sizeof(char));
sprintf(str, "%d", applyOperator(x, y, postfixStr));
stackPush(&s, str);
}
} while (postfixStr != NULL);
return stackPop(s);
}
I know the functions that manipulate the stack are correct as they were provided by my instructor. Could someone perhaps give me a clue as to what I'm missing?
You could change the while condition to while (++postfixStr != NULL) to increment the pointer to the next character in postfixStr.
This increment is done using the prefix notation (++var vs var++) so that the next character is compared to NULL. I'm not familiar with the behavior of the stack functions you're using, but I would recommend changing the do { ... } while (++postfixStr != NULL); loop to a while (postfixStr != NULL) { ... } loop, and increment postfixStr at the end of that while loop's block.
The safest thing to do is add a string length parameter to your function:
int evaluatePostfix(char *postfixStr, int strLength)
You would then use a loop that explicitly steps from the beginning of the string at index 0 to index strLength - 1, which would safely handle empty and non-NULL-terminated strings.
Related
I searched for a string replacement function and found this question
What is the function to replace string in C?
If I use the code from the answer, it works but it looks wrong and gives a warning:
/home/dac/osh/util.c: In function ‘str_replace’:
/home/dac/osh/util.c:867:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
for (count = 0; tmp = strstr(ins, rep); ++count) {
It looks like it's maybe a bug with = and == . Is it a bug or did I misunderstand? Should it be == instead?
No, it's not. In this case, the value of tmp is actually intended to be used as the condition.
The return value of strstr:
char * strstr(char * str1, const char * str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
To remove the warning, try this:
for (count = 0; (tmp = strstr(ins, rep)) != NULL; ++count) {
No, it's not a bug. As per the body of the loop:
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
it actually uses tmp for something. The continuation condition in that for statement will assign the result of strstr() to tmp then execute the body as long as it's non-zero (i.e., as long as it found the string). That's because strstr() returns NULL only if the string cannot be found.
I suspect this is just gcc being paranoid in that it realises the continuation condition (the middle bit) on a for statement usually tends to be a comparison and you may have accidentally used = rather then ==.
That's why the diagnostic states warning: suggest ... rather than error: what the heck? :-) If you want to get rid of the warning (which isn't a bad position to take), simply do what it suggests and surround the entire continuation condition with parentheses.
[ strstr reference ] states the return value for char * strstr (char *str1,const char *str2 ) is :
A pointer to the first occurrence in str1 of the entire sequence of
characters specified in str2, or a null pointer if the sequence is not
present in str1.
Now for a little more C terminology, when you do :
tmp = strstr(ins, rep)
the main intent of C is to evaluate the expression as a whole and C evaluates it to the return value of strstr(ins, rep) here. The side effect is assigning this return value to tmp. The error :
suggest parentheses around assignment used as truth value
is a way gcc helps you to avoid a careless mistake, say typing a=b instead of a==b, I believe. Note that in the first case the value of b is used as truth value, but in the second case the result of is a equal b is used a truth value. By putting a () around tmp = strstr(ins, rep) you give the compiler the green signal to evaluate the value of the expression as truth value.
Side Note :
Putting () around tmp = strstr(ins, rep) makes it a full expression, and full expression is considered as a sequence point. A sequence point is a point in program execution at which all side effects are evaluated before going on to the next step.
Why exactly is a string literal in an if-condition treated as true?
if("whatiamreturning")
//this is true. I want to know y?
Based on the above, what happens here?
#include<stdio.h>
void main() {
static int i;
for(;;) { //infinite loop
if(i+++"The Matrix")
// what is happening in the above line?
printf("Memento");
else
break;
}
}
if("whatiamreturning")
is equivalent to
if (1)
This is because "whatiamreturning" is a char [] that decays into a non-NULL char const* inside the if(). Any non-NULL pointer evaluates to true in the context of a boolean expression.
The line
if(i+++"The Matrix")
can be simplified to:
if( (i++) + "The Matrix")
In the first iteration of the loop, the value of i is 0. Hence, the (i++) + "The Matrix" evaluates to "The Matrix".
In the second iteration of the loop, the value of i is 1. Hence, the (i++) + "The Matrix" evaluates to "he Matrix".
However, the loop never ends and goes into the territory of undefined behavior since (i++) + "The Matrix" never evaluates to 0 and the value of i keeps on increasing.
Perhaps they meant to use:
if(i++["The Matrix"])
which will allow the expression inside if() it to be 0 after 10 iterations.
Update
If you are following somebody else's code, stay away anything else that they have written. The main function can be cleaned up to:
int main() {
char name[] = "The Matrix";
int i = 0;
for( ; name[i] != '\0'; ++i )
{
printf("Memento\n");
}
}
if(i+++"The Matrix") // what is happening here please help here to understand
This will take the value of i, add the pointer value of the location of the string "The Matrix" in memory and compare it to zero. After that it will increase the value of i by one.
It's not very useful, since the pointer value could be basically any random number (it depends on architecture, OS, etc). And thus the whole program amounts to printing Memento a random number of times (likely the same number each run though).
Perhaps you meant to write if(*(i+++"The Matrix")). That would loop 10 times until it i+"The Matrix" evaluates to the address pointing to the NUL byte at the end of the string, and *(i+"The Matrix") will thus return 0.
Btw, spaces are a nice way to make your code more readable.
It will return the address of first element of the string whatiamreturning.
Basically when you assign a string literal to a char pointer
char *p;
p = "whatiamreturning";
the assignment doesn't copy the the characters in whatiamreturning, instead it makes p point to the first character of the string and that's why string literals can be sub-scripted
char ch = "whatiamreturning"[1];
ch will will have character h now. This worked because compiler treated whatiamreturning as a char * and calculated the base address of the literal.
if(i+++"The Matrix") is equivalent to
if( i++ + "The Matrix")
or it can be rewritten as
if(&("The Matrix"[i++]))
which will be true for every i and results in an infinite loop. Ultimately, the code will suffer from undefined behavior due to integer overflow for variable i.
Why exactly is a string literal in an if-condition treated as true?
if("whatiamreturning")
The string literal "whatiamreturning" is a constant of type char[].
In nearly all contexts, including this one, arrays decay to pointers to their first element.
In a boolean context, like the condition of an if-statement, all non-zero values are true.
As the pointer points to an object, it is not the null-pointer, and thus is true.
Based on the above, what happens here?
#include<stdio.h>
void main() {
The above is your first instance of Undefined Behavior, whatever happens, it is right.
We will now pretend the error is corrected by substituting int for void.
Now, your loop:
static int i;
Static variables are default initialized, so i starts with value 0.
for(;;) { //infinite loop
if(i+++"The Matrix")
// what is happening in the above line?
printf("Memento");
else
break;
}
This loop has Undefined Behavior as well.
The condition takes i and adds it to the string literal "Memento" which decayed to a pointer like in the previous example, interpreting the resultant pointer in a boolean context, and as a side-effect incrementing i.
As long as i is no more than strlen("The Matrix")+1 on entry, everything is ok, the pointer points to an element of the string literal or one past, and the standard guarantees that's not a null pointer.
The moment it is though, all hell breaks loose because calculating such a pointer is Undefined Behavior.
Well, now that we know the loop is UB, let's ignore the loop too.
The rest of the program is:
}
Which is ok, because even though main has a return type of int, there's a special rule which states that if control reaches the end of main without executing a return-statement, an implicit return 0; is added.
Side-note: If an execution of a program encounters Undefined Behavior anywhere, the whole program is undefined, not only from that point on:
Undefined behavior can result in time travel (among other things, but time travel is the funkiest)
I've been at this for quite some time now and the existing answers offer little to no help. I am new to programming and am trying to write a sub-part of my program which tries to check whether any given input is constituted solely of alphabets.
For this, the idea I have in mind is to pass an entire array through the isalpha function by using a loop which passes each character at a time. The idea makes logical sense but I am having syntactic trouble implementing it. I will greatly appreciate any help!
Below is my code-
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(**<what I'm putting here is creating the problem, I think>**) = true)
{
printf("%c", p[i]);
}
}
You should modify your code as this (assuming you have the string type defined yourself):
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(p[i]) == true) // HERE IS THE ERROR, YOU HAD =, NOT ==
{
printf("%c", p[i]);
}
}
Operator = is for assignment and operator == is for comparison!
So what was happening? The assignment resulted in true, no matter what p[i] was.
As Quentin mentioned:
if(isalpha(p[i]) == true)
could be more elegant and error prune if written like this:
if(isalpha(p[i]))
Here is an example in C:
/* isalpha example */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i = 0;
char str[] = "C++";
while (str[i]) // strings in C are ended with a null terminator. When we meet
// the null terminator, while's condition will get false.
{
if (isalpha(str[i])) // check every character of str
printf ("character %c is alphabetic\n",str[i]);
else
printf ("character %c is not alphabetic\n",str[i]);
i++;
}
return 0;
}
Source
Ref of isalpha().
C does not have a string type.
Tip: Next time post your code as it is!
Aslo, as Alter noticed, it would be nice to use:
isalpha((unsigned char)str[i])
and in your code
isalpha((unsigned char)p[i])
for safety reasons.
Your example is here.
I.e. parameter of isalpha() is i-th character of string p. The only question is how to access to i-th character. Usually you can use []. I.e. just use following code: isalpha(p[i]) (I see that you already use [] in call of printf).
Also isalpha(p[i]) = true is wrong condition. It looks like you planned to check isalpha(p[i]) == true (you can skip == true).
Late but:
both other answers say omitting == true is desirable, but don't say it is necessary for portability.
The C core-language operators == != < <= > >= && || which return a 'logical' value use an int value of 1 for true and 0 for false. In C99 and up with stdbool.h and by common convention before that true is 1 and false is 0, so e.g. if( (a < b) == true ) will work correctly, although it is redundant and many (including me) consider it poor style. Language elements that test a logical value, namely if(c) while(c) for(;c;) and the operands to && || and the left operand to ?: consider any value that compares equal to 0 to be false, and any other value to be true.
The character-classification routines in ctype.h as well as some other standard-library routines like feof(f) and ferror(f) are specified to return some nonzero int for true and 0 (an int) for false, and on many implementations the nonzero value used for true is not (always) 1. In those cases isalpha(whatever) == true might result in testing say 4 == 1 and fail even when whatever is an alphabetic character. OTOH isalpha(...) != false or isalpha(...) != 0 does work correctly if you really want to write something explicit.
Here is my code to find substring entered by the user in the given string.
bool find_str(char *str, char const *substr) {
while(*str) {
if(*str++ == *substr) {
char const *a = substr;
while((*str++ == *++a)); /*empty*/
if(*a == '\0')
return true;
}
}
return false;
}
// If match found, then return true, else false
int main(void) {
printf("%d", find_str("ABCDEF", "CDE")); /* Return true in this case */
printf("%d", find_str("ABCDE", "CDE")); /* Return false in this case */
}
As explained in the comment, it returns true whenever it ends with an additional characters. If it is not, then it returns false. I think there is a problem in increment/decrement operator. But I could not find how?
This is because your code decides to stop on finding \0 only after performing the comparison
*str++ == *++a
This condition will be true even when the match happens at the end of the string on null terminators, so the while loop would happily proceed beyond the end of both strings past the null terminator, causing undefined behavior.
Changing the condition to exit when *a is zero should fix the problem:
while((*str++ == *++a) && (*a));
I analysed you piece of code a little bit and based on my analysis,
I think the problem is in here
while((*str++ == *++a)); /*empty*/
perhaps you would like to add another statement like below
while((*str++ == *++a) && ( *a != '\0' ) ) ; /*empty*/
I guess you are missing a null check, what if both pointer are pointing to NULL termination they will still go forward that's exactly whats happening
I was going through your piece of code and found quite a few interesting things
Lets say the memory allocated for CDE is at X
say again the memory allocated for ABCDEF is at X+4 (this was the case in my machine)
and say memory block allocated for ABCDE is at some X+Y or what ever
now when the function is called second time
both pointers a and str point to respective memory locations starting at X+2 where Character C satisfies the condition above, however the condition will still be true even if they reach to end i.e at X+3 and hence a will move forward and point to A which makes your program behave erroneously
I found this piece of code on Wikipedia.
#include <stdio.h>
int main(void)
{
int c;
while (c = getchar(), c != EOF && c != 'x')
{
switch (c)
{
case '\n':
case '\r':
printf ("Newline\n");
break;
default:
printf ("%c",c);
}
}
return 0;
}
I'm curious about expression used as condition for while loop:
while (c = getchar(), c != EOF && c != 'x')
It's quite obvious what it does, but I've never seen this construction before. Is this specific to while loop? If not, how does parser/compiler determine which side of comma-separated expression returns boolean value for while loop?
The comma operator is a binary operator that evaluates its first operand and discards the result, it then evaluates the second operand and returns this value.
It is also a "sequence point", which means that all side effects will be calculated before the next part of the code is executed.
The comma operator is a weird beastie until you get to understand it, and it's not specific to while.
The expression:
exp1, exp2
evaluates exp1 then evaluates exp2 and returns exp2.
You see it frequently, though you may not realize it:
for (i = j = 0; i < 100; i++, j += 2)
You're not actually using the return value from "i++, j += 2" but it's there nonetheless. The comma operator evaluates both bits to modify both i and j.
You can pretty well use it anywhere a normal expression can be used (that comma inside your function calls is not a comma operator, for example) and it's very useful in writing compact source code, if that's what you like. In that way, it's part of the family that allows things like:
while ((c= getchar()) != EOF) {...}
i = j = k = 0;
and so on.
For your specific example:
while (c = getchar(), c != EOF && c != 'x')
the following occurs:
c = getchar() is executed fully (the comma operator is a sequence point).
c != EOF && c != 'x' is executed.
the comma operator throws away the first value (c) and "returns" the second.
the while uses that return value to control the loop.
In many languages the comma is an operator that always results in the value of the second operand. The operands are evaluated sequentially from left to right.
Pseudo-code:
a = 10
print a = 7 + 8, a * 2
Note: print is considered a statement that does not take arguments, so what comes after is considered the single expression a = 7 + 8, a * 2.
Executed like this:
First line
put 10 in a
Second line
evaluate 7 + 8 (15)
put evaluated value (15) in a
evaluate a * 2 (30)
evaluate , operator with operands 15 and 30:
always value of second operand (30)
print evaluated value (30)
To expand a bit on the other answers, in this code:
EXPRESSION_1 , EXPRESSION_2
EXPRESSION_1 is first evaluated, then there is a sequence point, then EXPRESSION_2 is evaluated, and the value of the whole thing is the value of EXPRESSION_2.
The order of operation guarantee and the sequence point are both important to the code you quoted. Together, they mean that we can be certain that the getchar() function gets called and the value of variable c is fully updated before the value of c is tested.
The comma is an operator. It returns the value of the right hand expression by default. The order of evaluation is guaranteed to be left first and then right.
UPDATE (reply to Pax's comment):
Just like most operators, it can be overloaded for user defined types:
#include <iostream>
#include <string>
using namespace std;
enum EntryType { Home, Cell, Address };
class AddressBookEntryReference {
public:
AddressBookEntryReference(const string& name, const EntryType &entry)
: Name(name), Entry(entry) { }
string Name;
EntryType Entry;
};
AddressBookEntryReference operator,(const string& name, const EntryType &type) {
return AddressBookEntryReference(name, type);
}
class AddressBook {
string test;
public:
string& operator[](const AddressBookEntryReference item) {
// return something based on item.Name and item.Entry.
// just to test:
test = item.Name;
return test;
}
};
int main() {
// demo:
AddressBook book;
cout << book["Name", Cell] // cool syntax!
<< endl;
}