0

Since I found this particular documentation on https://www.tutorialspoint.com/c_standard_library/c_function_rand.htm,I have been thinking about this particular line of code srand((unsigned)time(&t));.Whenever I had to generate some stuff,I used srand(time(NULL)) in order not to generate the same stuff everytime I run the program,but when I came across this,I have been wondering :Is there any difference between srand((unsigned)time(&t)) and srand(time(NULL))?Because to me they seem like they do the same thing.Why is a time_t variable used?And why is the adress operator used in srand()?

#include <stdio.h>
#include<stdlib.h>
int main(){
    int i,n;
    time_t t;

    n = 5;

    srand((unsigned)time(&t)); 

    for (i = 0; i < n; i++) {
        printf("%d\n", rand() % 50);
    }
return(0);
}
klutt
  • 30,332
  • 17
  • 55
  • 95
Neri-kun
  • 173
  • 3
  • 14
  • 2
    Just because it's on the internet, doesn't mean it's good. Something to remember. – Mark Benningfield Apr 17 '19 at 15:49
  • 3
    That's not a bit operator, but an *address-of* operator. – Ignatius Apr 17 '19 at 15:50
  • What do you mean? – Neri-kun Apr 17 '19 at 15:50
  • @Taegyung I'm sorry,you're right.I wasn't paying attention to the context this operator was used. – Neri-kun Apr 17 '19 at 15:53
  • You can find out how `time` is being invoked by researching the [`time` library function](https://en.cppreference.com/w/c/chrono/time). It explains what is happening. The cast is something you should be familiar with (and generally avoid unless you know what you're doing, and likely even then). – WhozCraig Apr 17 '19 at 15:55

1 Answers1

6

Yes, it will yield the same result. But the example is badly written.

I would be careful reading Tutorialspoint. It's a site known for bad C code, and many bad habits you see in questions here at SO can be traced to that site. Ok, it's anecdotal evidence, but I did ask a user here why they cast the result of malloc, and they responded that they had learned that on Tutorialspoint. You can actually see (at least) four examples in this short snippet.

  1. They cast the result from the call to time() which is completely unnecessary and just clutters the code.
  2. For some reason they use the variable t, which is completely useless in this example. If you read the documentation for time() you'll see that just passing NULL is perfectly adequate in this example.
  3. Why use the variable n? For this short example it's perfectly ok with a hardcoded value. And when you use variables to avoid hardcoded values, you should declare them const and give them a much more descriptive name than n. (Ok, I realize I was a bit on the edge when writing this. Omitting const isn't that big of a deal, even if it's preferable. And "n" is a common name meaning "number of iterations". And using a variable instead of a hard coded value is in general a good thing. )
  4. Omitted #include<time.h> which would be ok if they also omitted the rest of the includes.
  5. Using int main() instead of int main(void).

For 5, I'd say that in most cases, this does not matter for the main function, but declaring other functions as for example int foo() with empty parenthesis instead of int foo(void) could cause problems, because they mean different things. From the C standard:

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

Here is a question related to that: What are the semantics of function pointers with empty parentheses in each C standard?

One could also argue about a few other things, but some people would disagree about these.

  1. Why declare i outside the for loop? Declaring it inside have been legal since C99, which is 20 years old.
  2. Why end the function with return 0? Omitting this is also ok since C99. You only need to have a return in main if you want to return something else than 0. Personally, in general I find "it's good practice" as a complete nonsense statement unless there are some good arguments to why it should be good practice.

These are good to remember if your goal is to maintain very old C code in environments where you don't have compilers that supports C99. But how common is that?

So if I got to rewrite the example at tutorialspoint, i'd write it like this:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(void){
    srand(time(NULL)); 

    for (int i = 0; i < 5; i++) {
        printf("%d\n", rand() % 50);
    }
}

Another horrible example can be found here: https://www.tutorialspoint.com/c_standard_library/c_function_gets.htm

The function gets is removed from standard C, because it's very dangerous. Yet, the site does not even mention that.

Also, they teach you to cast the result of malloc https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm which is completely unnecessary. Read why here: Do I cast the result of malloc?

