CS50x – Week 1

Written by on August 18, 2017 in Coding, CS50

‘C’

Last week we learnt the basics about the binary system and algorithms and how they apply to programming. We then looked at programming techniques and concepts and how to implement them using Scratch.

This week introduced more traditional programming. The introduction of the ‘C’ language.

#include <stdio.h>
int main(void)
{
    printf("Hello world\n");
}

The above code is quite possibly the most common piece of code that every person learning code will encounter, regardless of the language.

‘C’ is a language that was created in the 1970’s by Dennis Ritchie. It is a low-level language, which means that it is similar to the computer’s instruction set architecture. There are several layers of abstraction to computer languages. At the bottom we have machine code which is the basic 0’s and 1’s that a computer can read. It is almost impossible to program in machine code because it would require enormous attention to detail and memorisation of the number sets for instructions and the code would be very difficult to manage and modify. It can be made slightly easier by not strictly using binary but using hexadecimal values to make it easier to read. One level of abstraction above machine is Assembly language. In the early days of programming the programmers themselves would write their own assemblers which use keywords to represent an instruction in machine code. This made it easier to program although it is still hard compared to modern languages because each line in assembly is a machine instruction. One level above that are complied low-level languages, such as C. C requires a compiler to convert your code into machine code which can then be run by the computer.

Looking back at scratch last week we were introduced to some basic programming features. These included conditional statements, loops and boolean expressions just to name a few. These also exist in C and are the fundamental building blocks to writing code. In scratch if we wanted to have some text displayed we used the ‘say‘ block. In C we can use

printf("Hello World\n");

as seen in the above example. This is actually a function but we’ll get to that another time.

Loops

The forever block in scratch is an example of a loop. In C we can use a while loop like so:

while (true)
{
    printf("Hello world\n");
}

This code will continue forever until we stop the program because it uses while(true) and since true is always true it will always execute the code inside itself indefinitely.
We also have loops that will continue until a condition is met. This is the do while loop:

do
{
    printf("Hello world\n");
    count++;
}
while (count < 3);

This code will run once and check to see if the condition is met, if it is not then it will execute again until the condition is met. This is useful for verifying user input. In the above example ‘Hello world‘ will be printed 3 times.

We also have loops that will run a finite number of times. These are called ‘for loops‘:

for (int i=0;i<10;i++)
{
    printf("hello world\n");
}

for loops are extremely useful to repeat tasks a number of times. In the example above ‘hello world‘ will be printed 10 times.

Boolean expressions

The next common feature is Boolean expression. Boolean values are either True or False, or 1 and 0. We can also compare variables which will return either true or false. We use operators like ‘<‘ to check if something is less than something else. ‘>‘ for checking if something is greater than something. ‘!=‘ for checking to see if something is not equal to something and ‘==‘ to check to see if something is equal to something else.

Conditional statements

We can use conditional statements to check for boolean expressions.

if (x<y)
{
    printf("x is less than y\n");
}
else if(x>y)
{
    printf("x is greater than y\n");
}
else
{
    printf("x is equal to y\n");
}

Variables

Variables are a way to store information. The information could be anything, a number, a name or a boolean value. In C they are declared with their data type so the compiler knows how to interpret what the variable is. In the examples above x and y are variables and the value within them could be a number that was defined elsewhere in code.

CS50 IDE

In order to write C code you can actually use any text editor and save the file as .c but it is always recommended to use an IDE (Integrated Development Environment). IDE’s have a large number of features that make coding easier and often have built in compilers, debugging features and terminals that will improve your productivity. The guys at CS50 have decided to use a cloud-based IDE which is appropriately named CS50 IDE. It is built upon a platform called Cloud9 which offers cloud-based web-based development environments.

This is what the CS50 IDE looks like. It has a file explorer so you can browse your files within the IDE. The view for writing code can be split in a number of ways so you can view several source files at once. The terminal window at the bottom is where you can issue linux commands complete certain tasks. It is also where you can run these programs.

CS50 Library

The CS50 Library which is provided to us contains many useful features to make coding easier for us. It contains custom functions that allow use to retrieve user input more easily among other useful features.

