byte addresses[][6] = {"0"};
This creates an array of arrays of six bytes. The declaration does not tell you how big that array is, but in this particular case there is an initializer. The initializer causes the array to be one element long. That one element will be an array of six bytes initialised to 33,0,0,0,0,0 - 33 being the ascii code for '0'.
You will find, in the code, this expression:
sizeof(addresses)/sizeof(addresses[0])
This tells the compiler to take the size of the whole array and to divide it by the size of one of the elements of the array. In this case, the whole array is 6 bytes long, and the first element is 6 bytes long.
Alternatively, you may find this
sizeof(addresses)/sizeof(*addresses)
Which means the same thing, but explaining why that is the case is beyond the scope of this reply.
The point of this is that you can simply add more items in the initializer, and the compiler will substitute in the correct values allowing code to iterate through as many elements as the array happens to have.
typedef struct package Package;
Package data;
typedef
establishes an alias for a type. For instance, if we define [nobbc]typedef int Foo[5][5][/nobbc]
, we can subsequently use Foo to declare that something is a 5*5 array of int. In this case, 'Package' is defined as an alias for 'struct package', and then a variable of type 'struct package' is declared.
This actually identifies the code as being a bit elderly. Back in the day, you had to say struct package
every time you wanted to use the type, which is a bit of an annoyance and so it was common to typedef an alias. These days, a struct is simply a class whose members are all public, and the name of the struct can be used as a type without further mucking about.