CS50 Lesson 4 — tutorial notes part 2

Maggie
10 min readAug 31, 2021

26-Aug-2021

Hexadecimal
one kind of presentation of values, like binary and decimal
but its presentation really looks like decimal sometimes, so will use 0x as suffix to show that it is hexadecimal
Example: RGB (red green blue)
Hexadecimal is very convenient to convert to binary because 4th unit of binary would be equal to 1 unit of hexadecimal number.

Data structure
typedef struct{int name; string name;} person ← as long as i rmb?
typedef
1. shorthand or rewritten name for data types
2. define a type in the normal way, then alias it to sth else

rewrite name:
typedef <old name> <new name>
typedef unsigned char byte; ← This one I don’t understand
typedef char* string; ← kind of messy here, if string is declared as address, it should be storing address instead of “the word inside the quote”

photo a: redefine structure name from car to car_t
could finish it in one line instead of adding 2 lines
originally need to def the struct first (if you didn’t rename the structure in photo a)
now only need to tell the name

Is it necessary to rename for the struct first? ←no, you could simply name it like photo a // name it with typedef without naming it after struct
or just struct without the typedef would still work the same? yes
if you use typedef, the declaration could be shorten like the last photo in the above.

  • **********************Pointers******************************
    pass data between function
    - according to CS50- Lesson 2 Tutorial, except array, data were passed by value (copy) instead of data (data stored)
    -if pointer was used instead, the VALUE would be passed instead
    -the changes did in function would actually impact the other function (the caller)

Memory ←usually talking about RAM
file lives on the disk drive — hard disk drive/solid-state drive ←will still be there rebooting
Disk drive is storage space
manipulation and use of data can only take place in RAM ← move data from disk to ram ← will lose without electricity/ reboot
Usually array of 8-hit wide bytes

different type of data occupy different size in bytes (more details CS50 lesson 1)

Memory = big array of byte-sized cells
array also called by random access — access individual elements of array by indicating which index location we want (like the mailbox number)
Each location would get its own address

Example:

this is not the actually truth, if you are curious, could take a look into endianness

remember for string: you need to get one more byte for the \0 ←nul

They will line up things starting from multiply of FOUR (for some reasons)

show the address in general yb hexadecimal

POINTERS ARE ONLY ADDRESS

green box for putting in integers
when you declare : int k;
now we have a green box called k to store integer
then if you say k=5;
now we put 5 into the green k box

now a new box in greenish colour
when you declare: int* pk;
you name the greenish box pk
then if you say pk = &k;
now you put the address of k into the greenish colour box

pk is giving the address/path for you to go to box k in memory

