#include<stdio.h>
int main()
{
int i=10,a;
while(i>0)
{
scanf("%d",&a);
printf("%d\n",(a+a*a)/2);
i--;
}
}
Now what i want to ask is how to make it shorter? Maybe some way using pointers instead of variables? Maybe this: (a+a*a)/2 can be done better?
Beware what you ask for...
#include <iostream>
int main()
{
int a;
for (int i = 10;
i-- && (std::cin >> a) && (std::cout << (a + a * a) / 2); )
;
}
(this also includes error checking, which you didn't bother with)
EDIT: Chris's comments below reveal this to be a terse-programming challenge (and not about legibility, robustness etc.). His teacher claims a 54 character implementation.
Have to wonder whether that include spaces and newlines?
The tightest implementation I've got so far is:
#include<iostream.h>
int main(){for(int i=10,a;i--;)cin>>a,cout<<(a+a*a)/2;}
This uses the deprecated header iostream.h to remove the need to explicitly find cin and cout in std::. It's still 74 characters (LF newlines on both lines).
As a thought experiment, let's assume we had a header "x" that declared functions int g() (get an int from stdin) and void p(int) (write an int to stdin). The implementation would then be...
#include<x>
int main(){for(int i=10,a;i--;)a=g(),p((a+a*a)/2);}
...which is still 64 characters.
Another technique commonly used to shorten code is preprocessor tricks, but the obvious one here - loop unrolling - doesn't look promising. It could look like...
#define X ...
int main(){X X X X X X X X X X}
...but if you compare for loop code to the #define-necessitated code...
for(int i=10,a;i--;)
#define X X X X X X X X X X X
...we're clearly going backwards.
Summarily, I simply can not imagine any approach shaving 10 characters off the <iostream.h> version above. If he has a 54-character implementation, I think the requirements must have been miscommunicated in the question. If not, I do hope Chris will post it later :-).
One way you can shorten this is to use a for loop instead of a while loop. Try using
for (i = 10; i > 0; --i) {
Rather than your current while statement. This eliminates the need for the i--; line.
I'm not sure what you mean by making this code shorter "using pointers" though. Adding pointers won't help here.
Using this for loop, your code would look like:
#include<stdio.h>
int main()
{
int i, a;
for (i = 10; i > 0; --i)
{
scanf("%d",&a);
printf("%d\n",(a+a*a)/2);
}
}
This removes one line. The only way of removing more lines would be to make this code less readable, or by changing your code style (which is completely unnecessary).
Related
#include<iostream>
#include<stack>
#include<cmath>
using namespace std;
int Narsic(stack<int> stk)
{
int x=0;
int temp=0;
int val=0;
int power_count = stk.size();
while(! stk.empty())
{
x = stk.top();
stk.pop();
temp = pow(x,power_count);
val = val + temp;
}
cout<<val;
}
int main()
{
int num,indic;
num = 1652;
stack<int> numstack;
while(num>0)
{
indic = num%10;
num = num/10;
numstack.push(indic);
}
Narsic(numstack);
return 0;
}
Basically this program is to find the Narcissistic value of a given integer, my codes can be successfully executed and it is correct, but somehow, i think , maybe it is a bit lengthy, so the purpose of posting this problem is, whether anyone can give me suggestions on how to improve the codes above?
Sorry , I'm a beginner and just started learning C++. I hope this community won't get furious against by sucky codes XD.
(Oh yeah, i do search for some codes online and implement them partially here, so if anyone saw similar codes, please be aware that i have made changes, sorry if this irritates you.)
It looks like you're largely asking about style. I'm going to take your code and edit it to be more in keeping with what I would do, then I'll comment below.
#include <iostream>
#include <stack>
#include <cmath>
using std::cout;
using std::endl;
using std::stack;
/**
* Return the Narcissistic value of the digits stored in the stack.
* A Narcissistic value is (insert description).
*/
int narsic(stack<int> stk)
{
int result = 0;
int power_count = stk.size();
while (! stk.empty() ) {
int digit = stk.top();
stk.pop();
result += pow(digit, power_count);
}
return result;
}
/**
* Entry point.
*/
int main() {
int num;
num = 1652;
stack<int> numstack;
while (num>0)
{
int indic = num % 10;
num /= 10;
numstack.push(indic);
}
int result = narsic(numstack);
cout << "Result: " << result << endl;
return 0;
}
I use Java's naming conventions. Class names begin with an upper case letter. Variables and methods begin with lower case letters. This isn't necessarily the C++ way of doing it, but I programmed Java a long time, and it's what I prefer. You'll want to find a style for your academic work, and then use whatever your future employer uses.
I prefer more whitespace to make code readable -- especially for myself. I'm nearly 60 years old, with old eyes, and as code runs all together, it gets harder and harder to read. I've added whitespace here and there.
A blanket using namespace std is considered dangerous, but I don't like sticking std:: all over the place, so I tend to add specific using statements, although not too many.
You were missing a return statement in narsic().
And you had an unusual indentation style. Old-school C/C++ is either 4 spaces or use a tab, but set your editor to 4-space tabs. You indented the braces and then indented again. That would be odd. Some people put the open brace on the same line (I moved them) and some on the next line the way you did. I actually will put them on the next line if it makes the code more readable -- like if there's an obnoxiously long and complicated if-clause.
I moved variable declaration to just as the variables were about to used. This is better for a variety of reasons, including one less initialization plus makes your code smaller. Plus, it keeps scoping rules much tighter.
I switched a num = num / 10 to num /= 10. Similar thing with result +=.
I don't like the variable name val. I changed to result. I think I might have made one or two other variables more descriptive, too.
I added function comments and I did it in the doxygen style. Commenting each method means tools can auto-generate documentation. It also helps break code up a little bit better visually. For comments, it's important to provide information not in the code. The comment for main is trivial, but having it still helps if you actually use a documentation generator -and- provides a visual break.
A change I did NOT make but would normally do: I prefer main to be the first method in my files (at the top), so I would have made a forward reference to narsic() and moved it below main. I didn't do that just because I wanted to keep the code in the same order you had it.
I moved the cout statement and included an endl.
I am trying to write a lexer, when I try to copy isdigit buffer value in an array of char, I get this core dumped error although I have done the same thing with identifier without getting error.
#include<fstream>
#include<iostream>
#include<cctype>
#include <cstring>
#include<typeinfo>
using namespace std;
int isKeyword(char buffer[]){
char keywords[22][10] = {"break","case","char","const","continue","default", "switch",
"do","double","else","float","for","if","int","long","return","short",
"sizeof","struct","void","while","main"};
int i, flag = 0;
for(i = 0; i < 22; ++i){
if(strcmp(keywords[i], buffer) == 0)
{
flag = 1;
break;
}
}
return flag;
}
int isSymbol_Punct(char word)
{
int flag = 0;
char symbols_punct[] = {'<','>','!','+','-','*','/','%','=',';','(',')','{', '}','.'};
for(int x= 0; x< 15; ++x)
{
if(word==symbols_punct[x])
{
flag = 1;
break;
}
}
return flag;
}
int main()
{
char buffer[15],buffer1[15];
char identifier[30][10];
char number[30][10];
memset(&identifier[0], '\0', sizeof(identifier));
memset(&number[0], '\0', sizeof(number));
char word;
ifstream fin("program.txt");
if(!fin.is_open())
{
cout<<"Error while opening the file"<<endl;
}
int i,k,j,l=0;
while (!fin.eof())
{
word = fin.get();
if(isSymbol_Punct(word)==1)
{
cout<<"<"<<word<<", Symbol/Punctuation>"<<endl;
}
if(isalpha(word))
{
buffer[j++] = word;
// cout<<"buffer: "<<buffer<<endl;
}
else if((word == ' ' || word == '\n' || isSymbol_Punct(word)==1) && (j != 0))
{
buffer[j] = '\0';
j = 0;
if(isKeyword(buffer) == 1)
cout<<"<"<<buffer<<", keyword>"<<endl;
else
{
cout<<"<"<<buffer<<", identifier>"<<endl;
strcpy(identifier[i],buffer);
i++;
}
}
else if(isdigit(word))
{
buffer1[l++] = word;
cout<<"buffer: "<<buffer1<<endl;
}
else if((word == ' ' || word == '\n' || isSymbol_Punct(word)==1) && (l != 0))
{
buffer1[l] = '\0';
l = 0;
cout<<"<"<<buffer1<<", number>"<<endl;
// cout << "Type is: "<<typeid(buffer1).name() << endl;
strcpy(number[k],buffer1);
k++;
}
}
cout<<"Identifier Table"<<endl;
int z=0;
while(strcmp(identifier[z],"\0")!=0)
{
cout <<z<<"\t\t"<< identifier[z]<<endl;
z++;
}
// cout<<"Number Table"<<endl;
// int y=0;
// while(strcmp(number[y],"\0")!=0)
// {
// cout <<y<<"\t\t"<< number[y]<<endl;
// y++;
// }
}
I am getting this error when I copy buffer1 in number[k] using strcpy. I do not understand why it is not being copied. When i printed the type of buffer1 to see if strcpy is not generating error, I got A_15, I searched for it, but did not find any relevant information.
The reason is here (line 56):
int i,k,j,l=0;
You might think that this initializes i, j, k, and l to 0, but in fact it only initializes l to 0. i, j, and k are declared here, but not initialized to anything. As a result, they contain random garbage, so if you use them as array indices you are likely to end up overshooting the bounds of the array in question.
At that point, anything could happen—in other words, this is undefined behavior. One likely outcome, which is probably happening to you, is that your program tries to access memory that hasn't been assigned to it by the operating system, at which point it crashes (a segmentation fault).
To give a concrete demonstration of what I mean, consider the following program:
#include <iostream>
void print_var(std::string name, int v)
{
std::cout << name << ": " << v << "\n";
}
int main(void)
{
int i, j, k, l = 0;
print_var("i", i);
print_var("j", j);
print_var("k", k);
print_var("l", l);
return 0;
}
When I ran this, I got the following:
i: 32765
j: -113535829
k: 21934
l: 0
As you can see, i, j, and k all came out such that using them as indices into any of the arrays you declared would exceed their bounds. Unless you are very lucky, this will happen to you, too.
You can fix this by initializing each variable separately:
int i = 0;
int j = 0;
int k = 0;
int l = 0;
Initializing each on its own line makes the initializations easier to see, helping to prevent mistakes.
A few side notes:
I was able to spot this issue immediately because I have my development environment configured to flag lines that provoke compiler warnings. Using a variable before it's being initialized should provoke such a warning if you're using a reasonable compiler, so you can fix problems like this as you run into them. Your development environment may support the same feature (and if it doesn't, you might consider switching to something that does). If nothing else, you can turn on warnings during compilation (by passing -Wall -Wextra to your compiler or the like—check its documentation for the specifics).
Since you declared your indices as int, they are signed integers, which means they can hold negative values (as j did in my demonstration). If you try to index into an array using a negative index, you will end up dereferencing a pointer to a location "behind" the start of the array in memory, so you will be in trouble even with an index of -1 (remember that a C-style array is basically just a pointer to the start of the array). Also, int probably has only 32 bits in your environment, so if you're writing 64-bit code then it's possible to define arrays too large for an int to fully cover, even if you were to index into the array from the middle. For these sorts of reasons, it's generally a good idea to type raw array indices as std::size_t, which is always capable of representing the size of the largest possible array in your target environment, and also is unsigned.
You describe this as C++ code, but I don't see much C++ here aside from the I/O streams. C++ has a lot of amenities that can help you guard against bugs compared to C-style code (which has to be written with great care). For example, you could replace your C-style arrays here with instances of std::array, which has a member function at() that does subscripting with bounds checking; that would have thrown a helpful exception in this case instead of having your program segfault. Also, it doesn't seem like you have a particular need for fixed-size arrays in this case, so you may better off using std::vector; this will automatically grow to accommodate new elements, helping you avoid writing outside the vector's bounds. Both support range-based for loops, which save you from needing to deal with indices by hand at all. You might enjoy Bjarne's A Tour of C++, which gives a nice overview of idiomatic C++ and will make all the wooly reference material easier to parse. (And if you want to pick up some nice C habits, both K&R and Kernighan and Pike's The Practice of Programming can save you much pain and tears).
Some general hints that might help you to avoid your cause of crash totally by design:
As this is C++, you should really refer to established C++ data types and schemes here as far as possible. I know, that distinct stuff in terms of parser/lexer writing can become quite low-level but at least for the things you want to achieve here, you should really appreciate that. Avoid plain arrays as far as possible. Use std::vector of uint8_t and/or std::string for instance.
Similar to point 1 and a consequence: Always use checked bounds iterations! You don't need to try to be better than the optimizer of your compiler, at least not here! In general, one should always avoid to duplicate container size information. With the stated C++ containers, this information is always provided on data source side already. If not possible for very rare cases (?), use constants for that, directly declared at/within data source definition/initialization.
Give your variables meaningful names, declare them as local to their used places as possible.
isXXX-methods - at least your ones, should return boolean values. You never return something else than 0 or 1.
A personal recommendation that is a bit controversional to be a general rule: Use early returns and abort criteria! Even after the check for file reading issues, you proceed further.
Try to keep your functions smart and non-boilerplate! Use sub-routines for distinct sub-tasks!
Try to avoid using namespace that globally! Even without exotic building schemes like UnityBuilds, this can become error-prone as hell for huger projects at latest.
the arrays keywords and symbols_punct should be at least static const ones. The optimizer will easily be able to recognize that but it's rather a help for you for fast code understanding at least. Try to use classes here to compound the things that belong together in a readable, adaptive, easy modifiable and reusable way. Always keep in mind, that you might want to understand your own code some months later still, maybe even other developers.
Assume we have some variables named var1, var2 , ..., var100.
How can I call a function named func() with that variables with a for loop. I mean how should I
change this code that it works?
for (int counter{1}; counter <= 100; ++counter) {
cout << func(var+counter);
}
There is no1 way to do it. Use an array instead.
1
you know there is no impossible in computer world :D
— OP
If you really want to shoot yourself in the foot, there is a way: Boost.Preprocessor.
#include <boost/preprocessor/repetition/repeat.hpp>
// ...
int main()
{
#define FOO(unused0, index, unused1) cout << func(var##index);
BOOST_PP_REPEAT(101, FOO,)
#undef FOO
}
(Note that this snippet interacts with var0, ... var100, not var1, ... var100 you asked for. Changing the first index is left as an exercise to the reader. Hint: it can't be done with BOOST_PP_REPEAT, you need a different macro.)
There are some caveats:
The amount of variables has to be known at compile-time, and it has to be a preprocessor constant (i.e. 101 verbatim does work, but const int n = 101; or even 100+1 do not).
There is a hard limit on the amount of 'iterations'. (256 by default, probably can be increased).
This might increase your build times.
I'm trying to define macros to read and print matrices in C++, but I'm trying something different, and it's not working:
#define rm(A, m, n, type)
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
scanf("%##type##", &A[i][j]);
A is the matrix (int or char)
I want to write d or c to read int or char, but this code isn't working and I don't even know why, I just tried to use the concat ## symbol to create the string that scanf receive as argument, but it bugs.
My questions are:
1 - why is it wrong?
2 - how can I make this macro work fine?
(if necessary, the solution may contain 1 or 2 macro declarations, but short ones, otherwise I wouldn't ask and I could just create a macro for int and other for char.
PS: this macro is written one line, the algorithm above is just to show what it does.
Thanks
If you really must make a macro for this - which, as others have pointed out, is a Really Bad Idea and Not The Right Way To Do This - the issue that you're encountering is that macros are interpreted by the preprocessor, which treats line breaks as as the end of a macro replacement. To fix this, you'll need to introduce some escape sequences at the ends of the lines:
#define rm(A, m, n, type) \
for(int i = 0; i < m; i++) \
for(int j = 0; j < n; j++) \
scanf("%" #type, &A[i][j]);
Notice that I've factored out your use of the token-pasting operator from the inside of the string, since the preprocessor doesn't fill in string literals for you, and instead opted to use the stringizing operator # to convert the type to a string literal. Since the compiler automatically concatenates adjacent string literals together, there's no need to paste anything. I should repeat that this is a really bad idea in that it hurts code readability and doesn't offer anything you can't already do with a regular C++ function.
You've tagged this question as C++, though, so I should point out that scanf has all sorts of type safety issues that can come up, so it's almost certainly safer to use the iostream library, which for all its faults does catch a ton of possible errors at compile-time.
Fundamentally, though, you shouldn't use macros for this. Just write a regular old function. Here's one way to do this, which has the added benefit that it automatically infers the sizes of arrays:
template <typename T, size_t m, size_t n>
void readArray(T (&array)[m][n], std::istream& source = std::cin) {
for (size_t i = 0; i < m; i++) {
for (size_t j = 0; j < n; j++) {
source >> array[i][j];
}
}
}
Now, you can say something like this:
double arr[137][42];
readArray(arr);
to read an array of doubles from cin, or
int arr[5][5];
ifstream input("my-file.txt");
readArray(arr, input);
to read an array of ints from an external file. This is type-safe and will raise a compiler error if you try reading in a case where the array size isn't defined or where the type can't be read. This prevents all sorts of possible problems. Compare this with your macro, where I could do something like this:
int arr[5][5];
rm(arr, 6, 6, f);
Oops - I just used the wrong array size and the wrong scanf specifier. Any time you can offload work to the compiler that saves you from having to make code changes across lots of places, it's worth considering!
Im creating an infix problem solver and it crashes in the final while loop to finish the last part a of the equations.
I call a final while loop in main to solve whats left on the stack and it hangs there and if i pop the last element from the stack it will leave the loop and return the wrong answer.
//
//
//
//
//
#include <iostream>
#include<stack>
#include<string>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
using namespace std;
#define size 30
int count=0;
int count2=0;
int total=0;
stack< string > prob;
char equ[size];
char temp[10];
string oper;
string k;
char t[10];
int j=0;
char y;
int solve(int f,int s, char o)
{
cout<<"f="<<f<<endl;
cout<<"s="<<s<<endl;
cout<<"o="<<o<<endl;
int a;
if (o== '*')//checks the operand stack for operator
{
cout << f << "*" << s << endl;
a= f*s;
}
if (o == '/')//checks the operand stack for operator
{
cout << f << "/" << s << endl;
if(s==0)
{
cout<<"Cant divide by 0"<<endl;
}
else
a= f/s;
}
if (o == '+')//checks the operand stack for operator
{
cout << f << "+" << s << endl;
a= f+s;
}
if (o == '-')//checks the operand stack for operator
{
cout << f << "-" << s << endl;
a= f-s;
}
return a;
}
int covnum()
{
int l,c;
k=prob.top();
for(int i=0;k[i]!='\n';i++)t[i]=k[i];
return l=atoi(t);
}
char covchar()
{
k=prob.top();
for(int i=0;k[i]!='\n';i++)t[i]=k[i];
return t[0];
}
void tostring(int a)
{
stringstream out;
out << a;
oper = out.str();
}
void charstack(char op)
{
oper=op;
prob.push(oper);
}
void numstack(char n[])
{
oper=n;
prob.push(oper);
}
void setprob()
{
int f,s;
char o;
char t;
int a;
int i;
t=covchar();
if(ispunct(t))
{
if(t=='(')
{
prob.pop();
}
if(t==')')
{
prob.pop();
}
else if(t=='+'||'-')
{
y=t;
prob.pop();
}
else if(t=='/'||'*')
{
y=t;
prob.pop();
}
}
cout<<"y="<<y<<endl;
i=covnum();
cout<<"i="<<i<<endl;
s=i;
prob.pop();
t=covchar();
cout<<"t="<<t<<endl;
if(ispunct(t))
{
o=t;
prob.pop();
}
i=covnum();
cout<<"i="<<i<<endl;
f=i;
prob.pop();
t=covchar();
if (t=='('||')')
{
prob.pop();
}
a=solve(f,s, o);
tostring(a);
prob.push(oper);
cout<<"A="<<prob.top()<<endl;
}
void postfix()
{
int a=0;
char k;
for(int i=0;equ[i]!='\0';i++)
{
if(isdigit(equ[i]))//checks array for number
{
temp[count]=equ[i];
count++;
}
if(ispunct(equ[i]))//checks array for operator
{
if(count>0)//if the int input is done convert it to a string and push to stack
{
numstack(temp);
count=0;//resets the counter
}
if(equ[i]==')')//if char equals the ')' then set up and solve that bracket
{
setprob();
i++;//pushes i to the next thing in the array
total++;
}
while(equ[i]==')')//if char equals the ')' then set up and solve that bracket
{
i++;
}
if(isdigit(equ[i]))//checks array for number
{
temp[count]=equ[i];
count++;
}
if(ispunct(equ[i]))
{
if(equ[i]==')')//if char equals the ')' then set up and solve that bracket
{
i++;
}
charstack(equ[i]);
}
if(isdigit(equ[i]))//checks array for number
{
temp[count]=equ[i];
count++;
}
}
}
}
int main()
{
int a=0;
char o;
int c=0;
cout<<"Enter Equation: ";
cin>>equ;
postfix();
while(!prob.empty())
{
setprob();
a=covnum();
cout<<a<<" <=="<<endl;
prob.pop();
cout<<prob.top()<<"<top before c"<<endl;
c=covnum();
a=solve(c,a,y);
}
cout<<"Final Awnser"<<a<<endl;
system ("PAUSE");
return 0;
}
Hope this isn't too harsh but it appears like the code is riddled with various problems. I'm not going to attempt to address all of them but, for starters, your immediate crashes deal with accessing aggregates out of bounds.
Example:
for(int i=0;k[i]!='\n';i++)
k is an instance of std::string. std::string isn't null-terminated. It keeps track of the string's length, so you should be do something like this instead:
for(int i=0;i<k.size();i++)
Those are the more simple kind of errors, but I also see some errors in the overall logic. For example, your tokenizer (postfix function) does not handle the case where the last part of the expression is an operand. I'm not sure if that's an allowed condition, but it's something an infix solver should handle (and I recommend renaming this function to something like tokenize as it's really confusing to have a function called 'postfix' for an infix solver).
Most of all, my advice to you is to make some general changes to your approach.
Learn the debugger. Can't stress this enough. You should be testing your code as you're writing it and using the debugger to trace through it and make sure that state variables are correctly set.
Don't use any global variables to solve this problem. It might be tempting to avoid passing things around everywhere, but you're going to make it harder to do #1 and you're also limiting the generality of your solution. That small time you saved by not passing variables is easily going to cost you much more time if you get things wrong. You can also look into making a class which stores some of these things as member variables which you can avoid passing in the class methods, but especially for temporary states like 'equ' which you don't even need after you tokenize it, just pass it into the necessary tokenize function and do away with it.
initialize your variables as soon as you can (ideally when they are first defined). I see a lot of obsolete C-style practices where you're declaring all your variables at the top of a scope. Try to limit the scope in which you use variables, and that'll make your code safer and easier to get correct. It ties in with avoiding globals (#2).
Prefer alternatives to macros when you can, and when you can't, use BIG_UGLY_NAMES for them to distinguish them from everything else. Using #define to create a preprocessor definition for 'size' actually prevents the code above using the string's 'size' method from working. That can and should be a simple integral constant or, better yet, you can simply use std::string for 'equ' (aside from making it not a file scope global).
Prefer standard C++ library headers when you can. <ctype.h> should be <cctype>, <stdlib.h> should be <cstdlib>, and <stdio.h> should be <stdio>. Mixing non-standard headers with .h extension and standard headers in the same compilation unit can cause problems in some compilers and you'll also miss out on some important things like namespace scoping and function overloading.
Finally, take your time with the solution and put some care and love into it. I realize that it's homework and you're under a deadline, but you'll be facing even tougher deadlines in the real world where this kind of coding just won't be acceptable. Name your identifiers properly, format your code legibly, document what your functions do (not just how each line of code works which is something you actually shouldn't be doing so much later as you understand the language better). Some coding TLC will take you a long way. Really think about how to design solutions to a problem (if we're taking a procedural approach, decompose the problem into procedures as general units of work and not a mere chopped up version of your overall logic). #2 will help with this.
** Example: rather than a function named 'postfix' which works with some global input string and manipulates some global stack and partially evaluates the expression, make it accept an input string and return* the individual tokens. Now it's a general function you can reuse anywhere and you also reduced it to a much easier problem to solve and test. Document it and name it that way as well, focusing on the usage and what it accepts and returns. For instance:
// Tokenize an input string. Returns the individual tokens as
// a collection of strings.
std::vector<std::string> tokenize(const std::string& input);
This is purely an example and it may or may not be the best one for this particular problem, but if you take a proper approach to designing procedures, the end result is that you should have built yourself a library of well-tested, reusable code that you can use again and again to make all your future projects that much easier. You'll also make it easier to decompose complex problems into a number of simpler problems to solve which will make everything easier and the whole coding and testing process much smoother.
I see a number of things which all likely contribute to the issue of it not working:
There are no error or bounds checking. I realize that this is homework and as such may have specific requirements/specifications which eliminate the need for some checks, but you still need some to ensure you are correctly parsing the input. What if you exceed the array size of equ/tmp/t? What if your stack is empty when you try to pop/top it?
There are a few if statements that look like else if (t == '+' || '-') which most likely doesn't do what you want them to. This expression is actually always true since '-' is non-zero and is converted to a true value. You probably want else if (t == '+' || t == '-').
As far as I can tell you seem to skip parsing or adding '(' to the stack which should make it impossible for you to actually evaluate the expression properly.
You have a while loop in the middle of postfix() which skips multiple ')' but doesn't do anything.
Your code is very hard to follow. Properly naming variables and functions and eliminating most of the globals (you don't actually need most of them) would help a great deal as would proper indentation and add a few spaces in expressions.
There are other minor issues not particularily worth mentioning. For example the covchar() and covnum() functions are much more complex than needed.
I've written a few postfix parsers over the years and I can't really follow what you are trying to do, which isn't to say the way you're trying is impossible but I would suggest re-examining at the base logic needed to parse the expression, particularly nested levels of brackets.