If you list the contents of this directory, you should see the below.

Okay, let’s dive into the first of those subdirectories. Execute the command below in a terminal window in your appliance.

Bet you saw the same "random" sequence of ten numbers again? Yup, that’s what happens if you don’t vary a pseudorandom number generator’s initial seed.

Run the program a third time using that same value for n; you should see a different list of 10 numbers. Now try running the program with a value for s too (e.g., 0), as in the below.

Go ahead and run this program again, this time with a value of, say, 10 for n , as in the below; you should see a list of 10 pseudorandom numbers.

As this output suggests, this program expects one or two command-line arguments. The first, n , is required; it indicates how many pseudorandom numbers you’d like to generate. The second, s , is optional, as the brackets are meant to imply; if supplied, it represents the value that the pseudorandom-number generator should use as its "seed." A seed is simply an input to a pseudorandom-number generator that influences its outputs. For instance, if you seed rand by first calling srand (another function whose purpose is to "seed" rand ) with an argument of, say, 1 , and then call rand itself three times, rand might return 17767 , then 9158 , then 39017 . (Cf. https://www.cs50.net/resources/cppreference.com/stdother/srand.html .) But if you instead seed rand by first calling srand with an argument of, say, 2 , and then call rand itself three times, rand might instead return 38906 , then 31103 , then 52464 . But if you re-seed rand by calling srand again with an argument of 1 , the next three times you call rand , you’ll again get 17767 , then 9158 , then 39017 ! See, not so random.

You should be informed of the program’s proper usage, per the below.

Implemented in generate.c is a program that uses a "pseudorandom-number generator" (via a function called rand ) to generate a whole bunch of random (well, pseudorandom, since computers can’t actually generate truly random) numbers, one per line. (Cf. https://www.cs50.net/resources/cppreference.com/stdother/rand.html ) Go ahead and compile this program by executing the command below.

You should be informed that generate is already up to date. Incidentally, know that the leading whitespace on that second line is not a sequence of spaces but, rather, a tab. Unfortunately, make requires that commands be preceded by tabs, so be careful not to change them to spaces with gedit (which automatically converts tabs to four spaces), else you may encounter strange errors! The -Werror flag, recall, tells clang to treat warnings (bad) as though they’re errors (worse) so that you’re forced (in a good, instructive way!) to fix them.

The first line tells make that the "target" called generate should be built by invoking the second line’s command. Moreover, that first line tells make that generate is dependent on generate.c , the implication of which is that make will only re-build generate on subsequent runs if that file was modified since make last built generate . Neat time-saving trick, eh? In fact, go ahead and execute the command below again, assuming you haven’t modified generate.c .

How did make know how to compile generate in this case? It actually used a configuration file that we wrote. Using gedit , go ahead and look at the file called Makefile that’s in the same directory as generate.c . This Makefile is essentially a list of rules that we wrote for you that tells make how to build generate from generate.c for you. The relevant lines appear below.

Now, recall that make automates compilation of your code so that you don’t have to execute clang manually along with a whole bunch of switches. Notice, in fact, how make just executed a pretty long command for you, per the tool’s output. However, as your programs grow in size, make won’t be able to infer from context anymore how to compile your code; you’ll need to start telling make how to compile your program, particularly when they involve multiple source (i.e., .c ) files. And so we’ll start relying on "Makefiles," configuration files that tell make exactly what to do.

Once done commenting generate.c , re-compile the program to be sure you didn’t break anything by re-executing the command below.

Now take a look at generate.c itself with gedit . (Remember how?) Comments atop that file explain the program’s overall functionality. But it looks like we forgot to comment the code itself. Read over the code carefully until you understand each line and then comment our code for us, replacing each TODO with a phrase that describes the purpose or functionality of the corresponding line(s) of code. (Know that an unsigned int is just an int that cannot be negative.) And for more details on rand and srand , recall that you can execute:

Be careful not to add, say, *.c to that last line in Makefile ! (Why?) Any line, incidentally, that begins with # is just a comment.

This target allows you to delete all files ending in .o or called core (more on that soon!), find , or generate simply by executing the command below.

If only you could whittle this whole problem set down to a single command! Finally, notice these last lines in Makefile :

Even better, the below is equivalent (because make builds a Makefile 's first target by default).

This target implies that you can build both generate and find simply by executing the below.

You can then redirect that file’s contents as input to find with the command below.

Note that, when piping output from generate into find in this manner, you won’t actually see generate 's numbers, but you will see find 's prompts.

In turns out you can automate this process of providing hay, though, by "piping" the output of generate into find as input. For instance, the command below passes 1,000 pseudorandom numbers to find , which then searches those values for 42 .

You’ll be prompted to provide some hay (i.e., some integers), one "straw" at a time. As soon as you tire of providing integers, hit ctrl-d to send the program an EOF (end-of-file) character. That character will compel GetInt from the CS50 Library to return INT_MAX , a constant that, per find.c , will compel find to stop prompting for hay. The program will then look for that needle in the hay you provided, ultimately reporting whether the former was found in the latter. In short, this program searches an array for some value. At least, it should, but it won’t find anything yet! That’s where you come in. More on your role in a bit.

Per the dependencies implied above (after the colon), any changes to find.c , helpers.c , or helpers.h will compel make to rebuild find the next time it’s invoked for this target.

Notice further that you just compiled a program comprising not one but two .c files: helpers.c and find.c . How did make know what to do? Well, again, open up Makefile to see the man behind the curtain. The relevant lines appear below.

Notice, per that command’s output, that make actually executed the below for you.

Now take a look at find.c with gedit . Notice that this program expects a single command-line argument: a "needle" to search for in a "haystack" of values. Once done looking over the code, go ahead and compile the program by executing the command below.

And now the fun begins! Notice that find.c calls search , a function declared in helpers.h . Unfortunately, we forgot to implement that function fully in helpers.c ! (To be sure, we could have put the contents of helpers.h and helpers.c in find.c itself. But it’s sometimes better to organize programs into multiple files, especially when some functions are essentially utility functions that might later prove useful to other programs as well, much like those in the CS50 Library.) Take a peek at helpers.c with gedit , and you’ll see that search always returns false , whether or not value is in values . Re-write search in such a way that it uses linear search, returning true if value is in values and false if value is not in values . Take care to return false right away if n isn’t even positive.

When ready to check the correctness of your program, try running the command below.

./generate 1000 50 | ./find 2008

Because one of the numbers outputted by generate , when seeded with 50 , is 2008 , your code should find that "needle"! By contrast, try running the command below as well.

./generate 1000 50 | ./find 2013

Because 2013 is not among the numbers outputted by generate , when seeded with 50 , your code shouldn’t find that needle. Best to try some other tests as well, as by running generate with some seed, taking a look at its output, then piping that same output to find , looking for a "needle" you know to be among the "hay".

Incidentally, note that main in find.c is written in such a way that find returns 0 if the needle is found, else it returns 1 . You can check the so-called "exit code" with which main returns by executing

echo $?

after running some other command. For instance, assuming your implementation of search is correct, if you run

./generate 1000 50 | ./find 2008 echo $?

you should see 0 , since 2008 is, again, among the 1,000 numbers outputted by generate when seeded with 50 , and so search (written by you) should return true , in which case main (written by us) should return (i.e., exit with) 0 . By contrast, assuming your implementation of search is correct, if you run

./generate 1000 50 | ./find 2013 echo $?

you should see 1 , since 2013 is, again, not among the 1,000 numbers outputted by generate when seeded with 50 , and so search (written by you) should return false , in which case main (written by us) should return (i.e., exit with) 1 . Make sense?

When ready to check the correctness of your program officially with check50 , you may execute the below. Be sure to run the command inside of ~/Dropbox/pset3/find .

check50 2014/x/pset3/find helpers.c

Incidentally, be sure not to get into the habit of testing your code with check50 before testing it yourself. (And definitely don’t get into an even worse habit of only testing your code with check50 !) Suffice it to say check50 doesn’t exist in the real world, so running your code with your own sample inputs, comparing actual output against expected output, is the best habit to get into sooner rather than later. Truly, don’t do yourself a long-term disservice!

Anyhow, if you’d like to play with the staff’s own implementation of find in the appliance, you may execute the below.