# Structs and Files --- CS 130 // 2024-12-03 # Floating Point Numbers ## Scientific Notation - We can represent a number like $0.000312$ in **scientific notation** + $3.12\times 10^{-4}$ - We can reserve bits for the $3.12$ part and reserve other bits for the exponent $-4$
$$(-1)^s \times \mbox{fraction} \times 2^{\mbox{exponent}}$$ # `struct` / `typedef` ## Create a `struct` - A `struct` is a user-defined type that groups multiple values into one - Suppose we wanted a type to represent a 2D point: ```c struct point { double x; double y; }; ``` - Now we can create a `point` and modify it using: ```c struct point p; p.x = 5; p.y = 4; ``` ## Using `typedef` - The `typedef` keyword allows us to create aliases for types - For example, we could create an alias for `char *` named `string` for convenience: ```c typedef char string[10]; ... string x = "abc"; ``` - Alternatively, we could do: ```c typedef char *string; ``` ## Using `typedef` with `struct` - It is common practice to use `typedef` with `struct`s to avoid needing the `struct` keyword everywhere ```c struct point { double x; double y; } typedef struct point POINT; ``` ```c POINT p; p.x = 4; p.y = 5; ``` ```c POINT p = {.x=4, .y=5}; ``` ## Using `typedef` with `struct` - We can even avoid generating two names for the struct and simply do: ```c typedef struct { double x; double y; } POINT; ``` ## Example: Euclidean Distance - Suppose we'd like to write a function to calculate the distance between two points + $d = \sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}$ --- ```c #include
double distance(POINT p1, POINT p2) { double xdiff = p1.x - p2.x; double ydiff = p1.y - p2.y; return sqrt(xdiff * xdiff + ydiff * ydiff); } ``` ## Try it ```c #include
#include
typedef struct { double x; double y; } POINT; double distance(POINT p1, POINT p2) { double xdiff = p1.x - p2.x; double ydiff = p1.y - p2.y; return sqrt(xdiff * xdiff + ydiff * ydiff); } int main() { POINT p1 = {.x=4,.y=5}; POINT p2 = {.x=0,.y=0}; printf("Distance: %f\n",distance(p1,p2)); return 0; } ``` ## Using `math.h` - For historical reasons, the math library `math.h` is not a standard library - Back in the day, floating point math was **slow** and these functions took up a lot of extra memory - Thus, to compile a program that uses `math.h` you must explicitly tell `gcc` to include it: ```bash $ gcc distance.c -lm ``` - The `-lm` stands for "link math" - YMMV: codeSpaces made me do it, but my local compiler didn't ## Pointers to Structs - Suppose we have the following: ```c POINT p = {.x = 4, .y = 5}; ``` - We can define a **pointer** to `p`: ```c POINT *pp = &p; ``` - To get the `x` and `y` coordinates out of `pp`, normally we'd have to do: ```c int x = (*pp).x; int y = (*pp).y; ``` ## Pointers to Structs - Pointers to structs are so common that there is a special operator to dereference and extract a field simultaneously ```c POINT p = {.x = 4, .y = 5}; POINT *pp = &p; int x = pp->x; // same as (*pp).x int y = pp->y; // same as (*pp).y ``` # Files ## Reading from a File - File reading/writing is included in `stdio.h` - To open a file in C, you use the `fopen` function: ```c FILE *fp = fopen("input.txt", "r"); ``` + The `"r"` opens the file for **reading** and the path is relative to the directory of your program ## Reading from a File - Once a file is open, you can **read** text from it using: ```c FILE *fp = fopen("input.txt", "r"); char buffer[80]; ``` ```c // Reads until a newline character is found. Similar to // the readline() method in Python. // Stops after 79 characters to not overfill the buffer fgets(buffer, 80, fp); ``` - `fgets` returns `buffer` if it reads at least one character and returns `NULL` otherwise - Just like Python, it **includes** the newline characters at the end of the string ## Looping Over a File - One common pattern is looping over a file: ```c FILE *fp = fopen("my_file.txt", "r"); char buffer[80]; while (fgets(buffer, 80, fp) != NULL) { // buffer contains the current line here printf("%s\n",buffer); } fclose(fp); ``` ## Looping Over a File - Use sscanf to read ints in the file: ```c FILE *fp = fopen("my_file.txt", "r"); char buffer[80]; int total = 0; while (fgets(buffer, 80, fp) != NULL) { // buffer contains the current line here printf("%s\n",buffer); int curr_int = 0; sscanf(buffer,"%d",&curr_int); total += curr_int; } fclose(fp); printf("Total is %d.\n",total); ``` ## Parsing Structured Data - When reading a file, it is common to: 1. Use `fgets` to get one line at a time 2. Then use `sscanf` to parse the line into something useful - `sscanf` is identical to `scanf` except it reads from a string buffer instead of standard input ## Exercise - Suppose we'd like to parse a table of integers into a 2D array in C - Let's assume the file format is as follows: ```text 4/4 0,1,2,3 4,5,6,7 8,9,10,11 12,13,14,15 ``` - First two numbers are the width/height of the table - How would you go about this? ## Exercise Hint ```c FILE *fp = fopen("twoDarray.txt", "r"); char buffer[80]; int rows = 0; int cols = 0; fgets(buffer, 80, fp); sscanf(buffer,"%d/%d",&rows,&cols); printf("%d %d\n",rows,cols); ``` ## Exercise - **Discuss with those around you:** + How would you break this program down into helper functions? + Are there any functions in `string.h` and/or `stdlib.h` that might make parsing the rest easier? Look up the documentation! + Consider looking through `ctype.h`, too! ## Writing to a File - To open a file for writing you use: ```c FILE *fp = fopen("input.txt", "w"); ``` + If `input.txt` already exists, it is deleted + If it doesn't exit, it is created - You can use `fprintf` to print to a file: ```c fprintf(fp, "%d %d %d\n", 100, 200, 300); ``` ## Closing Files - It is important to **close** your files to inform your OS that you're done with the file - You can do this with: ```c fclose(fp); ``` ## Exercise - Suppose we have have some 2D points in a file - We could encode them in the following way: ```text 4 0 0 1 1 0 5 3.14 2.71 ``` - First line tells you how many points are in the file and then every other line is of the form `x y` ## Exercise (cont.) - Write a function called `read_points` with the following signature: ```c POINT *read_points(char *filename) ``` - Should parse the file into an array of `POINT` objects - Remember to use `malloc` to allocate the memory on the heap!