What Is The Point of Symbolic Constants? - c

I've having trouble understanding what is the point of Symbolic Constants in C, I am sure there is a reason for them but I can't seem to see why you wouldn't just use a variable.
#include <stdio.h>
main()
{
float fahr, celsius;
float lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf("%s\t %s\n", "Fahrenheit", "Celsius");
fahr = lower;
while (fahr <= upper) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f\t\t %3.2f\n", fahr, celsius);
fahr = fahr + step;
}
}
Vs.
#include <stdio.h>
#define LOWER 0
#define UPPER 300
#define STEP 20
main()
{
float fahr, celsius;
printf("%s\t %s\n", "Fahrenheit", "Celsius");
fahr = LOWER;
while (fahr <= UPPER) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f\t\t %3.2f\n", fahr, celsius);
fahr = fahr + STEP;
}
}

The (pre)compiler knows that symbolic constants won't change. It substitutes the value for the constant at compile time. If the "constant" is in a variable, it usually can't figure out that the variable will never change value. In consequence, the compiled code has to read the value from the memory allocated to the variable, which can make the program slightly slower and larger.
In C++, you can declare a variable to be const, which tells the compiler pretty much the same thing. This is why symbolic constants are frowned upon in C++.
Note, however, that in C (as opposed to C++) a const int variable is not a constant expression. Therefore, trying to do something like this:
const int a = 5;
int b[a] = {1, 2, 3, 4, 5};
will work in C++ but will get you a compilation error in C (assuming b was supposed to be a statically bound array).

One good example of why named constants are beneficial comes from the excellent book The Practice of Programming by Kernighan and Pike (1999).
§1.5 Magic Numbers
[...] This excerpt from a program to print a histogram of letter frequencies on a 24 by 80 cursor-addressed terminal is needlessly opaque because of a host of magic numbers:
...
fac = lim / 20;
if (fac < 1)
fac = 1;
for (i = 0, col = 0; i < 27; i++, j++) {
col += 3;
k = 21 - (let[i] / fac);
star = (let[i] == 0) ? ' ' : '*';
for (j = k; j < 22; j++)
draw(j, col, star);
}
draw(23, 2, ' ');
for (i = 'A'; i <= 'Z'; i++)
printf("%c ", i);
The code includes, among others, the numbers 20, 21, 22, 23, and 27. They're clearly related...or are they? In fact, there are only three numbers critical to this program: 24, the number of rows on the screen; 80, the number of columns; and 26, the number of letters in the alphabet. But none of these appears in the code, which makes the numbers that do even more magical.
By giving names to the principal numbers in the calculation, we can make the code easier to follow. We discover, for instance, that the number 3 comes from (80 - 1)/26 and that let should have 26 entries, not 27 (an off-by-one error perhaps caused by 1-indexed screen coordinates). Making a couple of other simplifications, this is the result:
enum {
MINROW = 1, /* top row */
MINCOL = 1, /* left edge */
MAXROW = 24, /* bottom edge (<=) */
MAXCOL = 80, /* right edge (<=) */
LABELROW = 1, /* position of labels */
NLET = 26, /* size of alphabet */
HEIGHT = (MAXROW - 4), /* height of bars */
WIDTH = (MAXCOL - 1)/NLET /* width of bars */
};
...
fac = (lim + HEIGHT - 1) / HEIGHT;
if (fac < 1)
fac = 1;
for (i = 0; i < NLET; i++) {
if (let[i] == 0)
continue;
for (j = HEIGHT - let[i]/fac; j < HEIGHT; j++)
draw(j+1 + LABELROW, (i+1)*WIDTH, '*');
}
draw(MAXROW-1, MINCOL+1, ' ');
for (i = 'A'; i <= 'Z'; i++)
printf("%c ", i);
Now it's clearer what the main loop does; it's an idiomatic loop from 0 to NLET, indicating that the loop is over the elements of the data. Also the calls to draw are easier to understand because words like MAXROW and MINCOL remind us of the order of arguments. Most important, it's now feasible to adapt the program to another size of display or different data. The numbers are demystified and so is the code.
The revised code doesn't actually use MINROW, which is interesting; one wonders which of the residual 1's should be MINROW.

