Professional Documents
Culture Documents
CS50 2024 Week 2 - Arrays
CS50 2024 Week 2 - Arrays
Class CS50x
Type Lecture
Reviewed
1. Compiling
“make” command is not exactly a compiler itself but what it really does is run a program
that automatically runs a compiler for you.
• If you were to type make hello , it runs a command that executes clang to create an output
file that you can run as a user.
clang hello.c
./a.out
—> And the output for hello.c will be “hello, world”. But this is not user-friendly.
💡 We can configure it using command line arguments, which are what we have been
using thus far.
Week 2 - Arrays 1
Command line arguments: additional words or shorthand notation that we typed at the
command prompt to modify the behaviour of a program.
However, for code with get input from the user, there will be an error that indicates that
clang does not know where to find cs50.h . To fix the issue, we need to include -lcs50 - to
link “cs50” library.
While the above is offered as an illustration, such that you can understand more deeply the
process and concept of compiling code, using make in CS50 is perfectly fine and the
expectation!
💡 Compiling is actually one of the four major steps of turning source code into machine
code, which are:
1. First, preprocessing is where the header files in your code, designated by a # (such
as #include <cs50.h> ) are effectively copied and pasted into your file. During this step, the
code from cs50.h is copied into your program. Similarly, just as your code
contains #include <stdio.h> , code contained within stdio.h somewhere on your computer
is copied to your program. This step can be visualised as follows:
int main(void)
{
string name = get_string("What's your name? ");
printf("hello, %s\n", name);
}
Week 2 - Arrays 2
2. Compiling: Second, converts C code into the underlying assembly code. This step can be
visualised as follows:
3. Assembling: Third, involves converting assembly code into 0’s and 1’s. This step can be
visualized as follows:
Week 2 - Arrays 3
4. Linking: Finally, during the linking step, code from your included libraries are converted
also into machine code and combined with your code. The final executable file is then
outputted.
2. Debugging
Everyone will make mistakes while coding.
Week 2 - Arrays 4
Further, consider the following code that has a bug purposely inserted within it:
#include <stdio.h>
int main(void)
{
for (int i = 0; i <= 3; i++)
{
printf("#\n");
}
}
Running the above code, four bricks appear instead of the intended three.
printf can be utilised to debug our code. We could modify our code as follows:
#include <stdio.h>
int main(void)
{
Week 2 - Arrays 5
for (int i = 0; i <= 3; i++)
{
printf("i is %i\n", i);
printf("#\n");
}
}
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 3; i++)
{
printf("#\n");
}
}
Allow users to dive deep into what the code actually did in the process of compiling and
running.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int h = get_int("Height: ");
print_column(h);
Week 2 - Arrays 6
}
However, notice that compiling and running this code still results in a bug.
3. Arrays
Each of the types of data has only a finite amount of space allocated to it.
Week 2 - Arrays 7
Inside of our computer, we have a finite amount of memory available.
Memory is basically a canvas that we can manipulate the bits on to store numbers anywhere.
Week 2 - Arrays 8
Physically, on the memory of your computer, you can imagine how specific types of data are
stored on your computer. You might imagine that a char , which only requires 1 byte of
memory, may look as follows:
Week 2 - Arrays 9
We can create a program called scores.c that explores these concepts:
#include <stdio.h>
int main(void)
{
// Scores
int scores1 = 72;
int scores2 = 73;
int scores3 = 33;
// Print average
printf("Average: %.2f\n", (scores1 + scores2 + scores3)
}
Week 2 - Arrays 10
scores.c ’s code might not be the best design because the scores variables are almost
identical, and we would get typographical errors while coding.
The introduction of arrays - a way of storing data back-to-back in memory such that this
data is easily accessible, proposed a solution to the previous problem:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Get scores
int scores[3];
scores[0] = get_int("Score: ");
scores[1] = get_int("Score: ");
scores[2] = get_int("Score: ");
// Print average
printf("Average: %.2f\n", (scores[0] + scores[1] + scores[2]
}
Week 2 - Arrays 11
☝ Notice that score[0] examines the value at this location of memory by indexing
into the array called scores at location 0 to see what value is stored there.
int scores[3] is a way of telling the compiler to provide you three back-to-back places in
memory of size int to store three scores .
This code is correct but, is still bad design. There is still an opportunity for improving our
code.
💡 Global variable which is placed outside of the curly braces will be in scope to every
function within the file.
const int N = 3;
int scores[N];
for (int i = 0; i < 3; i++)
{
scores[i];
}
printf("Average: %.2f\n", (scores[0] + scores[1] + scores[2]) /
However, there’s this code that completely do away with manually typing the total sum, that
is:
#include <cs50.h>
#include <stdio.h>
// Constant
const int N = 3;
// Prototype
float average(int length, int array[]);
int main(void)
Week 2 - Arrays 12
{
// Get scores
int scores[N];
for (int i = 0; i < N; i++)
{
scores[i] = get_int("Score: ");
}
// Print average
printf("Average: %f\n", average(N, scores));
}
🗣 Notice that a new function called average is declared. Further, notice that a const or
constant value of N is declared. Most importantly, notice how the average function
takes int array[] , which means that the compiler passes an array to this function.
Not only can arrays be containers: They can be passed between functions.
4. Strings
String is basically a sequence of characters( char ), for example:
Week 2 - Arrays 13
string s = "Hi!";
But in fact, a string is actually an array of characters, which in the above example, “HI!” is
an array of s[0] = “H”, s[1] = I and s[2] = !.
However, for string is a sequence of characters - which each has only 1 byte, how can the
computer know where a string ends?
—> In fact, there’s a special value of only 0 bits called a NUL character by the end of a string
that tells the computer where to end it:
Imagining this in decimal, your array would look like the following:
Week 2 - Arrays 14
Implementing this in our own code, type code hi.c in the terminal window and write code
as follows:
#include <stdio.h>
int main(void)
{
char c1 = 'H';
char c2 = 'I';
char c3 = '!';
#include <stdio.h>
Week 2 - Arrays 15
int main(void)
{
char c1 = 'H';
char c2 = 'I';
char c3 = '!';
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string s = "HI!";
printf("%c%c%c\n", s[0], s[1], s[2]);
}
#include <stdio.h>
int main(void)
{
string s = "HI!";
printf("%i %i %i %i\n", s[0], s[1], s[2], s[3]);
}
Notice that this prints the string’s ASCII codes, including NUL.
Let’s imagine we want to say both HI! and BYE! . Modify your code as follows:
Week 2 - Arrays 16
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string s = "HI!";
string t = "BYE!";
printf("%s\n", s);
printf("%s\n", t);
}
Notice that two strings are declared and used in this example.
5. String Length
To calculate the length of a string(without string.h), we could do this:
Week 2 - Arrays 17
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Prompt for user's name
string name = get_string("Name: ");
Fortunately, there is a human that did the coding for length calculation already in the string.h
file since this is such a common problem within programming. You can find the length of a
string by modifying your code as follows:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Prompt for user's name
string name = get_string("Name: ");
int length = strlen(name);
printf("%i\n", length);
}
If we forget what printf actually does(which is quite stupid), we could hardcode every
character within a string like so:
Week 2 - Arrays 18
string s = get_string("Input: ");
printf("Output: ");
for (int i = 0; i < strlen(s); i++)
{
printf("%c", s[i]);
}
printf("\n");
Nevertheless, this is still not optimal enough because we require the computer to check the
strlen(s) again, and again, which is a constant value. So we can code into something like this
instead:
💡 Because we call i as an int prior to n, which will also be called as an int so we just
need to declare just one “int” only.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string words[2];
words[0] = "HI!";
Week 2 - Arrays 19
words[1] = "BYE!";
printf("%s\n", words[0]);
printf("%s\n", words[1]);
}
Notice that both strings are stored within a single array of type string .
6. uppercase.c
#include <stdio.h>
#include <cs50.h>
#include <string.h>
int main(void)
{
string name = get_string("Before: ");
printf("After: ");
for (int i = 0, n = strlen(name); i < n; i++)
{
if (name[i] >= 'a' && name [i] <= 'z')
{
printf("%c", name[i] - 32);
}
else
{
printf("%c", name[i]);
}
}
printf("\n");
}
Recalling our previous work from last week, you might remember this ASCII values chart:
Week 2 - Arrays 20
When a lowercase character has 32 subtracted from it, it results in an uppercase version of
that same character.
This code will turn your lowercased strings into uppercased ones, but there is still good
chances for optimization of minus 32 or strlen part. So, the ctype.h file will handle this job:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string name = get_string("Before: ");
printf("After: ");
for (int i = 0, n = strlen(name); i < n; i++)
{
printf("%c", toupper(name[i]));
}
Week 2 - Arrays 21
printf("\n");
}
As above, when included a new library called ctype.h, we can use the function toupper()
which can capitalize only lowercase characters within a string without resorting to
hardcoding that is fragile.
7. Command-line Arguments
Command-line argumentsare those arguments that are passed to your program at the
command line. For example, all those statements you typed after clang are considered
command line arguments. You can use these arguments in your own programs!
In your terminal window, type code greet.c and write code as follows:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string answer = get_string("What's your name? ");
printf("hello, %s\n", answer);
}
Still, would it not be nice to be able to take arguments before the program even runs?
Modify your code as follows:
#include <cs50.h>
#include <stdio.h>
Week 2 - Arrays 22
else
{
printf("hello, world\n");
}
}
Notice that this program knows both argc , the number of command line arguments,
and argv which is an array of the characters passed as arguments at the command line.
Therefore, using the syntax of this program, executing ./greet David would result in the
program saying hello, David .
8. Exit status
Every program that we have written thus far has exit status, like a special return value from
a program.
if the return value is 0 then it is good, but if it is any other integers, it is bad. For instance:
error 404 which means ‘file not found’
If we run the file with more than 1 or 0 command-line arguments, the program will return
the value of 116, as above.
Week 2 - Arrays 23
☝ We can check the value that the program secretly handed us by running “echo $?”
which checks what most recently-run program secretly exit with.
9. Cryptography
Cryptography is the ability to send information securely.
Encryption is the act of hiding plain text from prying eyes. decrypting, then, is the act of
taking an encrypted piece of text and returning it to a human-readable form.
• The key is a special argument passed to the cipher along with the plaintext. The cipher uses
the key to make decisions about how to implement its cipher algorithm.
Week 2 - Arrays 24
Summing Up
In this lesson, we learned more details about compiling and how data is stored within a computer.
Specifically, you learned…
Week 2 - Arrays 25