======Exercise 8: Sizes And Arrays======
In the last exercise you did math, but with a '\0' (nul) character.
This may be odd coming from other languages, since they try to treat
"strings" and "byte arrays" as different beasts. C however treats
strings as just arrays of bytes, and it's only the different printing
functions that know there's a difference.
Before I can really explain the significance of this, I have to
introduce a few more concepts: sizeof and arrays. Here's the code we'll
be talking about:
#include <stdio.h>
int main(int argc, char *argv[])
{
int areas[] = {10, 12, 13, 14, 20};
char name[] = "Zed";
char full_name[] = {
'Z', 'e', 'd',
' ', 'A', '.', ' ',
'S', 'h', 'a', 'w', '\0'
};
// WARNING: On some systems you may have to change the
// %ld in this code to a %u since it will use unsigned ints
printf("The size of an int: %ld\n", sizeof(int));
printf("The size of areas (int[]): %ld\n",
sizeof(areas));
printf("The number of ints in areas: %ld\n",
sizeof(areas) / sizeof(int));
printf("The first area is %d, the 2nd %d.\n",
areas[0], areas[1]);
printf("The size of a char: %ld\n", sizeof(char));
printf("The size of name (char[]): %ld\n",
sizeof(name));
printf("The number of chars: %ld\n",
sizeof(name) / sizeof(char));
printf("The size of full_name (char[]): %ld\n",
sizeof(full_name));
printf("The number of chars: %ld\n",
sizeof(full_name) / sizeof(char));
printf("name=\"%s\" and full_name=\"%s\"\n",
name, full_name);
return 0;
}
In this code we create a few arrays with different data types in them.
Because arrays of data are so central to how C works, there's a huge
number of ways to create them. For now, just use the syntax type name[]
= {initializer}; and we'll explore more. What this syntax means is, "I
want an array of type that is initialized to {..}." When C sees this it
does the following:
* Look at the type, in this first case it's int.
* Look at the [] and see that there's no length given.
* Look at the initializer, {10, 12, 13, 14, 20} and figure out that
you want those 5 ints in your array.
* Create a piece of memory in the computer, that can hold 5 integers
one after another.
* Take the name you want, areas and assign it this location.
In the case of areas it's creating an array of 5 ints that contain
those numbers. When it gets to char name[] = "Zed"; it's doing the same
thing, except it's creating an array of 3 chars and assigning that to
name. The final array we make is full_name, but we use the annoying
syntax of spelling it out, one character at a time. To C, name and
full_name are identical methods of creating a char array.
The rest of the file, we're using a keyword called sizeof to ask C how
big things are in bytes. C is all about the size and location of pieces
of memory and what you do with them. To help you keep that straight, it
gives you sizeof so you can ask how big something is before you work
with it.
This is where stuff gets tricky, so first let's run this and then
explain further.
======What You Should See======
$ make ex8
cc -Wall -g ex8.c -o ex8
$ ./ex8
======The size of an int: 4======
======The size of areas (int[]): 20======
======The number of ints in areas: 5======
======The first area is 10, the 2nd 12.======
======The size of a char: 1======
======The size of name (char[]): 4======
======The number of chars: 4======
======The size of full_name (char[]): 12======
======The number of chars: 12======
name="Zed" and full_name="Zed A. Shaw"
$
Now you see the output of these different printf calls and start to get
a glimpse of what C is doing. Your output could actually be totally
different from mine, since your computer might have different size
integers. I'll go through my output:
5
My computer thinks an int is 4 bytes in size. Your computer
might use a different size if it's a 32-bit vs. 64-bit.
6
The areas array has 5 integers in it, so it makes sense that my
computer requires 20 bytes to store it.
7
If we divide the size of areas by size of an int then we get 5
elements. Looking at the code, this matches what we put in the
initializer.
8
We then did an array access to get areas[0] and areas[1] which
means C is "zero indexed" like Python and Ruby.
9-11
We repeat this for the name array, but notice something odd
about the size of the array? It says it's 4 bytes long, but we
only typed "Zed" for 3 characters. Where's the 4th one coming
from?
12-13
We do the same thing with full_name and notice it gets this
correct.
13
Finally we just print out the name and full_name to prove that
they actually are "strings" according to printf.
Make sure you can go through and see how these output lines match what
was created. We'll be building on this and exploring more about arrays
and storage next.
======How To Break It======
Breaking this program is fairly easy. Try some of these:
* Get rid of the '\0' at the end of full_name and re-run it. Run it
under Valgrind too. Now, move the definition of full_name to the
top of main before areas. Try running it under Valgrind a few times
and see if you get some new errors. In some cases, you might still
get lucky and not catch any errors.
* Change it so that instead of areas[0] you try to print areas[10]
and see what Valgrind thinks of that.
* Try other versions of these, doing it to name and full_name too.
======Extra Credit======
* Try assigning to elements in the areas array with areas[0] = 100;
and similar.
* Try assigning to elements of name and full_name.
* Try setting one element of areas to a character from name.
* Go search online for the different sizes used for integers on
different CPUs.
Copyright (C) 2010 Zed. A. Shaw
Credits