Variables are scoped locally to the structure they're declared in. Of course you could use variables instead of symbolic constants, but that might take a lot of work. Consider an application that frequently uses radians. The symbolic constant #define TWO_PI 6.28 would be of high value to the programmer.

Jonathan made a good point in why you would want to use symbolic constants in C (and in any other programming language, BTW).
Syntactically, in C this is different from C++ and many other languages because it is much restrictive on how you may declare such symbolic constant. So-called const qualified variables don't account for this as they would in C++.
You may use a macro that is defined to any constant expression: integer or floating point constants, address expressions of static variables, and some forms of expression that you form from them. These are only treated by the preprocessing phase of the compiler and you'd have to be careful when you use complicated expressions in them.
Yo may declare integer constant expressions in form of integer enumeration constants such as in enum color { red = 0xFF00, green = 0x00FF00, blue = 0x0000FF };. They are only of some restricted use, because they are fixed to have type int. So you wouldn't cover all ranges of values that you'd might want with them.
You might also see integer character constants like 'a' or L'\x4567' as predefined symbolic constants, if you like. They translate an abstract concept (the character value "a") into the encoding of the executing platform (ASCII, EBDIC, whatever).

Jonathan provides an excellent example of the user of symbolic constants.
It is possible that the program used in the question is not the best one to answer this question. However, given the program, symbolic constants might make more sense in the following case:
#include <stdio.h>
#define FAHRENHEIT_TO_CELSIUS_CONVERSION_RATIO 5.0 / 9.0
#define FAHRENHEIT_TO_CELSIUS_ZERO_OFFSET 32.0
#define FAHRENHEIT_CELSIUS_COMMON_VALUE -40.0
#define UPPER 300.0
#define STEP 20.0
int main()
{
float fahr, celsius;
printf("%s\t %s\n", "Fahrenheit", "Celsius");
fahr = FAHRENHEIT_CELSIUS_COMMON_VALUE;
while (fahr <= UPPER) {
celsius = (fahr - FAHRENHEIT_TO_CELSIUS_ZERO_OFFSET) * (FAHRENHEIT_TO_CELSIUS_CONVERSION_RATIO);
printf("%3.0f\t\t %3.2f\n", fahr, celsius);
fahr = fahr + STEP;
}
}
Possibly this makes it easier to understand why symbolic constants might be useful.
The program includes stdio.h, a rather common include file. Let's look at some of the symbolic constants defined in stdlib.h. This version of stdio.h is from Xcode.
#define BUFSIZ 1024 /* size of buffer used by setbuf */
#define EOF (-1)
#define stdin __stdinp
#define stdout __stdoutp
#define stderr __stderrp
Let's also look at two symbolic constants defined in stdlib.h.
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
These values may vary from system to system but using them makes programming in C a lot easier and portable. The symbolic constants for stdin, stdout and stderr have been known to change in various operating system implementations.
Using BUFSIZ to define character arrays for C input buffers generally makes a lot of sense.
Using EXIT_FAILURE and EXIT_SUCCESS makes code much more readable, and I don't have to remember if 0 is failure or success.
Would anyone prefer (-1) over EOF?
Using a symbolic constant to define the size of arrays makes it much easier to change code in one place rather than having to search all over for a specific number embedded in the code.

Related

CS50 problem result is not right and I don't understand why