Data types

In C there are several data types. The data types we’ll be most commonly using are:
bool for boolean values (true or false)
float which are real numbers
double for large real numbers with more bits than a float
int which is a integer or whole number
long long for large whole number with more bits than int
char for a single character
string which is used for text

These data types use a fixed number of bytes. We can use the sizeof() function to determine how many bytes are used for each data type.
bool is 1
float is 4
double is 8
int is 4
long long is 8
char is 1
string is 8

Within the CS50 IDE or more specifically the Cloud9 OS a bool requires 1 byte/8 bits. Strings are a special case in that they are given 8 bytes but this is not always the case as string actually work slightly differently to the other data types.
In any computer the number of bytes in memory is limited. If we had a binary number with 8 bits that was 11111110 and we added 1 to it we would now have 11111111. If we wanted to add another 1 to our number it would actually carry over and become 00000000 because we don’t have an extra bit to store that larger value.
We know that int is given 4 bytes of memory, which is 32 bits. 2^32 is ~4 billion values. However int data type includes negative numbers so the highest possible number with int is ~2 billion. If we wrote a program that doubles the value of an int over and over we would reach a point where the number would wrap around and become negative then it would become 0, where we have run out of bits to store such a large number. This is called an overflow. This bug has caused real world problems where an aeroplane shut off its engines because the software on-board used int to store the number of hours the engine was powered on and after 248 days of continuous use an integer overflow occurred.
Another bug which is common is called floating-point imprecision, which as the name suggests arises from using float data type. Floats also have a finite number of bits they can use (4 bytes) and if the number get large enough or small enough it can represent numbers inaccurately. If we divided 1 by 10 we get 0.1, if we wanted to display up to 10 decimal places it would be 0.1000000000. However if we wanted to go further and display more decimal places we would potentially end up with 0.100000000000000000555111512312578… As you can see even though we did ‘1/10’ the computer can only give a close approximation to 0.1.

Logical Operators

In C we can use logic to easily manipulate data. The two common ones are && and ||.

&& means AND and || means OR.
We can use them to check multiple conditions in a statement and execute code if both conditions are true or either conditions are true.

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    char c = get_char();
    if (c == 'Y' || c == 'y')
    {
        printf("yes\n");
    }
    else if (c == 'N' || c == 'n')
    {
        printf("no\n");
    }
    else
    {
        printf("error\n");
    }
}

We can implement the same program is a different way.

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    char c = get_char();
    switch (c)
    {
        case 'Y':
        case 'y':
            printf("yes\n");
            break;
        case 'N':
        case 'n':
            printf("no\n");
            break;
        default:
            printf("error\n");
            break;
    }
}

We can use a switch statement. Switches use cases which will execute code if the case matches the switch. It will continue through the statement until it reaches break; which will then stop the switch statement.

Functions.

We can create our own custom functions to do various things. One of the main reasons of writing your own functions is to stop repeating code. For example if you have to repeat a block of code two or three times it is more efficient to factor out that code into its own function and then call that function when needed. This allows us to keep our source files shorter and we can manage our code easier. If we needed to change that function in some way we can simply change it within that function itself but if we didn’t use the function we would have to implement the changes at every instance of that piece of code.

Problem Set 1

Problem Set 1 requires us to complete 4 tasks.

  1. Implement Hello
  2. Implement Water
  3. Implement either of:
    • Mario, less comfortable
    • Mario, more comfortable
  4. Implement either of:
    • Greedy, less comfortable
    • Credit, more comfortable

Hello

Hello is pretty straight forward. It asks use to simply print hello world to the screen.

see source
#include <cs50.h>
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
}
view raw hello.c hosted with ❤ by GitHub

 

Water

Water asks us to implement a program  that reports a user water usage. We ask the user to input the number of minutes they shower and print how many bottles of water that equates to. 1 minute in the shower equates to 12 bottles of water.

see source
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int mins;
do
{
printf("Minutes: ");
mins = get_int();
} while(mins <= 0);
mins *= 12;
printf("Bottles: %i\n", mins);
}
view raw water.c hosted with ❤ by GitHub

 

