if you didn't pick up your midterm in lecture, i have your midterm. you can pick them up at the end of discussion.
how do you feel about arrays? we can talk about them, or do some practice problems if you want.
sometimes, we need to represent things in our programs that are best
described by a combination of different variable types. for example,
suppose we want to write a program that keeps track of inventory for a
grocery store. for each item that the grocery store sells, we want to
keep track of the name of the item, and the number we have in
stock. in c, we can use structs to represent these kinds of
things. the declaration of the item struct looks like
this:
struct item
{
char name[50];
int quantity;
};
when we declare the item struct, we are declaring a new data type. it's kind of like drawing the "blueprints" for items... we're telling the computer what things need to be included in every item.
if we actually want some items to play around with, we need to declare
some variables of type struct item, like this:
struct item first; struct item second;
we now have two items that we can use. according to our definition of
the item struct, each item consists of an array of 50 characters
called name, and an integer called
quantity. to access variables within a struct, you use
the dot operator, like this:
strcpy(first.name, "apple"); first.quantity = 10; strcpy(second.name, "orange"); second.quantity = 50;
we can pass structs to functions in the same way that we pass any other variable. suppose we want to write a function that displays the name and quantity for an item. the definition looks like this:
void display(struct item i)
{
printf("%s %d\n", i.name, i.quantity);
}
back inside main, we can now say
display(first);
if we want to display the contents of the first item.
suppose we want to write a function that fills in an item's information for us. we can try to declare it like this:
void broken_fill_in(struct item i, char name[], int quantity)
{
strcpy(i.name, name);
i.quantity = quantity;
}
unfortunately, this does not work, because the item will be
passed by value [don't forget about call by value]! the
broken_fill_in function will receive a copy of the
struct, and the copy will be modified. the original item back in main
will not be modified.
if we want to make this work, we need to pass the struct by reference, like this:
void fill_in(struct item* i, char name[], int quantity)
{
strcpy((*i).name, name);
(*i).quantity = quantity;
}
and in main, we would say something like this:
fill_in(&first, "bananna", 50);
to save some typing, we could have declared fill_in like
this:
void fill_in(struct item* i, char name[], int quantity)
{
strcpy(i->name, name);
i->quantity = quantity;
}
i->name is equivalent to
(*i).name.
suppose we want to have lots of items in our inventory. we can declare an array of items, like this:
struct item inventory[100];
this makes an array of 100 items. if we want to fill in the information for some of the items and display the info, we can do it like this:
strcpy(inventory[24].name, "bananna");
inventory[24].quantity = 50;
printf("%s %d\n", inventory[24].name, inventory[24].quantity);
fill_in(&(inventory[12]), "grape", 20);
display(inventory[12]);
our programs can ask the computer for more memory as they are running
by using the malloc command. to do this, we ask
malloc for some number of bytes of memory, and
malloc returns us a pointer to a piece of memory of the
requested size. here's a simple example:
int* p = (int*) malloc(sizeof(int));
the sizeof command tells us the number of bytes that are
needed to store some data type. so, sizeof(int)tells us
how many bytes are needed to store an int [which is
usually 4]. it's best to use the sizeof command, even
though we know that we need 4 bytes, because in a few years people
might be using 8 bytes to store integers, and we would have to go back
and change our program to ask for 8 bytes. but, if we use
sizeof, we won't need to change our program.
the (int*) in front of the malloc call tells the computer
that we want to use the pointer returned by malloc as a pointer to
an integer.
after the malloc is done, we have reserved space in memory for an
integer, and we have a pointer to that integer. we can now do all the
usual stuff with this pointer, like *p = 24.
here's some more examples of malloc:
/* malloc a double */ double* dp = (double*) malloc(sizeof(double)); /* malloc an item */ struct item* ip = (struct item*) malloc(sizeof(struct item)); /* * malloc an array of 50 integers - the name of an array is always * a pointer to the first element of the array */ int* array = (int*) malloc(50 * sizeof(int));
after doing all this, we can use p, dp, and
ip like any other pointers, and we can use
array like any other array of integers.
when we don't need a malloc'd piece of memory anymore, we
need to free it. to do this, we use the free
command, and we pass it a pointer to the piece of memory that we want
freed, like this:
free(p); free(dp); free(ip); free(array);
write a function update that takes an item and an integer
x, and increases the quantity of the item by x.
using malloc, dynamically allocate memory for a new item. make its
name kiwi, and its quantity 5. display the
new item. try doing this both with and without using the
fill_in and display functions above.