I'm really sorry to bother but I have a problem and I don't know how to fix it. I've been doing CS5O and in Problem Set 2 I've been receiving wrong results and I don´t understand what I did wrong. It should be giving me "Before Grade 1" for the sentence "One fish. Two fish. Red fish. Blue fish." but is giving me Grade 2, it is giving Grade 14 for a sentence that is Grade 16+. Can someone help me? This is my code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
int count_letters(string text);
int count_word(string text);
int count_sentences(string text);
int letters;
int words;
int sentences;
int main(void)
{
string text = get_string("Text: ");
printf("Text: %s\n", text);
count_letters(text);
count_word(text);
count_sentences(text);
float L = 100 * (letters / words);
float S = 100 * (sentences / words);
int index = round(0.0588 * L - 0.296 * S - 15.8);
if (index < 1)
{
printf("Before Grade 1\n");
} else if (index > 16)
{
printf("Grade 16+\n");
} else
{
printf("Grade: %i\n", index);
}
}
int count_letters(string text)
{
letters = 0;
for (int i = 0; i < strlen(text); i++)
{
if ((text[i] >= 65 && text[i] <= 99) || (text[i] >= 97 && text[i] <= 122))
{
letters++;
}
}
return letters;}
int count_word(string text)
{
words = 1;
for (int i = 0; i < strlen(text); i++)
{
if (isspace(text[i]))
{
words++;
}
}
return words;}
int count_sentences(string text)
{
sentences = 0;
for (int i = 0; i < strlen(text); i++)
{
if (text[i] == 33 || text[i] == 46 || text[i] == 63)
{
sentences++;
}
}
return sentences;
}
Thank you!!
Regarding types:
There's a phenomenon sometimes called "sloppy typing" which basically means carelessly spamming out any random variable type in the code and then wonder why nothing works. Here's some things you need to know:
Integer division truncates the result by dropping the remainder. int is an integer, constants such as 100 is also int. Thus 3/2 evaluates to 1 in C.
Unless you have very good and exotic reasons1), you should pretty much never use the type float in a C program.
On high end systmes like PC, always use double. All the default math functions use double, for example round(). If you wish to use them with float you'd use a special function roundf(). Similarly, all floating point constants 1.0 are of type double. If you want them to be float you'd use 1.0f.
For the two above reasons, make it a habit of never mixing different types in the same expression. Do not mix integer and floating point. Do not mix float and double. Mixing types can lead to unexpected implicit conversion problems, accidental truncation, loss of precision and so on.
So for example a line such as float L = 100 * (letters / words); needs to be rewritten to explicitly use double everywhere:
double L = 100.0 * ((double)letters / (double)words);
1) Like using a microcontroller with single precision floating point FPU but only software floating point double. Or a FPU where double would be far less efficient.
Regarding functions and global variables:
The variables letters, words and sentences could have been declared locally inside main(), since your functions return the values to use anyway.
Declaring global variables like you do is considered very bad practice for multiple reasons. It exposes variables to other parts of the program that shouldn't have access, which in turn increases chances of accidental/intentional abuse since the variables are available everywhere. It increases the chances for naming collisions. It is unsafe in multi-threaded applications. It's universally bad; don't do this.
Instead pass variables to/from functions by parameters and return values.
Regarding "magic numbers":
Dropping a constant such as 0.0588 in the middle of source code, with zero explanation where that number comes from or what it does, is known as "magic numbers". This is bad practice since the reader of the code has no clue what it's therefore. The reader is most often yourself, one year from now, when you have forgotten all about what the code does, so it's a form of self-torture.
So instead of typing out some number like that, use a #define or const variable with a meaningful name, then use that meaningful name in the equation/expression instead.
In case of symbol table values, we don't have to invent that meaningful name ourselves, since C already has a built-in mechanism for it. Instead of text[i] >= 65 you should type text[i] >= 'A', which is 100% equivalent but much more readable.
An advanced detail regarding symbol table values is that they aren't actually guaranteed to be adjacant. Something like ch >= 'A' && ch <= 'Z' may work on classic 7 bit ASCII, but it's non-portable and also don't conver "locale" - local language-specific letters (as seen in Spanish, French, German and so on - almost every major language using latin letters). The portable solution to this is to use isupper or islower from ctype.h. Or in your case better yet, isalpha.
Regarding code formatting:
Don't invent some own non-standard formatting. There are some things regarding code formatting that are subjective, but these are not:
Always use empty lines between function bodies.
Always place the last } of a function at a line of its own.

Exceeding the range of long double and big floating point numbers

