188 lines
5.9 KiB
Org Mode
188 lines
5.9 KiB
Org Mode
#+LATEX_HEADER: \usepackage[margin=0.5in]{geometry}
|
|
|
|
* Assignment 1
|
|
|
|
ABC123: =zfp106=
|
|
|
|
Name: =Price Hiller=
|
|
|
|
Course: =CS2124=
|
|
|
|
Section: =0C3=
|
|
|
|
Semester: =Spring 2024=
|
|
|
|
** Source Code
|
|
|
|
The full source code for this project can be found at [[https://git.orion-technologies.io/Price/college/src/branch/Development/Spring-2023/CS-2124/Assignment-1]]
|
|
** Running the Programs
|
|
1. Install [[https://cmake.org/download/][cmake]] version 3.25 or greater.
|
|
2. Ensure you have recent version of ~make~ at the time of writing. This project successfully
|
|
compiles with ~GNU make~ version ~4.4.1~.
|
|
3. Go the directory with ~CMakeLists.txt~ and run ~cmake .~ to generate a Makefile.
|
|
4. Run ~make all~ to compile all the programs.
|
|
5. Go into the newly created ~bin~ directory where all the compiled programs will be output to.
|
|
6. Run the programs in sequence, from ~C1~ to ~C12~ to ensure the file operations work as
|
|
expected.
|
|
|
|
** Program Outputs and Question Solutions (C's)
|
|
|
|
*** C1 (Creation of a new file)
|
|
|
|
[[./assets/C1-output.png]]
|
|
|
|
*** C2 (Opening and closing an existing file)
|
|
|
|
[[./assets/C2-output.png]]
|
|
|
|
*** C3 (Writing to a file)
|
|
|
|
[[./assets/C3-output.png]]
|
|
|
|
*** C4 (Reading from file)
|
|
|
|
[[./assets/C4-output.png]]
|
|
|
|
*** C5 (Moving to a specific location in a file (end of file))
|
|
|
|
[[./assets/C5-output.png]]
|
|
|
|
*** C6 (Computes string's length and copies one string into another string)
|
|
|
|
[[./assets/C6-output.png]]
|
|
|
|
*** C7 (Concatenates(joins) two strings)
|
|
|
|
[[./assets/C7-output.png]]
|
|
|
|
*** C8 (Compares two strings)
|
|
|
|
[[./assets/C8-output.png]]
|
|
|
|
*** C9 (Converts String to lowercase)
|
|
|
|
[[./assets/C9-output.png]]
|
|
|
|
*** C10 (Converts string to uppercase)
|
|
|
|
[[./assets/C10-output.png]]
|
|
|
|
*** C11 (Dynamic Memory with Malloc)
|
|
|
|
[[./assets/C11-output.png]]
|
|
|
|
*** C12 (Dynamic Memory with Calloc)
|
|
|
|
[[./assets/C12-output.png]]
|
|
|
|
*** C13 (Describe the difference between ~malloc~ and ~calloc~)
|
|
~malloc~ and ~calloc~ both return a pointer to allocated memory for some purpose. The major
|
|
difference is that ~calloc~, by default, will initialize all elements in that allocated memory
|
|
to the value ~0~ whereas ~malloc~ does not modify anything in that block of memory before
|
|
returning a pointer.
|
|
|
|
You can achieve a poor man's ~calloc~ by using ~malloc~ with ~memset~ to initialize the
|
|
newly returned block of memory to ~0~ yourself. This will almost certainly be slower than most
|
|
~calloc~ usages as ~calloc~ "knows" the kernel will return something known as a virtual zero page and
|
|
thus will be receiving (on most systems) a chunk of memory that has all its values initialized
|
|
to ~0~ by default. Thus ~calloc~ can "know" when it needs to allocate those ~0~'s itself or if
|
|
it can skip the process and thereby be faster than ~malloc~ + ~memset~.
|
|
|
|
*** C14 (Explain pointers and pointers to pointers using code)
|
|
|
|
|
|
**** *_Write code for pointer and use that code to explain pointers in your own words_*
|
|
|
|
#+BEGIN_SRC c
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
char *str = "Hello";
|
|
while (*str != *"\0") {
|
|
printf("Pointer Location: %p, Remaining Letters: %s\n", str, str);
|
|
str++;
|
|
}
|
|
}
|
|
#+END_SRC
|
|
|
|
If you run the code above it will output something similar to the following:
|
|
#+BEGIN_SRC
|
|
Pointer Location: 0x402008, Remaining Letters: Hello
|
|
Pointer Location: 0x402009, Remaining Letters: ello
|
|
Pointer Location: 0x40200a, Remaining Letters: llo
|
|
Pointer Location: 0x40200b, Remaining Letters: lo
|
|
Pointer Location: 0x40200c, Remaining Letters: o
|
|
#+END_SRC
|
|
|
|
As you can see we're progressively incrementing the pointer location by one and outputting the
|
|
remaining letters from the current pointer location to the end of the string until we hit the
|
|
=NULL= character.
|
|
|
|
The line:
|
|
~char *str = "Hello";~
|
|
is really a pointer to some location that starts with the letter =H= and ends with a =NULL=
|
|
character, =\0=.
|
|
|
|
By incrementing the pointer by one, we're moving the location it's /pointing/ at by one. After
|
|
the first iteration through the while loop the ~*str~ pointer points at the letter ~e~. After
|
|
the second iteration, ~*str~ points at ~l~, after the third iteration, ~l~, and so on.
|
|
|
|
In reality a pointer is something that /points/ to a place in memory. It doesn't contain a
|
|
value itself, it merely points to where a value is stored. Hence why the output has the weird
|
|
hex codes for =Pointer Location= like =0x402008=. That hex code is a location in memory known
|
|
as a /memory address/ that ~*str~, the pointer, points to.
|
|
|
|
|
|
**** *_Write a code for pointer to pointer and use that code to explain pointer to pointer in your own words_*
|
|
|
|
A pointer to pointer can be seen in the following code:
|
|
#+BEGIN_SRC c
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
int some_integer = 106;
|
|
int *pointer = &some_integer;
|
|
int **pointer_to_pointer = &pointer;
|
|
printf("Value: %d\nPointer: %p\nPointer to Pointer: %p\n", some_integer, pointer, pointer_to_pointer);
|
|
}
|
|
#+END_SRC
|
|
|
|
When we run the above it will output (pointer values may vary):
|
|
#+BEGIN_SRC
|
|
Value: 106
|
|
Pointer: 0x7ffc87ea34d4
|
|
Pointer to Pointer: 0x7ffc87ea34c8
|
|
#+END_SRC
|
|
|
|
Notice that the ~pointer~ variable has a different address it points to than
|
|
~pointer_to_pointer~.
|
|
|
|
The ~pointer~ variable points to the memory location of ~some_integer~ and the
|
|
~pointer_to_pointer~ variable points to the memory location of where the ~pointer~ variable is
|
|
stored.
|
|
|
|
With the above in mind, we can then think of a pointer to a pointer as a double indirection.
|
|
See the following diagram for what this effectively "looks" like:
|
|
#+BEGIN_EXAMPLE
|
|
Pointer to Pointer ----> Pointer ----> Value
|
|
#+END_EXAMPLE
|
|
|
|
Thus, if we only had the variable ~pointer_to_pointer~ we could access the value all the
|
|
pointers ultimately point to with a multiple dereference like so:
|
|
#+BEGIN_SRC c
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
int some_integer = 106;
|
|
int *pointer = &some_integer;
|
|
int **pointer_to_pointer = &pointer;
|
|
printf("Deref'd Value from Pointer to Pointer: %d\n", **pointer_to_pointer);
|
|
}
|
|
#+END_SRC
|
|
|
|
Which will output:
|
|
#+BEGIN_SRC
|
|
Deref'd Value from Pointer to Pointer: 106
|
|
#+END_SRC
|