Jon Howson said:
Hello
I was reading thru some (yellowing!) mimeographed introductory notes on C
and I found code like the below.
main(argc,argv)
int argc;
char *argv[];
{
char *malloc();
char *strcpy();
int puts();
void free();
char *s;
if(argc>1 &&(s=malloc(8+strlen(argv[1])))){
strcpy(s,"Hello, ");
strcpy(s+7,argv[1]);
puts(s);
free(s);
}else{
puts("Program failed, unknown error");
}
}
I'm trying to work out what's happening. At the start of the function, I
guess the parameters are being converted into local variables, maybe a
way to get pass-by-value in C? [snip]
Just a few clarifications/additions to points made in other responses.
1. This style of parameter declaration (dating from more than 30
years ago, before C was standardized) is labelled 'obsolescent'
by the Standard. That means it's accepted now but don't count
on it being so in future revisions of the Standard. (On the other
hand it has been obsolescent for more than 20 years now.)
2. The newer (ie, current) style of parameter declarations is called
"prototypes", as for example
int main( int argc, char *argv[] ){ ... }
3. The prototype style of parameter declaration allows (and requires)
any call after the prototype declaration to have the types of its
arguments checked against the parameter types given in the prototype.
In contrast, the old style of parameter declaration does not do
such type checking (and the Standard says specifically that such
type checking will not be done).
4. The argument values are passed the same way in both cases,
except that, when old-style parameter declarations are used,
the parameter types are adjusted in some cases to reflect the
lack of knowledge about the types used. For example, a parameter
declared as 'char' will be passed as 'int' (or 'unsigned int' in
some implementations).
5. Except for the change of types mentioned in (4), how parameters
are used in function bodies is the same for both old-style and
the prototype form of parameter declaration.
6. Most people advise using the prototype declaration style when
writing any new code. I myself follow that advice in most cases
(and refrain now from trying to explain any of the exceptions).
7. For existing code using the older-style (aka "K&R style")
declarations, the most obvious benefit of changing it over to the
prototype form is better type checking. There are however two
gotcha's worth noting. One, the higher level of type checking
could produce compilation errors even though the code in question
works fine. (Of course it's also possible the code doesn't work
fine, and the type checking showed a problem.) Two, because of
the different rules for how parameter types work, it's possible
for a change that looks innocuous at face value to turn working
code into non-working code (and probably also the reverse, but I
think that's even less likely). So those changes are not ones
that should be made completely mindlessly and automatically.
8. (I'm skipping the question about the local function declarations
for malloc(), etc, because I don't have anything to add about
that here.)