Platonic said:
Hi-
I am learning C from some old lecture notes, but they don't have
solutions so I'd like some feedback on my code if anyone has the time.
Judging from your code, these are extremely old lecture notes. If there
is a date on them, I would guess it to be somewhere in the 1980's.
Since that time, C has evolved a bit. Not too much but enough that it
would be worthwhile to have a more recent book to accompany these
lecture notes.
I would suggest you get a copy of "The C Programming Language", second
edition, by Kernighan and Ritchie (often referred to as K&R2)
This is an exercise: "Write a program to trim any leading whitespace
from a string and return a newly allocated buffer containing the
trimmed string. Don't forget to handle errors."
To use library functions, you should #include the appropriate headers.
For this program, you need
#include <stdio.h> /* for puts() */
#include <stdlib.h> /* for malloc()/free() */
#include <ctype.h> /* for isspace() */
#include said:
main(argc, argv)
int argc; char **argv;
This style of declaring parameters is considered to be outdated.
It is preferred that you write it now like this:
int main(int argc, char **argv)
It is not wrong to declare a function at this point, but it is not
considered to be good style.
It is recommended that you declare functions at file scope, and that you
give a prototype for the function.
The prototype for strtrim() looks like
char *strtrim(char*);
The advantage of a prototype is that the compiler can verify (and
complain!) that you call the function in the correct way.
As a more personal style issue, I prefer to have one item per
declaration. I would have written the above declaration as:
char *strtrim(char*);
char *r;
I also might have used a more descriptive name for r.
puts(argc>1 && (r=strtrim(*++argv)) ? r : "Unspecified error");
C allows you to write extremely complex expressions, but usually it is
best to avoid using that freedom. (exception: IOCCC entries)
The statement above is right at the limit of how complex you should make
it (and some would argue it is over the limit).
As main() returns a success/failure code to the OS, you should make sure
that it is a sensible code:
return 0; /* indicates success. Other code are EXIT_SUCCESS and
EXIT_FAILURE */
}
/* trims initial whitespace */
char *strtrim(s)
char *s;
Same comment as with main(): you should place the argument type also
within the parentheses.
char *strtrim(char *s)
You should not write a declaration for library functions, like malloc().
Instead you should #include the required header (see above).
for( ; isspace(*s); s++);
r=malloc(strlen(s)+1);
if(r)
strcpy(r,s);
return r;
}
This looks OK to me and works correctly, but the compiler produces
some mysterious warnings about conflicting definitions that I don't
really understand.
Those warnings are probably due to the required headers that you forgot
to include.
Modern compilers will complain if the encounter a call to a function
that they have not yet seen before (like your calls to puts, isspace
and strcpy). The complaints are because the compiler has to make some
assumptions that are likely to be wrong.
BTW, if you have questions about compiler messages, it works so much
better if you post the compiler output (along with the code you fed
into the compiler). Most of us will know immediately what it means,
because we have seen the message before.
Bart v Ingen Schenau