Structs and Files Lab
Overview
In this lab, you’ll get some more practice with C, focusing on “strings” and file I/O.
As usual, I recommend you do this on mantis
through fern
.
Part A: Playing with structs
and strings
Getting started
First, make a new file, let’s call it lab2_struct.c
. Define the following struct
(retype this, don’t just copy it!):
typedef struct
{
int a[2];
long b;
char c[8];
char d[5];
} data_t;
Now, write a function print_data
that takes in a data_t
and prints out the elements of this struct
. You’ll need to remember a couple of things:
- You have to import
<stdio.h>
to getprintf
to work. - You can print an
int
with%d
or%x
without trouble, but along
is big – use%ld
or%lx
for something so “long”. - You can print a string (which is really just a null-terminated sequence of
char
) using%s
.
Once this works, create a new variable data
using this struct
definition in main
, fill it with values, and print it. Use whatever you want for a
and b
, but store "systems"
in C as follows:
data.c[0] = 's';
data.c[1] = 'y';
...
Don’t forget to null-terminate data.c
! Then go ahead and put some bytes in d
. Some UTF-8 encoded bytes would work nicely:
data.d[0] = 0xeb;
data.d[1] = 0xb4;
data.d[2] = 0x84;
data.d[3] = '\0';
Finally, call your print_data
function, and make sure to return 1
from main
to indicate a successful program completion.
To compile your code, we’ll use a shorter version of the gcc
command than usual (we don’t want it checking for nefarious things we’ll do later): gcc -o lab2_struct lab2_struct.c
.
Run your program (./lab2_struct
). Does it print what you expect?
How “strings” print
When printf
finds a %s
format specifier, it starts printing characters at the location provided, reading bytes one by one until it finds a null terminator ('\0'
).
-
Take a moment and write out the memory diagram for this
struct
. Where are the bytes ofc
andd
relative to each other? -
Okay, let’s be nefarious. Add this line of code just before the return of
main
:data.c[7] = '#';
. -
Add another call to
print_data
. What has changed? Why does this happen?
Copying strings
One way to copy string data around is to use the strcpy
function (you’ll need to import <string.h>
). It blindly copies the src
string into the dst
, including the null terminator, regardless of the size of dst
.
There’s a variant called strncpy
in which you have to specify the number of bytes to copy. This copies the provided src
string; if you say to copy more bytes than src
has before it hits a null terminator, it pads with 0s at the end (effectively null terminators).
-
Add another line to copy a new string into
c
:strcpy(data.c, "Lulu");
. -
Call
print_data
. Does the result make sense? -
Now add another line:
strncpy(data.c, "weRsneaky", 9);
. -
Call
print_data
one more time. Can you still make sense of the result? -
All the documentation for C functions is available through your terminal. In the terminal, type
man strcpy
and read through the “DESCRIPTION” to see what is going on withstrcpy
andstrncpy
.
Part B: File I/O
Getting started
Take a look at the line_counter.c
sample (remember you can find it linked from the Samples page on Moodle), and write down answers to the following questions:
- What is EOF?
- How are lines separated in a file?
- How would you count the number of vowels instead of the number of lines? (At a high level, you don’t need to write the code if you don’t want to)
Parsing lines
Modify the line_counter.c
sample to additionally print out the first character of each line, both as a character (%c
) and in hex (%x
). Try out your changes on this simple text file (actually copy these lines, as one has a tab and another has a space, then save it in the same folder as line_counter.c
):
Good morning!
How are you
doing
today??
Submit your lab2_struct.c
, line_counter.c
, and answers to the questions on Moodle for an engagement credit.
More practice
How would you modify the line_counter.c
program further to print out the length of each line? What about the last character? Make sure to think carefully through your logic to ensure you’re handling the last line in the file, too.