And although they mention that malloc returns NULL on failure, they don't show in the examples how to properly error check it. Same goes for functions like scanf.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • It is kind of ironic the fact that sometimes my laboratory professor at Algorithms Design gives us a link to study some theoretical aspects about data structures such as Doubly-Linked Lists: https://www.tutorialspoint.com/data_structures_algorithms/doubly_linked_list_program_in_c.htm and every time I see code like that it makes me go nuts. – Neri-kun Apr 17 '19 at 16:08
  • 2
    You should `#include ` and maybe use `int main(void)`. Also I prefer `srand(time(0))` :) – pmg Apr 17 '19 at 16:48
  • 1
    @pmg time.h fixed. However, I rarely care about void parameters, and especially not for main. Also, I prefer time(NULL) since the argument to time is a pointer. – klutt Apr 17 '19 at 20:25
  • @pmg Also, for this purpose, You could write a wrapper. `void srand(void) { srand(time(NULL)); }`, but since you usually call `srand` just one per program execution I don't see the point. – klutt Apr 17 '19 at 20:33
  • @Broman: for pointless things, I'd go with `#define INIT_RNG srand(time(NULL /* or 0 */))` :) – pmg Apr 17 '19 at 21:15
  • @pmg Actually, it would work with `time(NULL || 0)` :D – klutt Apr 18 '19 at 08:09
  • @pmg Why would you define a macro for something that is only called once? – klutt May 22 '19 at 14:17
  • @Broman: you can, for example, generate code with different PRNGs by using `INIT_RNG` and `NEXT_RNG` and 'linking' them to the `` version, or Mersenne Twister, or some other method :) – pmg May 22 '19 at 15:10
  • `int main()` is not strictly allowed by the Standard, unless an implementation decides to allow it explicitly. Use `int main(void)` instead. – ad absurdum Jun 24 '20 at 20:31
  • @exnihilo I did consider that, but in practice, at least for a beginner, you'll have a hard time finding a compiler that does not support it. IMO, it's unnecessary clutter. Do you know any compiler that does not support it? – klutt Jun 24 '20 at 20:39
  • @exnihilo added a comment about it – klutt Jun 24 '20 at 20:57
  • @klutt -- A beginner should definitely learn the right way; it is really no clutter to use `(void)` instead of `()` in one location when defining `main`. It is a very bad idea to use empty parameter lists in other function declarations when `(void)` is the intent, if for no other reason than to allow some compiler warnings. I doubt that any implementation will ever _not_ accept it, but IMO it is bad style in C. [Empty parentheses in function declarators are an obsolescent feature](https://port70.net/~nsz/c/c11/n1570.html#6.11.6), IAC. – ad absurdum Jun 24 '20 at 21:49
  • I disagree about not using `return 0;` in the `main()` function. Every other function that returns something needs a `return ;` statement. It is more consistent to do it also in the `main()` function. I also think explicit is better than implicit. – 12431234123412341234123 Aug 31 '20 at 12:59
  • @12431234123412341234123 Yes, as I said. Some people would disagree. IMHO, the "correct" solution would be to declare main as `void main(void)` but since the standard does not require the compilers to support that, it is not an option. To me it's just clutter with zero value. – klutt Aug 31 '20 at 13:09
  • @klutt `void main(void)` would be confusing on platforms where main is expected to return an exit code, like Linux and Windows. It is correct and often supported on freestanding environments where main never returns. The reason for making C99 not requiring `return 0;` is "The standard finally having to bow to sloppy existing practices." http://c0x.coding-guidelines.com/5.1.2.2.3.pdf – 12431234123412341234123 Aug 31 '20 at 15:44
  • @12431234123412341234123 I know. I just happen to think that this is a moment where "it's good practice" simply is not a good argument. IMO, unless you actually DO return something else than 0 from main from time to time, I'd say it's better to just skip it. If you compile with `-Wall` (which you should anyway) you'll get a warning if you forget returning from all other non-void functions. – klutt Aug 31 '20 at 21:48