Learning C by Comparison #2: Arrays, and More on Structs
This is the second part of my Learning code by comparison series of learning C with explanations in Ruby.
This time around I'm going to answer some simple questions I've had for myself while learning basic C. The first thing is how I could call a struct from another:
In Ruby I can do this:
class Person
attr_accessor :name, :age, :colors
def initialize(name, age, eye_color, hair_color)
self.name = name
self.age = age
self.colors = Colors.new(eye_color, hair_color)
end
end
class Colors
attr_accessor :eyes, :hair
def initialize(eye_color, hair_color)
self.eyes = eye_color
self.hair = hair_color
end
end
person = Person.new('James Newton', 21, 'brown', 'brown')
person.name #=> "James Newton"
person.colors.hair #=> "brown"
Since we don't have fancy classes in C as I touched on in the last post, we use struct to define our "objects" in C:
#include <stdio.h>
typedef struct {
char *eyes;
char *hair;
} Colors;
typedef struct {
char *name;
char *age;
Colors colors;
} Person;
int main(int argc, const char *argv[])
{
Person person = {"James Newton", 21, {"brown", "brown"}};
printf("Name: %s, Age: %i, Eye color: %s, Hair color: %s\n", person.name, person.age, person.colors.eyes, person.colors.hair);
return 0;
}
And after a quick compile and run we'll see:
$ gcc test.c
$ ./a.out
Name: James Newton, Age: 21, Eye color: brown, Hair color: brown
Now, how to work with arrays!
Ruby is easy, array = ['one', 'two', 'three'] gives us an array of three strings we could access with array[i]. With C we get a little complicated depending on what information we're throwing in our array.
#include <stdio.h>
int main(int argc, const char *argv[])
{
char *people[3] = {"James Newton", "Robert Babcock", "Zach Smith"};
for (int i = 0; i < sizeof(people) / sizeof(people[0]); i++) {
printf("Name: %s\n", people[i]);
}
return 0;
}
We can also define people[3] one by one like:
char *people[3];
people[0] = "James Newton";
people[1] = "Robert Babcock";
people[2] = "Zach Smith";
Since we're doing a loop here to print out all the names in people we're using sizeof to get the size of people in bytes, then dividing it by the size of an item in the array (people[0]). Without this the loop would continue to run past the 3 items because the array is greater than 3 bytes, and segfault. Ruby handles this for us when looping through arrays.
Compiling and running would get us:
$ gcc test2.c
$ ./a.out
Name: James Newton
Name: Robert Babcock
Name: Zach Smith
So now that we have an idea of how to use struct, why not try to make an array of "objects"?
Adding on to our Ruby script from earlier, we could do this quickly:
people = []
people << Person.new('James Newton', 21, 'brown', 'brown')
# add more people, like Robert and Zach.
people.first.name #=> "James Newton"
Now we'll make use of the code from both of our previous C programs to make an array called people that contain several Person struct's.
#include <stdio.h>
typedef struct {
char *name;
int age;
} Person;
int main(int argc, const char *argv[])
{
Person people[2] = {{"James Newton", 21}, {"Robert Babcock", 22}};
for (int i = 0; i < sizeof(people) / sizeof(Person); i++) {
printf("Name: %s, Age: %i\n", people[i].name, people[i].age);
}
return 0;
}
And when we compile we get the following output:
$ gcc test3.c
$ ./a.out
Name: James Newton, Age: 21
Name: Robert Babcock, Age: 22
And we'll stop here. So with this we've got some very simple samples on how to use a struct inside of another struct, and arrays.