Problem statement: I am working on a code that calculates big numbers. Hence, I am easily get beyond the maximum length of "long double". Here is an example below, where part of the code is given that generates big numbers:
int n;
long double summ;
a[1]=1;
b[1]=1;
c[1] = 1; //a, b, c are 1D variables of long double types
summ=1+c[1];
for(n=2; n <=1760; n++){
a[n]=n*n;
b[n]=n;
c[n] = c[n-1]*a[n-1]/b[n]; //Let us assume we have this kind of operation
summ= summ+c[n]; //So basically, summ = 1+c[1]+c[2]+c[3]+...+c[1760]
}
The intermediates values of summ and c[n] are then used to evaluate the ratio c[n]/summ for every integer n. Then, just after the above loop, I do:
for(n=1;n<=1760;n++){
c2[n]=c[n]/summ; //summ is thus here equals to 1+c[1]+c[2]+c[3]+...+c[1760]
}
Output: If we print n, c[n] and summ, we obtain inf after n=1755 because we exceed the length of long double:
n c[n] summ
1752 2.097121e+4917 2.098320e+4917
1753 3.672061e+4920 3.674159e+4920
1754 6.433452e+4923 6.437126e+4923
1755 1.127785e+4927 1.128428e+4927
1756 inf inf
1757 inf inf
1758 inf inf
1759 inf inf
1760 inf inf
Of course, if there is an overflow for c[n] and summ, I cannot evaluate the quantity of interest, which is c2[n].
Questions: Does someone see any solution for this ? How do I need to change the code so that to have finite numerical values (for arbitrary n) ?
I will indeed most likely need to go to very big numbers (n can be much larger than 1760).
Proposition: I know that GNU Multiple Precision Arithmetic (GMP) might be useful but honestly found too many difficulties trying to use this (outside the field), so if there an easier way to solve this, I would be glad to read it. Otherwise, I will be forever grateful if someone could apply GMP or any other method to solve the above-mentioned problem.
NOTE: This does not exactly what OP wants. I'll leave this answer here in case someone has a similar problem.
As long as your final result and all initial values are not out of range, you can very often re-arrange your terms to avoid any overflow. In your case if you actually just want to know c2[n] = c[n]/sum[n] you can re-write this as follows:
c2[n] = c[n]/sum[n]
= c[n]/(sum[n-1] + c[n]) // def. of sum[n]
= 1.0/(sum[n-1]/c[n] + 1.0)
= 1.0/(sum[n-1]/(c[n-1] * a[n-1] / b[n]) + 1.0) // def. of c[n]
= 1.0/(sum[n-1]/c[n-1] * b[n] / a[n-1] + 1.0)
= a[n-1]/(1/c2[n-1] * b[n] + a[n-1]) // def. of c2[n-1]
= (a[n-1]*c2[n-1]) / (b[n] + a[n-1]*c2[n-1])
Now in the final expression neither argument grows out of range, and in fact c2 slowly converges towards 1. If the values in your question are the actual values of a[n] and b[n] you may even find a closed form expression for c2[n] (I did not check it).
To check that the re-arrangement works, you can compare it with your original formula (godbolt-link, only printing the last values): https://godbolt.org/z/oW8KsdKK6
Btw: Unless you later need all values of c2 again, there is actually no need to store any intermediate value inside an array.
I ain't no mathematician. This is what I wrote with the results below. Looks to me that the exponent, at least, is keeping up with your long double results using my feeble only double only...
#include <stdio.h>
#include <math.h>
int main() {
int n;
double la[1800], lb[1800], lc[1800];
for( n = 2; n <= 1760; n++ ) {
lb[n] = log10(n);
la[n] = lb[n] + lb[n];
lc[n] = lc[n-1] + la[n-1] - lb[n];
printf( "%4d: %.16lf\n", n, lc[n] );
}
return 0;
}
/* omitted for brevity */
1750: 4910.8357954121602000
1751: 4914.0785853634488000
1752: 4917.3216235537839000
1753: 4920.5649098413542000
1754: 4923.8084440845114000
1755: 4927.0522261417700000 <<=== Take note, please.
1756: 4930.2962558718036000
1757: 4933.5405331334487000
1758: 4936.7850577857016000
1759: 4940.0298296877190000
1760: 4943.2748486988194000
EDIT (Butterfly edition)
Below is a pretty simple iterative function involving one single and one double precision float values. The purpose is to demonstrate that iterative calculations are exceedingly sensitive to initial conditions. While it seems obvious that the extra bits of the double will "hold-on", remaining closer to the results one would get with infinite precision, the compounding discrepancy between these two versions demonstrate that "demons lurking in small places" will likely remain hidden in the fantastically tiny gaps between finite representations of what is infinite.
Just a bit of fun for a rainy day.
int main() {
float fpi = 3.1415926535897932384626433832;
double dpi = 3.1415926535897932384626433832;
double thresh = 10e-8;
for( int i = 0; i < 1000; i++ ) {
fpi = fpi * 1.03f;
dpi = dpi * 1.03f;
double diff = fabs( dpi - fpi );
if( diff > thresh) {
printf( "%3d: %25.16lf\n", i, diff );
thresh *= 10.0;
}
}
return 0;
}
8: 0.0000001229991486
35: 0.0000010704333473
90: 0.0000100210180918
192: 0.0001092634900033
229: 0.0010121794607585
312: 0.0100316228017618
367: 0.1002719746902585
453: 1.0056506423279643
520: 10.2658853083848950
609: 103.8011477291584000
667: 1073.9984381198883000
736: 10288.9632129669190000
807: 101081.5514678955100000
886: 1001512.2135009766000000
966: 10473883.3271484370000000

