You define what is right and wrong, so it is up to you, but as a general rule you don't want your program logic in asserts (so checking the length of an input string is a poor use).
Just remember: assert is only active in debug mode, and so if you rely on it for error checking (like almost all of your examples), you will have weird things happening in release mode.
i.e. assert is normally a define like:
/* assert() only does something if NDEBUG is NOT defined */
#ifdef NDEBUG
#else
#define assert(x) _assert(x)
#endif
See Where does the -DNDEBUG normally come from? for more info on NDEBUG
You definitely don't want to change the flow using asserts e.g.
assert(some_function()); /* some_function only called if NDEBUG is not defined */
Using assert
to check the return of malloc
: If NDEBUG is not defined the check is not done, so in theory you can go off and access a NULL pointer. I'd say it is NOT safe. See Handling error checking with assert more discussion.
Lets look at your asserts one by one through the simple "only in debug" filter:
assert(argc==2);
/*
* If NDEBUG is defined and argc == 1 you get through,
* so anything that uses argc[1] will give undefined behavior.
* = BAD USE
*/
char *s = malloc(N);
/* 2 */
assert(s!=NULL);
scanf("%s", s
/*
* If NDEBUG is defined and malloc fails you keep going and read into
* NULL = undefined behaviour = BAD
*/
assert(strlen(s)<N);
/*
* If NDEBUG is defined keeps going even in strlen >= N.
* How bad that is depends on the code - if you are checking the size
* before putting it in a buffer, then it's bad.
* To me it is logic in the assert and so I say BAD
*/
/* 4 */
assert(!*(s+strlen(s)));
/*
* First of that's just silly code.
* If that comes to my code review you'll be removing or rewriting
* it - strlen relies on the NUL, so how can it fail?
* It is logic in the assert - If NDEBUG is set you'll keep going
* even if the condition is not met. How bad that is?
*/
/* 5 */
assert(atol(s));
/*
* Whoa. If NDEBUG is set and s = "Hello" we still keep going...
* What is atol("Hello") ?
*/
printf("%ld\n", 100000000/atol(s));
free(s);
return 0;
}
int f(char *s)
{
/* 6 */
assert(s!=NULL);
/*
* Again if NDEBUG is defined the check disappears and so if s = NULL
* then you dereference a NULL pointer which is undefined behavior
*/
return !*s;