Issues by the redefinition of a macro in C - 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.

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.

function declaration and call and definition in c

Why is this code not running after printing of array if I take value of n>=9?
#include <stdio.h>
#include <math.h>
float mean_function(float array[],int n);
int main() {
int i,n;
float array[n],mean,sum=0,s2,summation,deno,C[i],elements;
printf("Enter No of Elements\n");
scanf("%d",&n);
printf("Enter Elements\n");
for(i=0;i<n;i++){
scanf("%f",&array[i]);
printf("%f",array[i]);
}
printf("sample variance(s2) : (sum((x-mean)*(x-mean)))/(n-1) /n");
printf("population variance(sigma2) : (sum((x-u)*(x-u))/n");
mean_function(array,n);
for(i=0;i<n;i++) {
deno=((array[i]-mean)*(array[i]-mean));
C[i]=deno;
summation=summation+C[i];
}
s2=((summation)/(n-1));
printf("s2=%f \n",s2);
}
float mean_function(float array[],int n) {
int i;
float sum=0,mean;
for(i=0;i<n;i++){ sum=sum+array[i]; }
mean=(sum/n);
return mean;
}
Why is this code not running after printing of array if I take value
of n>=9?
Some thoughts about your code (and about building programs in steps):
Arrays in C don't change in size once defined. VLAs are out for a variety of reasons. malloc() is in.
Use double, unless there is a specific reason to use floats.
Define and initialize one variable per line. Uninit vars can only result in an error as mentioned by #Jens.
Function declarations at the top (which you have done)
During development, there is no need to complicate things with a scanf (at least initially). It only adds an unwarranted layer of complexity. If you are testing statistical functions (mean, variance), put numbers in a pre-defined static array and verify functionality first.
C[i] as been declared with uninitialized i.
For this initial phase of building this program, I include a basic program.
I am not a fan of zero space between tokens (but ignore that)
Consider calling your array something other than 'array'.
Calculating the size of the samples array allows you to change the number of elements without changing anything else in code; which adds another layer of complexity to an already difficult phase.
#include <stdio.h>
#include <math.h>
double sample_mean(double* p, int n);
int main()
{
double samples[] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 16.5, 2.3};
double mean = 0.0;
int size_samples = sizeof samples/sizeof(double);
printf("size_samples = %d\n", size_samples);
mean = sample_mean(samples, size_samples);
printf("Mean = %.2lf", mean);
}
// -------------------------------
double sample_mean(double* p, int n)
{
double mean = 0.0;
double total = 0.0;
for(int i = 0; i < n; i++)
total += *p++;
mean = total/n;
return mean;
}
Once this functionality is present (saved), you can start working on other stat functions. This way you can work step by step to get closer to the desired outcome.
Next up you can define sample_variance(double* p, int n) and work on that knowing that additional(new errors) are not coming from your code written so far.
Output:
size_samples = 8
Mean = 5.24
I hope it helps.
The code is likely not running because array[n] is declared with an uninitialized n. At the time you read n with scanf(), the array does not automatically "grow into the right size". You should either declare array big enough, or if you really want it to be user-defined, use malloc to allocate it (read the comp.lang.c FAQ) and all Stackoverflow questions tagged array...)
In addition, the scanf at some point fails. Note that when you enter numbers, you also have the "Enter" as a newline ('\n') in the input stream. You never read the newline so the next scanf fails.
This becomes obvious when you actually check the return value from scanf with code like this:
if (scanf("%f", &array[i]) == 1) {
/* successfully converted 1 item */
}
else {
/* scanf failed */
}
Usually what you want is to skip whitespace in the input. You do this by placing a space in the scanf format. Note that a single space tells scanf to skip any amount of white-space.
if (scanf(" %f", &array[i]) == 1) {

String won't allow floating point/ decimal number

I'm learning C and found this code on a tutorial and it works fine, but if I try to make a decimal number (like 5.5), it prints a negative one in the following arrays and loops itself.
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <math.h>
#include "stdafx.h"
#define ARBEITER 3
#define TAGE 5
#define ARBEITSKALENDER kalender();
int zeitkonto[ARBEITER][TAGE];
/* Fehlerausgabe */
void error(int n) {
printf("%d (?) Falsche Eingabe!!\n", n);
}
ABFRAGE0: {
int i = 0, j = 0;
for (i = 0; i < TAGE; i++) {
printf("\n\t[Eingeloggt als: %s ] Tag %d in der Woche\n", vorname, i + 1);
printf("\t-------------------\n\n");
for (j = 0; j < ARBEITER; j++) {
printf("Arbeiter Nr.%d in Std.: ", j + 1);
scanf("%ld", &zeitkonto[j][i]);
if (zeitkonto[j][i] > 24) {
printf("Ein Tag hat nur 24 Stunden?\n");
PCLEAR WHALLOWELT ABSATZ goto ABFRAGE0;
}
if (zeitkonto[j][i] > 47) {
printf("Wer wünscht sich nicht, man hätte mehr Zeit?");
PCLEAR WHALLOWELT ABSATZ goto ABFRAGE0;
}
}
}
}
What am I doing wrong?
If you want floating point numbers in zeitkonto, replace :
int zeitkonto[ARBEITER][TAGE];
by
double zeitkonto[ARBEITER][TAGE];
and replace
scanf("%ld", &zeitkonto[j][i]);
by
scanf("%f", &zeitkonto[j][i]);
and also replace any
printf("...%ld...", zeitkonto[...][...]) ;
by
printf("...%f...", zeitkonto[...][...]) ;
I'm guessing it's the scanf in the kalender function you have problem with.
If you read scanf you will see that the function returns the number of successfully scanned items. In your case, it will return one, zero or EOF.
If scanf returns one, you successfully read an integer. If it returns EOF the user pressed the end-of-file key combination (or there was another error). The case you really have to look out for is when scanf returns zero, which will happen if you enter something unexpected, like a floating point value. If scanf fails (when it returns zero or EOF) it will not change the value of the variable.
The question have been edited, and I see that I was focusing on the wrong scanf. However, my answer (including the hints on how to solve the problem) is still valid.
If you do want to be able to read floating point numbers, you should of course change the format to "%f" or "%lf", and you must also change the array base type from int to float or double.
zeitkonto is an array of integers - whole numbers. You need fractional numbers, in particular floating point. That means using double and %lf to read them.

Pascal's Triangle returning nonsense values

This is a homework project I was assigned some time ago... I've been successful in getting this far on my own, and the only hiccup I have left is (I believe) an issue with data types and overflow.
I've tried changing over to unsigned and double, and the code complies and still accepts input in the terminal, but it seems to hang up after that... nothing is printed and it looks like it's caught in a loop.
Here is the code...
/* pascaltri.c
* A program that takes a single integer as input and returns the nth line of
* Pascal's Triangle. Uses factorial() function to help find items of
* individual entries on a given row.
*/
#include <stdio.h>
#include <stdlib.h>
long factorial(long i)
{
long fact = 1;
while(i > 1)
{
fact = fact * i;
i = i - 1;
}
return fact;
}
main(void)
{
long n;
long *nPtr;
nPtr = &n;
scanf(" %i", nPtr);
if (n >= 0)
{
long k;
long *kPtr;
kPtr = &k;
for(k = 0; k <= n; k++)
{
long ans;
long *ansPtr;
ansPtr = &ans;
ans = factorial(n) / (factorial(k) * factorial(n - k));
printf("\n %i", ans);
}
return 0;
}
return 0;
}
It's not perfect or pretty, but it works up to an input of 13 (that is, row 14) of the triangle. Beyond that I start getting gibberish and even negative values sprinkled throughout the returns... much larger values break the code and return nothing but an exit error message.
Any ideas on how I can correct this problem? I've been staring at the screen for much to long to really see anything myself. Also, it's not essential, but I would like to print my return values on one line, rather than having them separated by a newline character.
1 5 10 10 5 1
Would the easiest way be to load the values into an array as they are computed, and then print the array? Or is there a built-in way I can tell the print statement to occur on only one line?
You are suffering from integer overflow. You may need to find a different approach to the algorithm to avoid having to calculate the large numbers.
In answer to your other point about the newline, you are explicitly printing the newline with the \n in your print statement. Remove it, and you will get answers printed on one line. You probably want to inlucde a final printf("\n"); at the end so the whole line is terminated in a newline.
Some other observations:
You don't need the first return 0; - the control will drop out of
the bottom of the if block and on to the second (should be only)
return 0; and not cause any problems.
You're declaring kPtr but not using it anywhere
You don't need to declare a separate variable nPtr to pass to scanf; you can pass &n directly.
For the garbage, you are most likely running into an integer overflow, that is, your calculated values become too large for the long data type. You should correct it by calculating your factorial function without explicitely calculating n!.
Change scanf(" %i", nPtr); to
scanf(" %ld", nPtr);
and printf("\n %i", ans); to
printf("\n %ld", ans);
to get printout on one line, use:
printf(" %ld", ans);
If you are using gcc, turn on warnings, i.e. use -Wall.

Averaging 3 integers

My assignment is to fix the code. I have my edited code below and the original code below that. I figure I still have a few errors in here. My error checking doesnt seem to work, and I am not sure if my getchar() function is written or working properly.
Please assume I know nothing becasue that is fairly accurate.
The code compiles, but the answer is always 2. I am about 4 hours into this piece of code with 3 more to work after this.
My code
#include <stdio.h>
double get_number(double num);
main () {
double n1,n2,n3;
double average;
printf("\nCompute the average of 3 integers\n");
printf("--------------------------------\n");
n1 = get_number(1);
n2 = get_number(2);
n3 = get_number(3);
average = (n1 + n2 + n3)/3;
printf("The average is %0.2f\n",average);
}
double get_number(double num) {
double value = 0;
char c;
int i;
printf("Please input number %d: ", num);
while (c = getchar != '\n') {
if ( (c>9) || (c<0) ) {
printf("Incorrect character entered as a number - %c\n",c);
return(0);
}
else {
value = num;
}
}
return(value);
}
Original code
#include <stdio.h>
main () {
double n1,n2,n3;
double average;
printf("\nCompute the average of 3 integers\n");
printf("--------------------------------\n");
n1 = get_number(1);
n2 = get_number(2);
n3 = get_number(3);
average = (n1 + n2 + n3)/3;
printf("The average is %0.2f\n",average);
}
double get_number(int num) {
double value = 0;
char c;
printf("Please input number %d: ", num);
while (c = getchar() != '\n') {
if ( (c<=9) && (c>=0) ) {
printf("Incorrect character entered as a number - %c\n",c);
exit(-1);
}
else {
value = 10*value + c - '0';
}
}
return(value);
}
A few issues:
1. You should be using '9' and '0', since you want the ASCII values for digit '9' (0x39) and '0' (0x30), not 0x9 and 0x0.
if ( (c>'9') || (c<'0') ) {
2. != has higher precedence than =, so you need parens. Learn operator precedence, and if you're in doubt, use parens:
3. getchar is a function not a variable.
while ((c = getchar()) != '\n') {
4. You use the wrong conversion. num is a double, so you would need %f. Or, you could make num a int.
printf("Please input number %f: ", num);
5. You never actually use c in any way (except error checking). You always return 0 or num (see your else clause), which makes no sense. The else body of the original is correct.
You got the floating point parsing all wrong and shouldn't be doing it yourself. There's an easier way:
double get_number(double num) {
double value = 0.0;
printf("Please input number %lf: ", num);
scanf("%lf", &value);
return(value);
}
The issues with the original program are:
getchar() returns an ASCII code, and the condition was wrong. When checking for boundaries, use ((c<'0') || (c>'9')).
For the exit function you need to include "stdlib.h".
For the main function to understand what is get_number, you need to either move the function to be before the main function, or you can use a forward declaration.
The assignment operator (=) has lower precedence than the inequality operator (!=), so you need to use parenthesis, like: ((c = getchar()) != '\n')
You have actually created several more issues, so I wouldn't rely on your code.
In any case, in general - it is advised you study how to use a debugger. Once your code is compiling (and for that you'll need to get accustomed to the compilation error messages), you need to start debugging your code. I suggest you take some time to learn how to set breakpoints, set watches, and go step by step into your code. That skill is absolutely essential for a good developer.
Here's how I'd go about correcting the code ...
http://ideone.com/a0UMm -- compilation errors
http://ideone.com/ljUg1 -- warnings, but it works now
http://ideone.com/Qd0gp -- no errors, no warnings, test run ok
For 1. I used the "original code" as posted by you.
For 2. I used int main(void), declared the function get_number before defining main, added parenthesis in line 20, and added #include <stdlib.h>
For 3. I added return 0; before the final } of main. I also removed the extra output that messed up the ideone interface (it looks better on an interactive interface)
Edit more tests needed to complete the task of correcting the original code

Resources