Description
Part 1: sizeof()
is not how you get the length of an array
You don’t have to turn anything in for this part, but please do it. This stuff is important and I’ll expect you to know it in future labs/projects/lectures.
sizeof()
is not how you get the length of an array. You cannot “get” the length of an array in C because arrays are not real.
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!
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.
sizeof()
is not how you get the length of an array. You cannot “get” the length of an array in C because arrays are not real.
You can find out the size of a type using the sizeof
operator. This is NOT a function. 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 inequalities:
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. Text characters are really a special case of one-byte value.
Now for practice
Make a copy of lab1.c
as a starting point, and name it sizeof.c
.
Inside main
, put this code:
The (int)
in there is to cast the result of sizeof
to an int. Otherwise, you’ll get annoying warnings.
int x = 10;
printf("sizeof(x) = %d\n", (int)sizeof(x));
printf("sizeof(int) = %d\n", (int)sizeof(int));
Compile it like gcc -Wall -Werror --std=c99 -o
sizeof sizeof.c
Run it like ./sizeof
. What does it print?
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.
-
Does
unsigned
change the size? -
What size are the pointers?
-
Does the pointer type change the size?
Array variables are really weird
Okay: now to blow your mind some. Add this code.
char a[10];
int b[10];
int* c = b;
Now print sizeof(a)
, sizeof(b)
, and sizeof(c)
, sizeof(&a)
, and sizeof(&b)
.
What the hell is going on?
Array variables are the ones declared with brackets. 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.
But when you use sizeof()
on a pointer, it gives you the size of the pointer. It never gives you the length of the array that the pointer points to.
sizeof()
is not how you get the length of an array. You cannot “get” the length of an array in C because arrays are not real. sizeof()
is not how you get the length of an array. You cannot “get” the length of an array in C because arrays are not real. sizeof()
is not how you get the length of an array. You cannot “get” the length of an array in C because arrays are not real.
Finally: 32-bit machines
Thoth is 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?
Part 2: Console I/O
Make a new file, lab2.c
. Here’s some code to get you started.
Feel free to reuse these functions in future labs/projects.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void get_line(char* buffer, int size) {
fgets(buffer, size, stdin);
int len = strlen(buffer);
// this is a little more robust than what we saw in class.
if(len != 0 && buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
}
// returns 1 if the two strings are equal, and 0 otherwise.
int streq(const char* a, const char* b) {
return strcmp(a, b) == 0;
}
// returns 1 if the two strings are equal ignoring case, and 0 otherwise.
// so "earth" and "Earth" and "EARTH" will all be equal.
int streq_nocase(const char* a, const char* b) {
// hohoho aren't I clever
for(; *a && *b; a++, b++) if(tolower(*a) != tolower(*b)) return 0;
return *a == 0 && *b == 0;
}
int main() {
return 0;
}
What your program will do
This program will calculate how much the user weighs on various planets in our solar system. Here’s how your program will work:
-
Ask them what planet they want to visit.
-
If they typed
exit
, usebreak;
to exit the loop. -
If they typed
earth
, call them silly or something. -
Otherwise,
-
Get the scaled weight for that planet using your
planet_to_weight
function (see below). -
If it returned a value less than 0, that means it’s not a planet, so say so.
-
Otherwise, tell them how much they’d weigh there.
-
"%.2f"
would be a nice format.
-
-
-
Go back to step 1.
Here’s how it looks when I interact with my program:
[thoth ~/private/cs0449/lab2]: ./lab2
Uh, how much do you weigh? 250
What planet do you wanna go to ('exit' to exit)? mars
You'd weigh 95.00 there.
What planet do you wanna go to ('exit' to exit)? JUPITER
You'd weigh 635.00 there.
What planet do you wanna go to ('exit' to exit)? pluto
That's not a planet.
What planet do you wanna go to ('exit' to exit)? earth
uh, you're already there, buddy
What planet do you wanna go to ('exit' to exit)? exit
[thoth ~/private/cs0449/lab2]:
Reading a number
First we’ll read a number, the user’s weight (sorry if that’s sensitive info…).
-
Use the
get_line
function to ask the user for their weight.
printf("How much do you weigh? ");
char input[100];
get_line(input, sizeof(input)); // notice the sizeof!
We used sizeof(input)
so we don’t have to repeat the 100. Also, that avoids mistakes if you change the size of the input
array.
-
Use
sscanf
to parse the number out of the string. You use it like this:
int weight;
sscanf(input, "%d", &weight); // DON'T FORGET THE & or it'll crash.
sscanf
means string
. It’s like
scan formattedprintf
backwards. It can parse values out of a string.
How this works is by handing off a pointer to the weight
variable to sscanf
. Then it looks in the input
string for an integer (the "%d"
tells it to do that), and it puts that value into weight
indirectly.
Test it out, see if it works. Never write a whole program at once. Compile early, compile often. Print out the weight variable to see if it parsed correctly.
Making a function
The const
means “I only want to read the string from this variable, I promise I won’t change it.” We’ll talk about it later in the term.
Before main
, make a function with this signature:
float weight_on_planet(const char* planet_name, int user_weight)
This function takes the name of a planet and a weight, and returns:
-
what you’d weigh on that planet, or
-
-1 if it’s not a planet.
-
Like Pluto.
-
Which is not a planet.
-
It’s a dwarf planet.
-
It’s a Kuiper Belt Object.
-
It’s not a planet.
-
Okay?
-
Okay.
-
-
-
-
-
-
-
Here is a table of relative gravity strengths on the seven non-earth planets in our solar system:
Planet |
Gravity |
---|---|
Mercury |
0.38 |
Venus |
0.91 |
Mars |
0.38 |
Jupiter |
2.54 |
Saturn |
1.08 |
Uranus |
0.91 |
Neptune |
1.19 |
Use streq_nocase
to check which planet it is, e.g.
if(streq_nocase(planet, "mars")) {
// it's mars.
}
The “case-insensitivity” of this function means they can type e.g. “mars”, “Mars”, “MARS” and it’ll all work the same way.
Remember, if the planet is not on this list, return -1.
TEST IT OUT. Call it from main with a few values and see what it returns. See if it behaves how you expect. Test, test, test. Testing your own code BEFORE you use it will save you so much trouble.
Loopydoop
Make an infinite loop. true
is not a thing in C by default, so you can write while(1)
to make an infinite loop.
In that loop, you’ll be reading a line of input from the user and then using streq_nocase
to see what they typed in. You’ll have to check for "exit"
and "earth"
specifically. Then, if it’s neither of those, use weight_on_planet
. Go look at the program description above!
Submission
Remember the instructions you learned last time? Replace lab1
with lab2
.