C error: pointer expected

I made a simple program in C that finds if a number is prime. I am new to C and decided to try to use scanf instead of hardcoded numbers to check. When I run my code:
#include <stdio.h>
typedef int bool;
#define true 1
#define false 0
int main(){
//I am going to check if the "checking" variable is a prime
int checking;
scanf("%d",checking);
//"stopper" is where the for loop will stop
int stopper = checking**0.5 + 1;
//"found" will show if I have found something bad
bool found = false;
for (int i = 2; i < stopper; i++)
{
if (checking % i == 0){found = true; break;}
}
if (!found) {printf("it is prime");}
else {printf("it is not prime");}
}
when I try to compile this with TCC it gives the error (primes.c is the name of the document)
primes.c:12 error: pointer expected
I don't know how to fix this.
EDIT: I just made stopper = checking/2 and the program crashes
int stopper = checking**0.5 + 1;
line 12... what do you expect the ** operator to do?
A * typically performs a multiply, or dereferences a pointer.
The compiler could be interpreting it as follows:
int stopper = checking * (*0.5) + 1;
Of course, trying to dereference a float (*0.5) is bad / impossible, hence the error.
Did you mean:
instead of **, you meant * (multiply)
instead of ** (not a C operator), you meant pow() (raise to the power of)
You also need to be specific - even if you're an expert at precedance, the reader may not be, and you may well be wrong.
If you're not sure what's going on, use braces to be specific, which of the following do you mean?
int stopper = checking * (0.5 + 1);
int stopper = (checking * 0.5) + 1;
int stopper = pow(checking, 0.5) + 1;
int stopper = pow(checking, 0.5 + 1);
If you are indeed after the square root, then as #JeremyP says, invert your thinking - multiply is much less costly than pow():
for (int i = 2; i * i <= checking; i++)
You have two problems in your program:
(1) Replace
int stopper = checking**0.5 + 1;
with
int stopper = checking*0.5 + 1;
(2) Replace
scanf("%d",checking);
with
scanf("%d",&checking);
You should be good to after these corrections.
There's no built in operator to raise a number to the power of another number. There is a function to do that - also a square root function but you don't need them (see below).
x**y
is parsed as
x* (*y)
which is where your pointer error comes from
Instead of trying to find the square root, come at it from the other direction, change your for loop like this
for (int i = 2; i * i <= checking; i++)
Also, as others have said, the scanf is wrong.
scanf("%d",&checking);
// ^- scanf needs a pointer to an int.
Firstly, the scanf is wrong.
Use scanf("%d",&checking);
For finding the square root use math.h library for sqrt function.
int stopper = sqrt(checking) + 1;
There were a lot of typing mistakes in your code. Please, correct your syntax before asking a question.
Ideone link for code

Finding derivative of a function stored in a character array