Mario

Mario asks us to create the iconic pyramid that appear at the end on the first level of Mario. We ask a user for an input to give us the height of the pyramid we have to draw. The less comfortable version asks us to draw only one side of the pyramid and the more comfortable asks us to draw both sides.

see source
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int height;
do
{
printf("Height: ");
height = get_int();
} while (height < 0 || height > 23);
for (int i = 0; i < height; i++)
{
//print spaces for left pyramid
for (int c = 2; c <= height - i; c++)
{
printf(" ");
}
//print hashes for left pyramid
for (int c = 0; c <=i; c++)
{
printf("#");
}
//print gap
printf(" ");
//print right hashes
for (int c = 0; c <=i; c++)
{
printf("#");
}
//print new line
printf("\n");
}
}
view raw mario.c hosted with ❤ by GitHub

 

For the final task we are given an option to implement 1 of 2 programs. One option is Greedy which we can do if we are less comfortable with coding and the other option is Credit which we can implement if we are more comfortable with programming. I decided to do both just for the sake of it.

 

Greedy

Greedy asks us to calculate how many coins we must return given a certain amount of change. Being a US course thus using US currency we need to calculate how many cents, nickels, dimes and quarters have to be returned.

see source
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
//declare variables
float change;
int coins, cents;
//Get user input, must be non-negative.
do
{
printf("O hai! How much change is owed?\n");
change = get_float();
}while (change <0);
//convert into int and minimise floating point imprecision
cents = (int)round(change*100);
coins = 0;
//Get how many 25c coins are needed, get the remainder via modulo
coins += cents / 25;
cents %=25;
//Get how many 10c coins are needed, get the remainder via modulo
coins+= cents / 10;
cents %= 10;
//Get how many 5c coins are needed, get the remainder via modulo
coins += cents / 5;
cents %= 5;
//remainder coins are pennies
coins += cents;
//Print result
printf("%i\n", coins);
return 0;
}
view raw greedy.c hosted with ❤ by GitHub

 

Credit

In Credit we have ask the user for their credit card number and we must determine whether it is valid and if so what type of credit card it is. We check to see if it is either American Express, MasterCard or Visa.

see source
#include <cs50.h>
#include <stdio.h>
int main(void)
{
long long cc_num;
//Get User input
do
{
printf("Please enter your credit card number: ");
cc_num = get_long_long();
} while (cc_num < 0);
//Determine the length of the credit card number
int length = 0;
long long chk_length = cc_num;
while (chk_length >0)
{
chk_length /= 10;
length++;
}
//Separate credit card number into an array
int number[length];
for (int i =0; i < length; i++)
{
number[i] = cc_num % 10;
cc_num /= 10;
}
//Calculate sum of every other digit from the last.
int added_sum = 0;
for (int i =0; i < length; i+=2)
{
added_sum += number[i];
}
//Calculate the sum of every other digit from 2nd to last times 2
int x2_sum = 0;
for (int i = 1; i<length; i+=2)
{
if (number[i]*2 > 9)
{
x2_sum += (number[i] * 2) / 10;
x2_sum += (number[i] * 2) % 10;
}
else
{
x2_sum += number[i] * 2;
}
}
//Check to see if card is valid and what type of card it is
int checksum = added_sum + x2_sum;
if (checksum % 10 == 0 && (length == 13 || length ==15 || length == 16))
{
if (number[length-1] == 3 && (number[length-2] == 4 || number[length-2] == 7))
{
printf("AMEX\n");
}
else if (number[length-1] == 5 && (number[length-2] == 1 || number[length-2] == 2 || number[length-2] == 3 || number[length-2] == 4 || number[length-2] == 5))
{
printf("MASTERCARD\n");
}
else if (number[length-1 == 4])
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
}
}
else
{
printf("INVALID\n");
}
}
view raw credit.c hosted with ❤ by GitHub

 

That was week 1 and This is CS50!

Leave a Reply

Your email address will not be published. Required fields are marked *

Comments«