WordPress & Full-stack development

Section

  • type * is a pointer that stores the address of a type
  • *x takes a pointer x and gets the value stored at that address
  • &x takes x and gets its address

Why would you ever use pointers instead of the basic syntax we already know?

  • You can pass variables to functions by reference, not just by copy. The code you write is cleaner as a result.
  • You can use dynamic memory (e.g., with malloc) instead of fixed amounts of static memory. Your programs can now scale their usage of memory according to user behaviour.

Passing by Copy versus passing by Reference

Imagine that you have a function swap() that takes two integers and swaps the values. When you just pass the integers that you created in the main() function, you'll actually create copies of the variables and the original variables won't be affected when the swap() function finishes.

Instead, we take the address so we can alter the original values.

void swap(int *a, int *b){
  int temp = *a;
  *a = *b;
  *b = temp;
}

So in this example we take two pointers as arguments.

Why do we need to close files after opening them

When you use fopen, you always need to use fclose. If you would keep opening files and never closing them, you'd have a lot of open files that take up resources, but you always want to make sure that no two programs are opening the same file at the same time.

Buffers

  • fread reads data from a file into a buffer.
  • fwrite writes data from a buffer to a file.

A buffer is a chunk of memory that can temporarily store some contents from the file.

Why do we use a buffer if it only stores a part of a file? Why don't we just read the entire file into memory at once?

We often don't know exactly how big a file is. So it's a good idea to look at parts of it until we get to the end.

If you want to read from a file, you first need to answer four questions:

  • From where are you reading?
  • To where are you reading?
  • What size (in bytes) is each block of data you want to read? For a text file, this could be 1 byte because you want to read one character at a time
  • How many blocks do you want to read. How do you decide this? It depends on a few things, like how much memory you want to use. If you don't care about seeing all data at once, it's better to use small chunks to make sure that you don't use too much memory. It tends to be a bit faster to read bigger chunks (100 bytes for example).
fread(<to where: buffer>,<what size: bytes>,<how many blocks at a time>,<from where: filepointer>)

Files are composed of individual blocks of data. In a text file, each block would be a character. An image file is broken up in 3-byte chunks (because you need 3 bytes for every pixel: RGB)

When you use fread, the pointer will point to the rest of the file. For example, when you read 4 bytes at once, after going through the first 4 bytes, the pointer will now to the fifth byte. When you're done, you'll need to return the pointer to the first position (like rewinding a VHS tape). You know that you're at the end when you see the EOF (End of File) character.

Checking for file types

Files always start with a specific combination of bytes (signature) to tell you the kind of file. For example, a pdf starts with: 37, 80, 68, 70.

Example: program that checks if the file is a pdf

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

int main(int argc, string argv[]){
    // Check first four bytes in given file to check if it's a pdf

    // Step 1: The user will provide the filename in the command line
    string filename = argv[1];

    // Step 2: Create a pointer to the file specified by the user
    FILE *f = fopen(filename, "r");

    // Step 3: Read from the file
    // Create a buffer to store (part of) the file. A buffer will often be an array
    // We're going to use a special type of integer that is 8 bits (or 1 byte) long and is only positive.
    uint8_t buffer[4];
    // How many bytes do we want to read? 4 bytes (because we have to check the first 4 bytes)
    // Read TO the buffer, in 1 BYTE chunks, 4 BYTES at a time, FROM the file f
    fread(buffer,1,4,f);

    for (int i = 0; i < 4; i++){
        printf("%i\n",buffer[i]);
    }

    fclose(f);



}

Problem Sets

Pset 1: volume

In this pset, we need to write a program that will take a WAV file as input, modify the volume and output the second file with the modified volume.

Since each sample of a WAV file is 2 bytes large, we can use the int16_t datatype.

Harvard-CS50-Problem-Sets/week 4 (memory)/volume.c at main · thibaultseynaeve/Harvard-CS50-Problem-Sets
Contribute to thibaultseynaeve/Harvard-CS50-Problem-Sets development by creating an account on GitHub.

Pset 2: Filter (Less)

In the first version of the filter program, you need two write four functions that will manipulate an image:

  • Greyscale
  • Sepia
  • Reflect
  • Blur

Some are a bit more complicated then the others. The 'blur' filter is definitely the most challenging.

Harvard-CS50-Problem-Sets/week 4 (memory)/filter-less at main · thibaultseynaeve/Harvard-CS50-Problem-Sets
Contribute to thibaultseynaeve/Harvard-CS50-Problem-Sets development by creating an account on GitHub.

Pset 3: Recover

This one was honestly a bit easier than the filter pset. You get a memory card file and you need to find all the JPEG's on it and create a new JPEG file for every one of them.

Harvard-CS50-Problem-Sets/week 4 (memory)/recover.c at main · thibaultseynaeve/Harvard-CS50-Problem-Sets
Contribute to thibaultseynaeve/Harvard-CS50-Problem-Sets development by creating an account on GitHub.
You’ve successfully subscribed to Teebow Dev Blog
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Success! Your email is updated.
Your link has expired
Success! Check your email for magic link to sign-in.