What is pointer?
Data item
- value is memory address
- “type” describes the data locate at that memory address
(dont quite understand, it also can state the type that the box is storing? so that is why it is in greenish colour and you need to indicate the data type when declaration?)
Help sharing the data structures/variables (instead of copy // not pass by value) among functions

simplest pointer in C
-points to nothing(NULL) ( could be very useful later on)
(NULL =/= NUL where null means nothing, and NUL is one of the code in ASCII (char))
-pointer should ALWAYS be pointing to NULL if the value is not set yet
you can check the pointer is NULL or not using equality(==) ←HOW????
(by using pointer == NULL)

Instead of creating a pointer from nothing, you can extract the address of variable that already exist through “&” (address extraction operator)

我懶得打, but take note on the last point: if you only use the array name, it would point to the address of first one — just like what it will be pointing with string

The reason why the array is pass by data: is that it is indeed a type of pointers, so the callee could change the value of caller

Dereferencing
modify or inspect the location to which the pointer points
if pointer-to-char is pc, then *pc is the data stored inside memory address pc.

“ * “ ←dereference operator
when put together with pointer, it means go to the reference(pointer) and accesses the data at that specific memory location, allow you to manipulate the data
dereference is like the action of walking towards(getting access to the value) the address pointer points to, but no just knowing the address

what if you dereference the pointer points to NULL
SEGMENTATION FAULT
it pops out error! why it is good for pointer to point at null?
To tell you there is an error. if you didn’t assign value to the variable after declaration, there is a risk that the variable were assigned with unknown number from the garage value or breaking other program/functions
if you don’t assign anything meaningful to the pointer, just point it towards NULL
crash is better than screw up other program / function

However, star is part of the type and variable name. You will get 1 pointer and 2 int in this case
But it would be better to declare them individually

How large of the bytes size of string?
String is only the array of char*, would be 4/8 bytes (every address would be 64bits long; if you are using 32bits system, would be 4 bytes long)

I would say: the value in green box(right) would change into 35 instead of 5

the star would be dereferencing operator → dereference the address

I would say the address of k was changed into the address of m, which means the value of green box k would be equal to 4 instead of 35

Nope, pk now get the address of m instead of k, so none of the data changes.
But if you change the data through pointer pk, then the value in box m would be changed.

Dynamic Memory Allocation
One of the way to work with pointers — pointing a pointer variable statically at another variable that already exists in our system
eg: int x = 5;
int* px = &x;
- need to know exactly how much memory our system will need at the moment during compile — ????? (like int* ? ←telling the system it would take 4 bytes) ← nope, means we know the value in the int box
-??? what if we don’t know how much memory needed when we compile the code? How are new memory being accessed while our program is running? (not declaring the data type? but it should be with data type stored inside right?)← it means something like letting the users to set the int in this case

How — -> get new memory address while the program is running???

Block of dynamically-allocated memory at runtime
they come from pool of memory called heap (dynamically used memory (grows down))
before this, all memory we worked with has been coming from stack(statically declared memory) (grows up)

how to access
function malloc() from <stdlib.h>
int* pi = malloc(4) ← number of bytes you would like to have
malloc will return pointer to that memory
→ if malloc cannot give you memory → NULL will be returned
so it is very important to check NULL after declaring malloc!!!!!!!
(run out of memory/catastrophic failure)

// statically obtain an integer ← save in stack
int x ;

//dynamically obtain an integer ← save in heap
int *px = malloc(4);
int *px = malloc(sizeof(int)); (sizeof operator ←give back the bytes that the type take up in system)
1. malloc will find the alternate 4 bytes from the heap
2. malloc will return a pointer called px pointing towards that memory
3. then you could dereference the pointer

let’s try
//get an int from user
int x = get_int();

//array of floats on the stack
float stack_array[x]; ← get from the

//array of floats on the heap
float* heap_array = malloc(x * sizeof(float));

Problem:
dynamically-allocated memory is not automatically returned to the system after the functions it belongs to finished execution
there will be memory leak if the used memory was not returned back to system → compromise the system’s performance
finish working with dynamically-allocated memory → must free() them
HOW ABOUT STATIC MEMORY? →
the allocated memory used for this function would be destroyed and then released back to the system → very convenient

How to fix it:

char* word = malloc(50 * sizeof(char));

// do sth with word

//now we are done with word
free(word);

  • ***************3 rules with malloc********************
    1.every block of memory that you malloc() must subsequently be free()
    2. ONLY memory that you malloc() should be free() (no need for static ← computer will do it for you)
    3. Don’t not free() same block more than once.
int* b and int* a would still be there

Call Stack
take recursion as example
how the function are called and operate in C
-when you called a function
— system will sets aside space in memory for that function to do the work
— that chunks of memory would be stack frames or function frames

more than 1 functions’ stack frame may exist in memory at a given time.
-if main() calls move() and move() calls direction(), then all of them have open frames
But active frame is only 1
The frames are arranged in stack → most recently called frame is always on top
When new function is called, the new frame was pushed on to the top
When the function finish its work, the frame popped off of the stack.
The frame below it would immediately becomes the new, active function, and picks up immediately where it left off.

How the functions were called and disappears (fact(1) returns 1)
now fact(2) returns(2*1)
now fact(3) returns(3*(2*1))
now fact(4) returns(4* (3*(2*1)))
fact(5) returns(5* (4*(3*(2*1))))
Then it receive 120 and print it out
find if there are any other things run in main

File pointers
no storage of information after the execution of program
→ but you can make a file
File pointer vs pointer → not exactly the same but not mentioned here
-persistent data ← data that does not disappear when program stops running// give you the ability to read data from and write data to files
-abstraction of files that C provides is implemented in a data structure — FILE
-pointer: FILE* would be used when handling with files

Stdio.h
-include functions to manipulate file (file input/output I/O)
ALL of them accept FILE* as one of their parameters (except fopen())
e.g fopen() ← for getting a file pointer FILE*
fclose()
fgetc()
fputc()
fread()
fwrite()

fopen()
opens a file and returns a file pointer ( one pointer can only work for one operation)
**check the return value to make sure it is not store in NULL
FILE* ptr = fopen(<filename>,<operation>);
ptr: generic name for file pointer(←i think no need to stay the same every time, but it is not the file name)
operation:
eg: FILE* ptr1 = fopen(“file1.txt”, “r”); ←r is read, w: write ← overwrite, a: append ← writing start from the end of the existing information

fclose()
closes the file pointed to by the given file pointer
fclose(<file pointer>);
eg fclose(ptr1); ←the pointer name

fgetc()
read and return the next character (or the first one if you first call the file) from the file pointed to
file get character
The operation of the file pointer passed in as a parameter must be “r”
char ch = fgetc(<file pointer>);
- you could get all characters from a file and print them to the screen → through loop

cat in Linux command do the same thing

In CMD, type cat and the file name, it will print out the whole contents in terminal
EOF = the end of file character

ONE operation with ONE file pointer
if you want to read and write← you need 2 file pointers

fputc()
~with fgetc()
writes/appends the specified character to the pointed-to file
MUST be “w” // “a” pointer
fputc(<character>, <file pointer>);
fputc(‘A’ , ptr2);
-can read characters from file/write characters to then
You could copy one file to another, instead of printing to the screen

similar to cd in Linux command

fread()
could read arbitrary amount of information instead of only one char at a time
reads <qty> units of size <size> from the file pointed to and stores them in memory in a buffer (usually an array) pointed to by <buffer>.
MUST be “r”
fread(<buffer>, <size>, <qty>, <file pointer>);
buffer → where to store the the information
eg
int arr[10];
fread(arr, sizeof(int), 10, ptr); ←size of int = byte as unit?
This means it would read 40 bytes from the file and store it in arr
“arr”, the name of array, is only the pointer to first element of information
OR in dynamic way
double* arr2 = malloc(sizeof(double) *80);
fread(arr2, sizeof(double), 80, ptr);
OR only getting one char
char* c;
fread(c, sizeof(char), 1, ptr); nooooooooooooo you need to point to the ADDRESS
char* c;
fread(&c, sizeof(char), 1, ptr); ← pointed to the place

fwrite()
write <qty> units of size <size> from the file pointed to by reading them from a buffer (usually an array) pointed to by <buffer>.
fread(<buffer>, <size>, <qty>, <file pointer>);
Pointer of the file should SHOULD be “a” // “w” instead of r
int arr[10];
fwrite(arr, sizeof(int), 10, ptr);
Putting information from arr(buffer) to ptr(file)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response