What I need to do is read a file which contains equations. I need to take the derivative of each equation and then write those derivative equations in a different .txt file. I've read all the equations into an array of character arrays and now I don't know what to do once I've stored them into the array. I really don't need help writing the equations into another file; I know I can figure that out.
What I need help on is finding a way to taking the derivative of the functions. The type of equations that are going to be read are not that complicated; they're going to be polynomials that don't need the chain rule or quotient rule. There will be, however, sin x, cos x and tan x. Some sample equations that would be read are.
-2x^2+2x-3
-2x+sinx-3
-x+sin2x-tanx
The trig functions will not have parenthesis and the variable will always be "x".
I just need a push in the right direction, please.
What you're really asking for is a parser.
A parser is basically a set of rules to read those equations and change/read (parse) each of them.
I'd try to iterate over each line of the file, and differentiate it considering you have a specific character set (i.e ^ means power, x is the parameter, etc.);
For example, some pseudo code:
Open the file.
While there's lines to read:
Read a line -
Seperate it by the operands (+,-,/,*)
For each part:
Find the power of x,
Reduce it by one,
...(derivating rules) // no way around, you have to implement each function if you want this to work as others mentioned in the comments.
Reconnect the parts into a string,
Add it to a list.
Print each element of the list.
If you need help translating that into C, just ask for it; I'll happily help you.
What you need to do, by the looks of things, is separate the expression into individual terms so that you can find the derivative of each in turn.
You can define a term as the largest sequence of characters not containing term separators such as (in your examples) + and -.
Hence the terms for your examples are:
-2x^2+2x-3 => 2x^2 2x 3
-2x+sinx-3 => 2x sinx 3
-x+sin2x-tanx => x sin2x tanx
For each term, you then need to evaluate the form of the term. The form will dictate how you create the derivative.
For example, you can detect if it contains a trigonometric function of the form [n]sin[m]x where n and m are optional numbers. To simplify things, you could add in those terms if they're not there, such as sinx becoming 1sin1x (I'll call this the full-form of the term). Being able to assume all subterms are present will greatly ease the derivative calculation.
Let's say the term is sin4x. Expanding that will give you 1sin4x which you can then split into term-multiplier 1, function sin and x-multiplier 4. Then using standard derivative knowledge nsinmx => (n*m)cosmx, this would become 4cos(4x) and that term would be done.
If it doesn't contain a trigonometric function, you can use the same full-form trick to cover all of the power/constant expressions with the following rules in turn:
if it's a constant (all numeric), append x^0 (multiply by 1).
if it ends with x, append ^1, so 4x becomes 4x^1.
if it starts with x, prefix it with 1, so x^3 becomes 1x^3.
Once that's done, you will have a full-form of ax^b and you can then create the derivative (ab)x^(b-1) and post-process it:
if the bit after x is ^0, remove the whole x^0.
if the bit after x is ^1, remove the ^1.
if the bit before the x is 1, remove it.
if the bit before the x is 0, remove the entire term (and preceding term separator, if any).
So, taking a complex combination of your test data:
-2x^2 + 5x + 4sin3x - 3
which can be treated as:
0 - 2x^2 + 5x + 4sin3x - 3
The following actions happen to each term:
0 [0x^1] (derives as) 0, remove it.
2x^2 [2x^2] (derives as) (2*2)x^(2-1) => 4x^1 => 4x
5x [5x^1] (derives as) (5x1)x^(1-1) => 5x^0 => 5
4sin3x [4sin3x] (derives as) 12cos3x
3 [3x^0] (derives as) 0, remove it and preceding '-'
Thus you end up with - 4x + 5 + 12cos3x which, although my calculus education is some thirty years in the past (and I don't think I've used it since, though I will no doubt be using it next year when my eldest hits secondary school), Wolfram Alpha appears to agree with me :-)
This function will parse the text, cut it in to different parts identified by type[i], stores in a structure. It recognizes x, +, -, and numbers. It can be expand it to include other operators etc.
#define maxlen 50
#define idx 0 //X variable
#define idnumber 1 //number
#define idplus 2 //+ sign
#define idminus 3 //- sign
struct foo
{
int type[10];//each type can be a number (idnum), +, -, etc.
int num[10];//if type[i] is number then num[i] identifies that number
int count;//total number of parts
};
void parse_one_line(struct foo *v, const char *s)
{
char buf[maxlen];
memset(buf, 0, maxlen);
int j = 0;
//remove white spaces
for (int i = 0, len = strlen(s); i < len; i++)
{
if (s[i] == ' ') continue;
buf[j] = s[i];
j++;
}
char part[maxlen];
v->count = 0;
for (int i = 0, len = strlen(buf); i < len; i++)
{
char c = buf[i];
if (c == 'x')
{
v->type[v->count] = idx;
v->count++;
}
else if (c == '+')
{
v->type[v->count] = idplus;
v->count++;
}
else if (c == '-')
{
v->type[v->count] = idminus;
v->count++;
}
else if (c >= '0' && c <= '9')
{
int j = 0;
memset(part, 0, maxlen);
for (; i < len; i++)
{
c = buf[i];
if (c >= '0' && c <= '9')
{
part[j] = c;
j++;
}
else
{
break;
}
}
i--;
v->num[v->count] = atoi(part);
v->type[v->count] = idnumber;
v->count++;
}
}
for (int i = 0; i < v->count; i++)
{
switch (v->type[i])
{
case idnumber: printf("%d", v->num[i]); break;
case idx: printf("X"); break;
case idplus: printf("+"); break;
case idminus: printf("-"); break;
default:break;
}
}
printf("\n");
}
int main()
{
struct foo st;
parse_one_line(&st, "-23x + 2 + 2x - 3");
return 0;
}

