I am in process of rewriting my CS50 credit solution to use functions.
Stumbled upon error when defining readCardNumber().
long long readCardNumber()
{
do
{
long long result = get_long_long("Enter card number to verify: \n");
if (result < 0)
{
printf("Retry: \n");
}
}
while (result < 0);
return result;
}
I am using the CS50.h https://reference.cs50.net/cs50/get_long_long to get number. I cannot compile this solution because of :
error: use of undeclared identifier 'result'
Can someone experienced please explain whats the issue here? I did declare function at beginning of my code and declared and initialised result in function.
What would be a better way to validate that number?
https://docs.cs50.net/2018/x/psets/1/credit/credit.html - Spec for solution I am trying to rework.
The result variable is declared inside of the do...while block. It is not visible outside of the block, which includes the condition of the while.
You need to move the variable definition outside of the loop:
long long result;
do
{
result = get_long_long("Enter card number to verify: \n");
if (result < 0)
{
printf("Retry: \n");
}
}
while (result < 0);
It is a matter of scopes. In C, a scope is defined by { and }. A variable ceases to exist at end of the scope it is declared within. (Well, static variables don't but they get unaccessible. Unless you have pointers to them.)
What you need to do is to move the declaration outside the loop.
I do however want to emphasize that it is a VERY good practice to declare variables within the scope that they are used. It reduces the risk of bugs significantly. If a variable is only used inside a loop, then declare it inside the loop. It is basically the same reason as why you should not use globals unless necessary.
You do return result; when result is out of scope. But your code contains redundancy: you test result < 0 twice. I would recommend changing the structure to avoid this, with bonus side-effect of fixing the original problem:
long long readCardNumber(void)
{
for (;;)
{
long long result = get_long_long("Enter card number to verify: \n");
if (result >= 0)
return result;
printf("Retry: \n");
}
}
This is one of those inconvenient or even "unnatural" things about do/while statement: everything you declare inside the cycle body will not be visible to the condition in the while portion of the statement. The scope of those identifiers ends at the } before the while portion.
This often forces the user to declare the variable(s) before the cycle
long long result;
do
{
result = get_long_long("Enter card number to verify: \n");
if (result < 0)
printf("Retry: \n");
}
while (result < 0);
The price to pay for this solution is
unnecessary extension of result's scope beyond the cycle
it is no longer possible to meaningfully initialize the variable at the point of declaration
For many of us this is so unpleasant that we prefer to switch to the do/while(1) approach with break in the middle to terminate the cycle
do
{
long long result = get_long_long("Enter card number to verify: \n");
if (result >= 0)
break;
printf("Retry: \n");
}
while (1);
This is also not perfect, obviously. Chose for yourself, which approach you like better.
In the latter case do/while(1) serves as an "idiomatic" way to express a cycle with exit from the middle. Other people might prefer for (;;) or while(1) for that purpose, thus avoiding do/while statement altogether.
Related
When I compile this simple code the output is the above error.
So how to declare finalTotal outside while loop?
while (total<endn)
{
int finalTotal = (total + total/3 - total/4);
}
printf("no of years is %i\n", finalTotal)
NOTE:total and endn are part of the total code but not necessary for the question.
You can simply move the declaration of finalTotal as an int to before the loop.
int finalTotal = 0; // declare and initialize to 0 in case while loop does not run
while (total<endn)
{
finalTotal = (total + total/3 - total/4);
}
printf("no of years is %i\n", finalTotal)
This does look like an infinite loop though, as neither total nor endn seems to change.
You need to read up on scope. Variables can only be accessed within their scope. Since you declare int finalTotal inside of the while loop, only other statements inside of the while loop can access it.
Instead you need to declare your variable in the outer scope, so that the following printf can access it.
For example:
int finalTotal; // Declared outside of the while loop.
// You may want to consider initializing it
// with some value in case the while-loop
// never executes. (Such as -1 or something
// to signal an invalid number of years).
while (total<endn) // NOTE: This may infinite loop. Perhaps a typo?
{
// This scope has access to `finalTotal` since it was declared
// by an outer scope.
finalTotal = (total + total/3 - total/4);
}
// Now `finalTotal` can be accessed here, since it's within the same
// level of scope and not stuck inside the scope of the while-loop
// curly braces.
printf("no of years is %i\n", finalTotal)
As mentioned by others, another problem is that the while loop may never terminate since total and endn are not changing inside of the while loop. So it will potentially iterate forever.
Perhaps this was intended to be while (finalTotal < endn).
so i was going to run a function in an infinite loop which takes a number input, but then I remembered I codn't do
while (true) {
myfunc(scanf("%d));
}
because I need to put the scanf input into a variable. I can't do scanf(%*d) because that doesn't return value at all. I don't want to have to do
int temp;
while (true) {
scanf("%d", &temp);
myfunc(temp);
or include more libraries. Is there any standard single function like gets (I cod do myfunc((int) strtol(gets(), (char**) NULL, 10)); but its kinda messy sooo yea)
srry if im asking too much or being pedantic and i shod do ^
btw unrelated question is there any way to declare a string as an int--- or even better, a single function for converting int to string? I usually use
//num is some number
char* str = (char*) malloc(12);
sprintf(str, "%d", num);
func(str);
but wodnt func(str(num)); be easier?
For starters, the return value of scanf (and similar functions) is the number of conversions that took place. That return value is also used to signify if an error occurred.
In C you must manually manage these errors.
if ((retv = scanf("%d", &n)) != 1) {
/* Something went wrong. */
}
What you seem to be looking for are conveniences found in higher-level languages. Languages & runtimes that can hide the details from you with garbage collection strategies, exception nets (try .. catch), etc. C is not that kind of language, as by today's standards it is quite a low-level language. If you want "non-messy" functions, you will have to build them up from scratch, but you will have to decide what kinds of tradeoffs you can live with.
For example, perhaps you want a simple function that just gets an int from the user. A tradeoff you could make is that it simply returns 0 on any error whatsoever, in exchange for never knowing if this was an error, or the user actually input 0.
int getint(void) {
int n;
if (scanf("%d", &n) != 1)
return 0;
return n;
}
This means that if a user makes a mistake on input, you have no way of retrying, and the program must simply roll on ahead.
This naive approach scales poorly with the fact that you must manually manage memory in C. It is up to you to free any memory you dynamically allocate.
You could certainly write a simple function like
char *itostr(int n) {
char *r = malloc(12);
if (r && sprintf(r, "%d", n) < 1) {
r[0] = '0';
r[1] = '\0';
}
return r;
}
which does the most minimal of error checking (Again, we don't know if "0" is an error, or a valid input).
The problem comes when you write something like func(itostr(51));, unless func is to be expected to free its argument (which would rule out passing non-dynamically allocated strings), you will constantly be leaking memory with this pattern.
So no there is no real "easy" way to do these things. You will have to get "messy" (handle errors, manage memory, etc.) if you want to build anything with complexity.
Suppose I have the variable counter. If I need to:
access and modify the variable from many places in the code
make sure that the variable is modified in the "correct" way,
is this solution adequate, or are there more efficient/cleaner ways to do it?
int counter_access(int value) {
static int counter = 0;
if (value > 100) {
printf("there is a bug in the code");
return counter;
}
counter += value;
return counter;
}
And then when I need to modify the variable:
counter_access(10); /* increase counter by 10 */
counter_access(-2); /* decrease counter by 2 */
And when I need to access the variable:
if (counter_access(0) == 100) do_something();
This solution seems rather kludgy to me. However, I can't think of very many good ways to do this. I could use global variables (which cause bugs). I could pass the address of counter to the functions which need it, but that doesn't make sure that the variable isn't modified in an incorrect way (in the example above, if counter is incremented by more than 100, there is an error).
Essentially, the problem with using a function to access the variable is that there isn't a satisfactory way to tell the caller that the value is incorrect.
Using a single function for things like this is a good option for single threaded programs, you just need to set up things in the proper way.
To signal that something went wrong you can use some "out of the range" value. In your case the counter range is 0 .. 100.
You may have something like:
#define COUNT_OVERFLOW -1
#define COUNT_UNDERFLOW -2
#define counter_get() counter_add(0)
int counter_add(int incr)
{
static int counter = 0;
int counter_temp;
counter_temp = counter +incr;
if (counter_temp < 0) return COUNT_UNDERFLOW;
if (counte_temp > 100) return COUNT_OVERFLOW;
counter = counter_temp;
return counter;
}
Now, to detect an error you may check if the return value is < 0:
cnt = counter_add(x);
if (cnt < 0) {
fprintf(stderr,"There is a bug in the code\n");
}
....
if (counter_get() == 100) {
printf("DONE!\n");
}
Note as the value of counter is preserved even if there's an error. Also, it's better not to have functions like your counter_access() printing error messages, it's better to check the return value and make the caller print it (if it is so inclined).
I added the macro counter_get() to avoid having the user remember that adding 0 has the side effect of returning the current counter value.
As mentioned before, in more complicated cases you shouldn't use static variables (or equivalently, global variables). In those cases the proper way is to have a struct that is instatiated for each thread and keeps the variables that are relevant for that thread state. You will have to pass a pointer to that structure around and having the counter_access() function accepting it as a parameter.
Looking closely, you can see that here we are trying to mimick the object-oriented approach of encapsulating data and operations. In this case we implemented (implicitly) a single instance of an object (the counter) that has two methods: one to change the value and one to get the value.
I am new to programming and I am currently learning the C language. This is my code. I have tried different fixes, such as making sure I have my semicolons. However, when I go to check my code in the online compiler, I always get unused variable and data definition has no type or storage class. Any information would help me, I assure you, so please let me know what you think a possible solution could be.
//C code
//This program will calculate the average speed of passing cars using a WHILE-END loop
//Developer: Jasmine Tucker
//Date: 7 Sept 2014
#include <stdio.h>
Int main ()
{
/* define variable */
int average_speed;
int car_count;
int car_speed;
};
/* set variable values */
average_speed= 0;
car_count=0;
car_speed=0;
/*WHILE-END loop */
WHILE (car_count > 0)
{
printf (“Enter the car’s speed %s:”, car_count);
scanf (“%d”, & car_speed);
average_speed= car_speed/ car_count
car_count++;
}
printf (“\n The average speed is %d miles per hour. \n”, (average_speed));
return 0;
}
A Few Things:
Int main()
should be
int main()
This is perhaps an easy typo, or the unfortunate side effect of a grammar check.
You could probably do well by studying the standard types in C.
Modifiers aside, there are not very many, and except for special types, _Bool, _Complex, _Imaginary, they are lowercase. (The same holds true for keywords).
Storage class refers to something less commonly used, or at least out of the scope of this program (auto,register,static,extern).
The following definitions use the int type as well, so I will reproduce them here [sic].
/* define variable */
int average_speed;
int car_count;
int car_speed;
};
/* set variable values */
average_speed= 0;
car_count=0;
car_speed=0;
As others have mentioned, there is an extraneous curly brace after the three variables are declared. };
(Notice how sad he looks.)
If you are coming from a language that requires semi-colons after curly braces, you have some hard habits to break.
In any case, commenting that out should remove several errors:
/* }; */
as this is effectively closing the block for main().
As user haini pointed out, you could actually pull the variable definitions outside of main(), allowing them to be accessible to any function. (Use across source files would bring up the aforementioned extern).
Some programmers use special varaible [pre|suf]fixes to distinguish global from local variables.
int g_average_speed;
int g_car_count;
int g_car_speed;
As these variables need to be initialized before use, you can do this in the definition:
int g_average_speed = 0;
int g_car_count = 0;
int g_car_speed = 0;
Often, the use of global variables is discouraged, preferring instead parameter-based sharing of variables, which makes more sense once you introduce multiple functions.
As mentioned, 'WHILE' is not a keyword, while while is. As with the variable types, the list of keywords is very short, and mostly lowercase. It is good to know the keywords so as to avoid using them for variable/function naming.
As far as logic is concerned, your while-loop will never begin, as the expression car_count > 0 will not be satisfied as you've initialised car_count to 0.
While it's easy to hard-code a value, you may probably want to set another variable such as max_cars to an upper limit and check for car_count < max_cars. (Don't forget you're counting from 0).
/* define variable */
int max_cars = 10;
/* rest of variables, init */
while( car_count < max_cars )
Now, aside from the interesting quotations '“' which will give you trouble, and the missing semicolon at average_speed = car_speed / car_count as pointed out again by haini, you should try to step through your loop mentally. Don't ever forget that users are inherently evil and will attempt possibly unforseen values when allowed to interact with the program (scanf()). Negative values and 0 are not out of the question with int and %d, though you may expect some cars to be 'parked' and thus speed 0. Down the line, the unsigned modifier and %u may be of use.
In any case, it's good to get in the habit of sanitizing user input, and/or giving the user an option to opt-out (i.e. "TYPE -1 to break..." ), and checking for invalid or exit codes with an if. (break may be the keyword to pursue in this case)
Your average_speed calculation doesn't quite seem right. Don't forget you're storing values into integers, so you're gonna have some rounding errors.
First think about what happens when your initial case arrives -- what is car_count, and what happens when you divide by that value?
Then, think about the final case, (assuming your upper boundary is 10) in which car_count == 9. You will be assigning car_speed / car_count to average_speed. Is this really what you want?
You can minimize rounding errors and more difficult calculation by maybe 'keeping track' of the total of the speeds, and only one average calculation.
/* define variable */
int total_speed = 0;
In your while loop:
total_speed += car_speed;
or
total_speed = total_speed + car_speed;
And then outside of the loop:
average_speed = total_speed / (car_count - 1);
(The adjustment to car_count is necessary because the value increments after the final loop.)
NOTE: in this limited example, the average_speed variable may not be necessary, unless used outside of the printf().
There are a few issues in your code that I see.
The code will never get in the while loop. If you initialize it to 0, it will never be greater than 0, so will never enter the loop.
Even if it gets into the loop, this is an infinite loop. Keep adding one to a variable would make it so the variable is always greater than 0, so will never exit the loop.
MAJOR ONE: your variables are inside main, but you are using them outside of main!
#include <stdio.h>
Int main ()
{
/* define variable */
int average_speed;
int car_count;
int car_speed;
**};**
(Not sure about this one) but you have an uppercase I in the word int in your method declaration, and uppercase WHILE, should be while.
Code that is not within the main() function causes your errors.
//C code
//This program will calculate the average speed of passing cars using a WHILE-END loop
//Developer: Jasmine Tucker
//Date: 7 Sept 2014
#include <stdio.h>
/* define variable */
//You Can define global variables or local variables. If you want to use them outside your
//function you Need to declare them globally as done here
int average_speed;
int car_count;
int car_speed;
//This is where the Magic happens. If you execute your program it will jump to the main
//function and execute whatever is in there
int main ()
{
/* set variable values */
average_speed= 0;
car_count=0;
car_speed=0;
/*WHILE-END loop */
//The while Loop is not a function, you Need to put it in main() so it gets executed
while(car_count > 0)
{
//You did use very strange signs here. The correct ones are These: ""
printf("Enter the car’s speed %s:", car_count);
scanf("%d", &car_speed);
average_speed= car_speed / car_count; //You Forget a semicolon indeed ;-)
car_count++;
}
printf("\n The average speed is %d miles per hour. \n", average_speed);
return 0;
} //semicolons at the end of a function are not used in C. They are used if you want to define a structure.
I strongly suggest that you start off with basic books / a wiki to C programming. Here is a good (at least it was for me) start into that: http://en.wikibooks.org/wiki/C_Programming/Intro_exercise
I have some code that should do a simple thing :
if the value of the parameter is -1 then I should change the value.
else - do nothing
I have a list of 20 parameters, but I wanted to know if there is any way of checking it without doing :
if param1 == -1 then ... else...
if param2 == -1 then.... else...
anyone has any idea what can I do to make it more efficient ?
thanks!
If parameters are all variables (it's not in array or something), you can make a function and write
change_or_let_it_be( ¶m1, value );
change_or_let_it_be( ¶m2, value );
change_or_let_it_be( ¶m3, value );
and there you have only one if (in function) and a lot of calls.
Better would be to store it in some structure (array, list etc) and avoid calling this function 20 times.
Not sure if I'm understanding what you want, but how about this?
void func(int params[20]) {
for (int i = 0; i < 20; ++i) {
if (params[i] == -1)
params[i] = NEW_VALUE;
}
}
Checks every value with a for, so you don't need to hardcode all the different values, and then changes the parameter when it's -1. Also note that I'm supposing with "efficient" you mean more code-writing-time efficient here!
To be honest the series of if/then statements is the most efficient, if not the prettiest solution! Embedding the tests in a loop and storing the parameters as an array requires the following additional calculations:
- testing that the loop counter does not exceed the maximum
- incrementing the loop counter
- using pointer arithmetic to access each parameter
Of course these speed considerations are only a factor if you have to perform those 20 tests man many times. But in fact you've already written it as efficiently as possible :)
Another cleaner solution:
int *p[] = {¶m1, ¶m2, ¶m3, NULL};
int i = 0;
for(;p[i] != NULL; i++) {
if(*p[i] == -1) *p[i] = SOME_VALUE;
}