Bill Cunningham said:
I have this code snippet that won't compile with gcc -c and I get errors
of needing casts. This is untested code of course and I thought I'd ask for
opinions on what I've done wrong.
I'll make a few general remarks...
#include <stdio.h>
void *get(void *pv)
{
double price;
long int date;
unsigned int number;
int check;
FILE *fp;
if ((fp = fopen("num", "r")) == NULL) {
perror("fopen error");
return 1;
}
if ((check = fscanf(fp, "%u %f %l", &number, &price, &date)) == EOF) {
(you need %lf to read a double. %f is for float)
printf("%d\n", ferror(fp));
clearerr(fp);
return 1;
}
This is an example of what I'd call programming upside down. Look at
all the detail there: the file name, the format, the error messages, the
clearing of the IO error and so on, but *no code to do any real work*.
You've started walking, but you have no idea where you are going. A
clue to that is the function prototype. The name is entirely
noncommittal, and while there are valid uses of void *, here I think
they mean "I don't know what I need to pass to this function and I have
no idea what it should return".
When I program, I usually start with an outline of the overall behaviour
i.e. I start with main. This is broken down into functions that can do
the constituent parts of the job. Even these functions are often
written in outline first with the focus on what they actually do. The
parts you've worked out in detail, I will leave for later. For one
thing, I want to start testing as soon as possible, so I need a function
that works right away. If I find, either in testing or when finishing
these sketched functions, that things are going wrong, I can change the
design before I've sunk too much effort into it.
So my functions usually start out having a very specific name and
prototype:
double get_stock_price_on_date(FILE *fp, long int date)
but the body will often be what's called a stub:
double get_price_on_date(FILE *fp, long int date)
{
// Rewind file.
// Loop until third field equals date
// If date not found I'll return a negative price.
return 42;
}
Once it's all written like this I can start testing and filling in
the details as I go. If you can't do this, it is often because you
don't know, in enough detail, what your program is to do. It's almost
impossible to program with out a clear objective, so when I find myself
unable to sketch things out like this, it means I need to think more
about my objectives.
A detail: always test for fscanf success. As you say elsewhere the
returns are complex but if it returns 3 you got the three things you
need and you can do what you need to with them. You can (at least
initially) treat any return that is not 3 as an error. You can waste
ages dealing with all the various ways in which things have gone wrong,
so start instead with writing what happens when the input worked.