Issues by the redefinition of a macro in C

I want to change the value of a macro during the run of the program, for that I've wrote this example :
#include <stdio.h>
#define MAX (65535 *0.5)
int main ( ){
float amp = 0.0;
float temp = 0.0 ;
temp = MAX ;
char c;
while (1){
printf(" MAX value %.2d.%.3d \n ", (short)temp,(short)(temp*1000));
scanf("%c",&c);
if( c =='x') {
#undef MAX
#define MAX (65535 +amp);
amp+= 0.1;
temp = MAX;
}
}
return 0 ; }
I've got two problems :
1. the printf doessn't show the values as hoped, for instand 19.211, it always
-32768.-32768
2. I don't see any change of the value of the macro.
any idea what I'm doing wrong here ?
You can only define macros at compile time. The c preprocessor replaces every occurrance of a macro before actual compilation happens, with gcc you can see what code was generated after preprocessing by using the -E switch, if you try it experimenting with different macros, you may get to understand the preprocessor a little better, read the link to understand more.
This
if( c =='x') {
#undef MAX
#define MAX (65535 +amp);
amp+= 0.1;
temp = MAX;
}
does not do what you think.
If you execute the preprocessor on the source code, then what will actually happen is that the snippet above will be compiled as
if( c =='x') {
amp+= 0.1;
temp = MAX;
}
so as you can see, it doesn't do what you think.
Also, this is not related to the macro redefinition issue, but your code has a bug that can make it enter an infinite loop, this
scanf("%c",&c);
will keep scanning the '\n' that is left in the stdin after pressing Enter/Return, so you need to explicitly ignore that character by adding a white space before the specifier like this
scanf(" %c", &c);
/* ^ white space goes here */
Note: another answer has suggested that you are using the incorrect data type and suggested a solution, you should take a look at it, since in fact it seems your program has an integer overflow issue.
Let's run your file through the C preprocessor (CPP) manually. The result is
int main ( ) {
float amp = 0.0;
float temp = 0.0 ;
temp = (65535 *0.5) ;
char c;
while (1) {
printf(" MAX value %.2d.%.3d \n ", (short)temp,(short)(temp*1000));
scanf("%c",&c);
if( c =='x') {
amp+= 0.1;
temp = (65535 +amp);;
}
}
return 0 ;
}
Macros are evaluated before the compiler even sees your source code. You cannot change the value of a macro based on a decision taken at runtime.
Why not instead use a variable float max = ... and change that one's value depending on user input?
Macros are resolved during compilation, so during program execution there is no such thing like MAX - each occurence was already replaced by its value (65535).
However, if you need to define local constant (local in terms of translation unit), why not use static variable?
static unsigned int MAX = 65535;
And then:
if (c == 'x')
{
MAX = 65535 + amp;
//...
}
You are using too short data type and printing the fractional part incorrectly. Consider doing this:
double i;
printf(" MAX value %.2d.%.3d \n ", (int)temp,(int)(modf(temp,&i)*1000));
...instead of this:
printf(" MAX value %.2d.%.3d \n ", (short)temp,(short)(temp*1000));
Be sure to #include <math.h> if using modf.
Your redefinition of the MAX macro looks strange to me, though. Macros are defined at compile time, not at run time, so most of the time you don't want to redefine macros.
Note also that
scanf("%c",&c);
will read the newline as a separate character, so you want to do instead:
scanf(" %c",&c);
...to consume whitespace. Do consider checking also for the EOF (end-of-file) condition; currently you don't do that.

Resources