forked from zedz/lcthw-cn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ex9.tex
114 lines (91 loc) · 4.88 KB
/
ex9.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
\chapter{Exercise 9: Arrays And Strings}
In the last exercise you went through an introduction to creating basic
arrays and how they map to strings. In this exercise we'll more completely
show the similarity between arrays and strings, and get into more about
memory layouts.
This exercise shows you that C stores its strings simply as an array
of bytes, terminated with the \verb|'\0'| (nul) byte. You probably clued
into this in the last exercise since we did it manually. Here's
how we do it in another way to make it even more clear by comparing it
to an array of numbers:
\begin{code}{ex9.c}
<< d['code/ex9.c|pyg|l'] >>
\end{code}
In this code, we setup some arrays the tedious way, by assigning a value
to each element. In \ident{numbers} we are setting up numbers, but in
\ident{name} we're actually building a string manually.
\section{What You Should See}
When you run this code you should see first the arrays printed with
their contents initialized to zero, then in its initialized form:
\begin{code}{ex9 output}
\begin{lstlisting}
<< d['code/ex9.out'] >>
\end{lstlisting}
\end{code}
You'll notice some interesting things about this program:
\begin{enumerate}
\item I didn't have to give all 4 elements of the arrays to initialize them.
This is a short-cut that C has where, if you set just one element, it'll
fill the rest in with 0.
\item When each element of \ident{numbers} is printed they all come out as
0.
\item When each element of \ident{name} is printed, only the first element 'a'
shows up because the \verb|'\0'| character is special and won't display.
\item Then the first time we print \ident{name} it only prints "a" because,
since the array will be filled with 0 after the first 'a' in the
initializer, then the string is correctly terminated by a \verb|'\0'|
character.
\item We then setup the arrays with a tedious manual assignment to each thing
and print them out again. Look at how they changed. Now the numbers
are set, but see how the \ident{name} string prints my name correctly?
\item There's also two syntaxes for doing a string:
\verb|char name[4] = {'a'}| on line 6
vs. \verb|char *another = "name"| on line 44. The first
one is less common and the second is what you should use
for string literals like this.
\end{enumerate}
Notice that I'm using the same syntax and style of code to interact with both
an array of integers and an array of characters, but that \ident{printf}
thinks that the \ident{name} is just a string. Again, this is because to the
C language there's no difference between a string and an array of characters.
Finally, when you make string literals you should usually use the
\verb|char *another = "Literal"| syntax. This works out to be the same thing,
but it's more idiomatic and easier to write.
\section{How To Break It}
The source of almost all bugs in C come from forgetting to have enough
space, or forgetting to put a \verb|'\0'| at the end of a string. In
fact it's so common and hard to get right that the majority of good C
code just doesn't use C style strings. In later exercises we'll actually
learn how to avoid C strings completely.
In this program the key to breaking it is to forget to put the \verb|'\0'|
character at the end of the strings. There's a few ways to do this:
\begin{enumerate}
\item Get rid of the initializers that setup \ident{name}.
\item Accidentally set \verb|name[3] = 'A';| so that there's no terminator.
\item Set the initializer to \verb|{'a','a','a','a'}| so there's too many
'a' characters and no space for the \verb|'\0'| terminator.
\end{enumerate}
Try to come up with some other ways to break this, and as usual run all of
these under Valgrind so you can see exactly what is going on and what the
errors are called. Sometimes you'll make these mistakes and even
Valgrind can't find them, but try moving where you declare the variables
to see if you get the error. This is part of the voodoo of C, that
sometimes just where the variable is located changes the bug.
\section{Extra Credit}
\begin{enumerate}
\item Assign the characters into \ident{numbers} and then use \ident{printf}
to print them a character at a time. What kind of compiler warnings
did you get?
\item Do the inverse for \ident{name}, trying to treat it like an array
of \ident{int} and print it out one \ident{int} at a time. What
does Valgrind think of that?
\item How many other ways can you print this out?
\item If an array of characters is 4 bytes long, and an integer is 4 bytes
long, then can you treat the whole \ident{name} array like it's just
an integer? How might you accomplish this crazy hack?
\item Take out a piece of paper and draw out each of these arrays as a
row of boxes. Then do the operations you just did on paper to see
if you get them right.
\item Convert \ident{name} to be in the style of \ident{another} and see
if the code keeps working.
\end{enumerate}