Try to do each one without looking at the solution. If you’re stumped, look at the solution and read the notes that I put in there as well. I try to explain why I solved it that way.
Table of contents, by lecture/lab
Discovering the sizes of things with sizeof()
(Lab 2)
sizeof()
is not how you get the length of an array. You cannot get the length of an array in C because that information is unavailable at runtime.
There are two kinds of numerical types in C: integer types and floating-point types.
There are also signed integers (the default) or unsigned integers (which cannot represent negative numbers.) Java doesn’t have these unsigned integers!
Did you know? sizeof()
is not how you get the length of an array. You cannot get the length of an array in C because that information is unavailable at runtime.
Unlike Java, the sizes of the integer types in C are not fixed. They depend on the platform: what CPU and operating system you’re using. There are some common sizes for these types that you are statistically far more likely to encounter, but they are not always that size.
You can find out the size of a type using the sizeof
operator. Although it may look like a function, this is NOT a function that executes at runtime. It operates at compile time and gives you a constant value saying how many bytes something takes up.
The sizes of the integer types in C follow these (in)equalities:
sizeof(char) == 1
sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
char
is an integer type in C. You can use a char
whenever you need a one-byte value or an array of one-byte values. (ASCII/UTF-8 characters are a special case of one-byte value.)
Now for practice
Make a new file called sizeof.c
. Inside, include stdio.h
as usual. Inside main
, put this code:
The %zu
format specifier prints out a size_t
as an u
nsigned value. Mhmm. Yep.
int x = 10;
printf("sizeof(x) = %zu\n", sizeof(x));
printf("sizeof(int) = %zu\n", sizeof(int));
Compile it like gcc -Wall -Werror --std=c99 -o sizeof sizeof.c
Run it like ./sizeof
. What does it print? Is that what you expected it to print?
Did you really create, compile, and run that program, or are you just trying to look at the answer because it seems “too easy” for you? ;) Cmon, go do it and see what it prints.
It prints:
sizeof(x) = 4
sizeof(int) = 4
If you were expecting it to print the sizes of the values in bits, that’s understandable, but no: everything in memory is measured in multiples of bytes, so the byte size is a much more useful thing to know.
Well strictly speaking everything in memory is measured in multiples of the “smallest addressable unit of memory,” which is “a byte” on almost every computer around today. But there are computers which are word-addressable, in which case
sizeof(int)
may be 1!
Now extend it. Print the sizes of the following types:
char
short
unsigned int
long
long long
float
double
long double
int*
&x
(yes, writesizeof(&x)
)int**
double*
char*
Make notes of what these print. Things to ask yourself/notice:
- Does
unsigned
change the size (e.g.int
vsunsigned int
)? - What size are the pointers?
- Does the pointer type change the size (e.g.
int*
vschar*
vsint**
vsdouble*
)?
I’m not gonna tell you the answers here. Go do it!
Array variables are really weird
Okay, now to blow your mind some. Add this code to the beginning of main
:
char a[10];
int b[10];
int* c = b;
Then add some more lines to print out:
sizeof(a)
sizeof(b)
sizeof(c)
sizeof(&a)
sizeof(&b)
What the hell is going on?
Array variables are the ones declared with brackets (here, a
and b
are array variables). C treats them very strangely. They’re kind of pointers but kind of not.
When you use sizeof()
on an array variable, it tells you how many bytes it takes up. It does NOT tell you the length, at least not directly. (Compare sizeof(a)
and sizeof(b)
. They’re the same length, but they’re different numbers of bytes, because their items are different sizes!)
But when you use sizeof()
on a pointer type like c
, it gives you the size of the pointer. It never gives you the length of the array that the pointer points to.
The size of an array variable is only available:
- at compile time, and
- within the same function in which the array variable was declared.
VLAs work a little differently. We’ll get to those.
32-bit machines
I had a bit of an oversight, and in order to use the -m32
flag in the next command, you need to install something into your VM. In your VM terminal, run this:
sudo apt-get install gcc-multilib
It will ask for your password; type it in. It will take a few minutes to install, so take a little break. Then you can continue.
(apt-get install
is how you can install all kinds of things into your VM. But don’t go crazy with it lol. sudo
runs the command as an administrator so that it actually works.)
You’re compiling on a 64-bit machine. But you can compile a 32-bit executable by using the -m32
flag to gcc, like so:
gcc -Wall -Werror --std=c99 -m32 -o sizeof sizeof.c
Now run ./sizeof
. Which numbers changed? Why do you think that is?
Seems like many (but not all!) things that are 8 bytes (64 bits) on x86-64 are 4 bytes (32 bits) on x86-32. A 32-bit CPU has 32-bit registers and can only perform 32-bit loads and stores, so that seems reasonable enough.
Notice also that pointers are 4 bytes instead of 8. Generally, 32-bit machines can only use addresses that are 32 bits, and can only access 232 Bytes of memory, which is 4 GiB. This is the main reason we moved to 64-bit architectures - so we could access more than 4 gigabytes of memory. Having bigger integers is just a bonus!
Conclusion: Things to remember
- When you pass an array to another function, there is no way to find out what length it is.
- This is a consequence of the fact that arrays become pointers when passed to functions.
- This is why
fgets
takes a pointer and length as arguments: because you have that info and it doesn’t!
sizeof()
is not how you get the length of an array in C.- You cannot get the length of an array in C in general, because that information is unavailable at runtime.
sizeof()
can be used on array variables within the same function to get their byte size…- But this is a pretty niche use case and doesn’t generalize to all arrays.