Introduction to Structs
Structs are objects in C++ that represent "data structures", or variables, functions, etc. that are organized under a categorizing identifier.
Andrew, no one is impressed when you use lots of words.
Fine... in other words, structs are ways of grouping variables and functions into single, cohesive objects.
For example, instead of shipping you your TV piece by piece, the manufacturers send it as a completed, cohesive television.
"Hey, nice screen, antenna, RF input, tuner, and speakers! Is it a Sony?"
Don't be foolish, it's a television. We name it by its whole unit and worry less about its individual parts... yet, we still have names for those individual parts:
Data Members are variable components of a given struct; they can be of any variable type.
So, essentially, when we declare a struct, we are declaring a new type! All of the rules we're familiar with (when dealing with types) now similarly apply.
For starters, we should look at how to declare a struct...
We declare structs using the following syntax:
struct <structName> {
<member1_type> <member1_name>;
<member2_type> <member2_name>;
// ...etc.
}; // Remember the semicolon!
So how about an example? Let's declare a struct, as such:
struct Computer {
char model[5];
int processors;
double processorSpeed;
};
Here, I've defined a struct named Computer that has three data members: (1) a 5 element cstring named model, (2) an int named processors, and (3) a double for the processor speed.
struct Computer {
char model[5] = "L4M3";
int processors = 4;
double processorSpeed = 2.6;
};
We'll talk more about "initializing" struct data members later.
A struct instance / object is a particular object of a particular type of struct.
If we modeled the car company Ford as a struct, then an instance of Ford might be: Ford myMustang;.
That said, if I wanted to declare an instance of a struct, I need the following notation:
struct Computer {
char model[5] = "L4M3";
int processors = 4;
double processorSpeed = 2.6;
};
// ...
// [Primitive] "i" is of type "int"
int i;
// [Struct] "myAncientMac" is of type "Computer"
Computer myAncientMac;
Here, myAncientMac is an instance of struct Computer.
Alright, so I've declared a struct... now what?
The world is your oyster! Go forth and struct!
But first... let's talk about how to talk about members of structs...
The Element / Member Selection Operator (.) says, "Give me member <rvalue> of the object in my <lvalue>..."
That is, we select the member on the right of the period from the struct instance on the left.objectInstance.dataMember
Here's an example:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct Computer {
char model[5];
int processors;
double processorSpeed;
};
int main () {
Computer myAncientMac;
strcpy(myAncientMac.model, "C00L");
myAncientMac.processors = 4;
myAncientMac.processorSpeed = 2.6;
cout << myAncientMac.model << endl;
cout << myAncientMac.processors << endl;
cout << myAncientMac.processorSpeed << endl;
}
Will the following code compile or have any unpredictable behavior? If "No" to both questions, what will it output?
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct Computer {
char model[5];
int processors;
double processorSpeed;
};
int main () {
Computer myAncientMac;
cout << myAncientMac.model << endl;
cout << myAncientMac.processors << endl;
cout << myAncientMac.processorSpeed << endl;
}
Will the following code compile or have any unpredictable behavior? If "No" to both questions, what will it output?
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct Computer {
char model[5];
int processors;
double processorSpeed;
};
int main () {
cout << myAncientMac.model << endl;
cout << myAncientMac.processors << endl;
cout << myAncientMac.processorSpeed << endl;
}
Structs are defined within scope the same way variables are:
Because we can treat struct definitions as entities of a particular scope, there is a shorthand to both define and declare variables of a struct type:
struct Computer {
char model[5];
int processors;
double processorSpeed;
};
Computer c1;
Computer c2;
Computer andrewsHackStation5000;
// ...
// Is equivalent to saying
// ...
struct Computer {
char model[5];
int processors;
double processorSpeed;
} c1, c2, andrewsHackStation5000;
This is useful for when we want to organize data in a struct locally to a function without polluting the global namespace.
Which of the following marked lines would I need to remove in order for the code to compile and run correctly?
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct wow {
int woah;
char manyWords[11];
char* greatWords;
} otherDoge;
int main () {
struct such {
double suchRepetition;
char manyWords[10];
} doge;
// Which lines below break the code?
// Which lead to undefined behavior?
otherDoge.wow.woah = 3; // 1
strcpy(such.wow.manyWords, "suchPoetry"); // 2
strcpy(doge.wow.manyWords, "suchPoetry"); // 3
strcpy(otherDoge.manyWords, "suchPoetry"); // 4
such.suchRepetition = 2.222222; // 5
otherDoge.greatWords = doge.manyWords; // 6
strcpy(otherDoge.greatWords, otherDoge.manyWords); // 7
cout << doge.manyWords << endl; // 8
}
Constructors and Initializing Structs
Now, the next question you might be asking is: how do I initialize a struct?
To give values to our struct data members without specifying them by hand with every declaration, we can use constructors:
A constructor is used to initialize the data members of a newly declared struct object; it's how we "initialize" them.
Constructors are called automatically at struct instance declaration and are defined by listing a member function with the same name as the struct and NO return type.StructName () { /* Constructor Body */ }
A parameterized constructor is simply a constructor that takes parameters when constructing an object.
StructName (paramType1 param1, paramType2 param2, ...) { /* Constructor Body */ }
In general, a member function is a function defined on the struct that instances of the struct have access to.
Take the following example for... example:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Ford {
// Data Members ---------------
int tires;
string model;
bool fourWheelDrive;
// ----------------------------
// Constructor for Ford objects
Ford () {
tires = 5; // 4+1 Spare
model = "Ranger";
fourWheelDrive = false;
}
};
int main () {
// Constructor invoked below!
Ford myCar;
cout << myCar.tires << endl;
cout << myCar.model << endl;
cout << myCar.fourWheelDrive << endl;
}
See how when I declared a new instance of Ford called myCar in the main function, it attains the member values defined in the constructor.
Member Functions
Member functions, sometimes called methods, are functions that are called by instances of a particular struct.
Here's an example where I define a member function called getFlat() that returns the number of remaining tires on my Ford after decrementing how many it has.
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Ford {
// Data Members ---------------
int tires;
string model;
bool fourWheelDrive;
// ----------------------------
// Member Functions -----------
// Removes a tire and returns
// the number of tires left
int getFlat () {
tires--;
if (tires < 0) {
tires = 0;
}
return tires;
}
// ----------------------------
// Constructor
Ford () {
// +One spare
tires = 5;
model = "Ranger";
fourWheelDrive = false;
}
};
int main () {
Ford myCar;
Ford yourCar;
myCar.getFlat();
myCar.getFlat();
yourCar.getFlat();
cout << myCar.tires << endl;
cout << yourCar.tires << endl;
}
Some things to notice:
The number of tires each instance of Ford has is specific to each object in main
When I reference a member variable in a member function defined in a struct, it refers to the variable owned by the calling instance
But what if I wanted to define a member function outside of the struct definition? I could use the following syntax:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Ford {
int tires;
string model;
bool fourWheelDrive;
// Need function prototype
int getFlat();
// Constructor
Ford () {
// +One spare
tires = 5;
model = "Ranger";
fourWheelDrive = false;
}
};
// Member function definition
int Ford::getFlat () {
tires--;
if (tires < 0) {
tires = 0;
}
return tires;
}
int main () {
Ford myCar;
Ford yourCar;
myCar.getFlat();
myCar.getFlat();
yourCar.getFlat();
cout << myCar.tires << endl;
cout << yourCar.tires << endl;
}
A few things to note about this syntax:
Note how in the struct, I need to provide a function prototype for the member function that I've promised I'll later define.
When I define the member function getFlat outside of the struct, I specify the function name within the struct scope by saying Ford::getFlat
Public & Private Tags
What if we didn't want users of our structs to tamper with its internal data members? We could ask them nicely and be disappointed, or we could force them to obey our will!
The public tag, used in a struct, says "Everything that comes after this (until you say otherwise) is publically accessible and modifiable."
The private tag, used in a struct, says "Everything that comes after this (until you say otherwise) is ONLY accessible to member functions."
Will the following code compile? If so, what will it output?
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Ford {
// Available to anyone!
public:
// Need function prototype
int getFlat();
// Constructor
Ford () {
// +One spare
tires = 5;
model = "Ranger";
fourWheelDrive = false;
}
// Can't touch these!
private:
int tires;
string model;
bool fourWheelDrive;
};
// Member function definition
int Ford::getFlat () {
// this is a keyword for a pointer to the
// calling Ford instance
tires--;
if (tires < 0) {
tires = 0;
}
return tires;
}
int main () {
Ford myCar;
Ford yourCar;
myCar.getFlat();
myCar.getFlat();
yourCar.getFlat();
// ...errrr, are tires private?
cout << myCar.tires << endl;
cout << yourCar.tires << endl;
}
Why do we care about declaring members as private or public? What is the purpose?
So that we can limit what our code's users are able to see / modify! More useful the more stupider our users are.
So how do I give users access to my private members? ...there's gotta be a better way to say that...
Member functions called getters are used to allow users access to viewing private member values.
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Ford {
// Available to anyone!
public:
// Need function prototypes
int getFlat();
int getTires();
// Constructor
Ford () {
// +One spare
tires = 5;
model = "Ranger";
fourWheelDrive = false;
}
// Can't touch these!
private:
int tires;
string model;
bool fourWheelDrive;
};
// Member function definition
int Ford::getFlat () {
// this is a keyword for a pointer to the
// calling Ford instance
tires--;
if (tires < 0) {
tires = 0;
}
return tires;
}
int Ford::getTires () {
return tires;
}
int main () {
Ford myCar;
Ford yourCar;
myCar.getFlat();
myCar.getFlat();
yourCar.getFlat();
// ...now I've provided an interface to see the number
// of tires
cout << myCar.getTires() << endl;
cout << yourCar.getTires() << endl;
}
Classes
I'm making a new section for classes not because they're very different from structs, but because the last section was getting too big...
Classes are exactly like structs except that, instead of having all members default to public access, all members of classes default to private.
Will the following code compile?
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct StructExample {
int x;
double d;
StructExample () {
x = 3;
d = 3.333;
}
void printX () {
cout << x << endl;
}
};
int main () {
StructExample s;
s.printX();
}
Will the following code compile?
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
class ClassExample {
int x;
double d;
ClassExample () {
x = 3;
d = 3.333;
}
void printX () {
cout << x << endl;
}
};
int main () {
ClassExample s;
s.printX();
}
Structs in Memory
Remember when we said that memory addresses are contiguous in the hardware? This is still true! But we didn't say the whole truth...
(you couldn't handle the whole truth then, but now you can)
Memory addresses are segmented into storage locations known as machine words, which we talked about at the beginning of class but as reminder:
A machine word in memory is the architecture-specific "native" data size that the CPU is capable of processing.
So, for example, on a 32-bit processor, a machine word is 4 bytes long, because the processor can handle 32 bits at a time, which we know is = 4 bytes * 8 bits / 1 byte.
Physical memory is therefore separated into whatever word size the current architecture and operating system can support.
Think of a 32-bit machine with 4 byte machine words as having 4 byte "chunks" of memory indicies.
If we had a 64-bit machine with 8 byte machine words, then we might envision the memory laid out as follows:
A couple things to note here:
We still have sequential indecies of memory addresses; that hasn't changed
We still have the same *amount* of memory
BUT, the way different C++ types get stored in memory gets a tiny bit tricky
A word boundary is therefore the end address of a word in memory.
So if a word started in memory at address 1000, then on a 32 bit machine, that word's boundary would be at the end of address 1003.
Why is this important, Andrew? I've already eaten 5 pumpkin pies and the only reason I'm reading this is because I'm too tired to switch tabs.
Glad you asked... my apologies in advance for being a bit handwavy here (the specifics are a bit out of this class' scope), but getting the general idea will help you to understand structs in memory.
A struct's individual members are guaranteed to be sequential in memory, but not necessarily contiguous. That said, we are also guaranteed that other variables (outside of the struct members) will not be stored in between the members.
By sequential, I mean that if member int i; is declared before char c; in a given struct, then we are guaranteed that
&i < &c
That said, if i starts at memory address 1000 and extends to address 1003 on a 64-bit machine, then we are NOT guaranteed that c
is located at address 1004.
In brief, your compiler is free to add padding in memory between members to align things properly.
Take, for example, the following two structs with the same members declared in two different orders. The main function will print different values out for you depending on where the members are put in memory at runtime, but you can still glean the padding that the compiler has added.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct inStructive {
int i;
double d;
char c;
};
int main () {
inStructive s;
cout << static_cast<void *>(&s.i) << endl;
cout << static_cast<void *>(&s.d) << endl;
cout << static_cast<void *>(&s.c) << endl;
}
Your compiler might have done the following allocation of this struct in memory:
Andrew, that's pretty lame how you couldn't fit "char c;" into that box, it looks really asymmetrical.
I will find you and ruin your Thanksgiving leftovers!
Now, if I rearrange the member declarations as such:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct inStructive {
double d;
int i;
char c;
};
int main () {
inStructive s;
cout << static_cast<void *>(&s.d) << endl;
cout << static_cast<void *>(&s.i) << endl;
cout << static_cast<void *>(&s.c) << endl;
}
Then I *might* get some sort of spacing like the following:
See how that works? Here are the take-away messages:
Struct members are guaranteed to be sequential (relatively positioned to each other) in memory
Struct members are not guaranteed to be contiguous (absolutely positioned one after another) in memory
Because of the above, the size of our struct types will depend on what members it has, what types those members are, and in what order they're declared.
Just how these are arranged will be a topic for a future class, worry not!
Struct Pointers
Struct pointers work pretty much exactly as you'd expect.
Pointers to struct instances must have the same type as the object to which they're pointing
The this keyword is a special keyword usable within member functions that provides a pointer to the calling instance.
The dereference and access arrow (->) operator is just like the member selector (.) operator except that the lvalue of (->) is a pointer to an object rather than the object itself.
Our arrow operator to access the members of whatever struct a struct pointer points to:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
string s;
Stuff () {
x = 5;
s = "hi :)";
}
};
int main () {
Stuff ing;
// Pointer of type Stuff equal to the
// location of the first member of ing
Stuff* ptr = &ing;
cout << ptr->x << endl;
cout << ptr->s << endl;
}
[Just for the Curious] Notice the addresses that the pointer points to and the address of the first declared member, x:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
string s;
Stuff () {
x = 5;
s = "hi :)";
}
};
int main () {
Stuff ing;
// Pointer of type Stuff equal to the
// location of the first member of ing
Stuff* ptr = &ing;
cout << ptr << endl;
cout << &ptr->x << endl;
}
What if we had an array as a member of a struct?
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
string s;
int i[3];
Stuff () {
x = 5;
s = "hi :)";
i[0] = 5;
i[1] = 6;
i[2] = 7;
}
};
int main () {
Stuff ing;
// Pointer of type Stuff equal to the
// location of the first member of ing
Stuff* ptr = &ing;
for (int j = 0; j < 3; j++) {
cout << ptr->i[j] << endl;
}
}
Arrays of Structs
Now that we know how structs are arranged in memory, we can talk about sticking them into arrays!
To declare an array of structs, we use the notation we're all used to with other types:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
char c[6];
Stuff () {
x = 3;
strcpy(c, "mine?");
}
};
int main () {
// An array of 5 Stuffs!
// Each element is a newly default-constructed
// Stuff object
Stuff ing[5];
// Ways to access members and elements of
// members, like arrays
cout << ing[0].c << endl;
cout << ing[2].c << endl;
cout << ing[2].c[4] << endl;
}
What we see here is that the constructor is called for EACH of the 5 elements of ing, which is why we get the predictable values of the text in member c.
I can still talk about the array elements with pointers:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
char c[6];
Stuff () {
x = 3;
strcpy(c, "mine?");
}
};
int main () {
Stuff ing[3];
Stuff* ptr = ing;
strcpy((ptr + 1)->c, "woah!");
for (int i = 0; i < 3; i++) {
cout << (ptr + i)->c << endl;
}
}
Will the following code print out the same thing twice? If not, what could you *add* to the first print out to make it print the same thing?
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
char c[6];
Stuff () {
x = 3;
strcpy(c, "mine?");
}
};
int main () {
Stuff ing[3];
Stuff* ptr = ing;
// Will these print out the same thing?
cout << *(ptr + 1)->c << endl;
cout << ing[1].c << endl;
}
We can still call member functions in an array as well:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct Stuff {
int x;
char c[6];
int incX (int i) {
x += i;
return x;
}
Stuff () {
x = 3;
strcpy(c, "mine?");
}
};
int main () {
Stuff ing[3];
ing[2].incX(2);
for (int i = 0; i < 3; i++) {
cout << ing[i].x << endl;
}
}
Functions & Structs
Yada yada we can use structs in functions yada yada...
First things first, as always:
Structs are passed by value in function parameters, meaning that copies of each data member are made.
This can be harmless whenever our structs are small, usually whenever they simply have primitive-type members...
...but when our structs are large, e.g., with huge array members that we want to copy, then this operation can be expensive.
Let's look at a simple example function that returns the average of a type we've defined called SmartIntArray:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct SmartIntArray {
private:
int size;
int arr[100];
int maxIndex;
public:
void set (int i, int val) {
arr[i] = val;
// [!] Do you see a possible issue here?
if (i > maxIndex) {
size = i + 1;
maxIndex = i;
}
}
int get (int i) {
return arr[i];
}
int length () {
return size;
}
SmartIntArray () {
maxIndex = 0;
size = 0;
}
};
// Computes the average of the entities in a
// SmartIntArray
double average (SmartIntArray sInt) {
double result = 0;
for (int i = 0; i < sInt.length(); i++) {
result += sInt.get(i);
}
return (double) result / sInt.length();
}
int main () {
SmartIntArray sInt;
for (int j = 0; j < 5; j++) {
sInt.set(j, j * 5);
}
cout << average(sInt) << endl;
}
Of course, we can still pass by reference whenever we want to modify the struct:
Will the following code compile? If so, what will it print out?
// ...
// SmartIntArray unmodified here
void addToEach (SmartIntArray sInt, int toAdd) {
for (int i = 0; i < sInt.length(); i++) {
sInt.set(i, sInt.get(i) + toAdd);
}
}
int main () {
SmartIntArray sInt;
for (int j = 0; j < 5; j++) {
sInt.set(j, j * 5);
}
addToEach(sInt, 5);
sInt.toCout();
}
Will the following code compile? If so, what will it print out?
// ...
// SmartIntArray unmodified here
void addToEach (SmartIntArray& sInt, int toAdd) {
for (int i = 0; i < sInt.length(); i++) {
sInt.set(i, sInt.get(i) + toAdd);
}
}
int main () {
SmartIntArray sInt;
for (int j = 0; j < 5; j++) {
sInt.set(j, j * 5);
}
addToEach(sInt, 5);
sInt.toCout();
}
As per usual, we can also set struct parameters to be const, meaning that we expect that the struct (and any of its members) will not be modified.
That said, there's something of a peculiarity when it comes to calling non-const member functions from a const instance.
Will the following code compile? If so, what will it output?
// ...
// SmartIntArray unmodified here
// Notice the const SmartIntArray parameter
int total (const SmartIntArray sInt) {
int result = 0;
for (int j = 0; j < sInt.length(); j++) {
result += sInt.get(j);
}
return result;
}
int main () {
SmartIntArray sInt;
for (int j = 0; j < 5; j++) {
sInt.set(j, j * 5);
}
cout << total(sInt) << endl;
}
Well that's weird... Why didn't that work? Nothing I did modified SmartIntArray...
Well, because we call member functions .length() and .get(...), the compiler doesn't know that these seamingly innocuous functions won't change the parameter sInt.
So, we have to tell our compiler that the member functions won't modify the calling instance.
To declare a member function that will not modify any members the calling instance, we use the keyword const after the member function's parameter list:
Here's how we would fix our code above by declaring our member functions constant:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct SmartIntArray {
private:
int size;
int arr[100];
int maxIndex;
public:
void set (int i, int val) {
arr[i] = val;
if (i > maxIndex) {
size = i + 1;
maxIndex = i;
}
}
// [!] const keyword added
void toCout () const {
for (int i = 0; i < size; i++) {
cout << arr[i] << endl;
}
}
// [!] const keyword added
int get (int i) const {
return arr[i];
}
// [!] const keyword added
int length () const {
return size;
}
SmartIntArray () {
maxIndex = 0;
size = 0;
}
};
// Notice the const SmartIntArray parameter
int total (const SmartIntArray sInt) {
int result = 0;
for (int j = 0; j < sInt.length(); j++) {
result += sInt.get(j);
}
return result;
}
int main () {
SmartIntArray sInt;
for (int j = 0; j < 5; j++) {
sInt.set(j, j * 5);
}
cout << total(sInt) << endl;
}
See how we use the const keyword after the parameters in our member function definitions? This saves us a lot of headache later...
The rule of thumb is: always think about what member functions could *possibly* modify the calling instance, and if they *never* will, tag them with the const keyword.
We can also return structs, which is safe as long as we're returning by value:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct SmartIntArray {
private:
int size;
int arr[100];
int maxIndex;
public:
void set (int i, int val) {
arr[i] = val;
// Do you see a possible issue here?
if (i > maxIndex) {
size = i + 1;
maxIndex = i;
}
}
void toCout () const {
for (int i = 0; i < size; i++) {
cout << arr[i] << endl;
}
}
int get (int i) const {
return arr[i];
}
int length () const {
return size;
}
SmartIntArray () {
maxIndex = 0;
size = 0;
}
};
// Converts the first count elements of i into a SmartIntArray
SmartIntArray intsToSIA (int i[], int count) {
SmartIntArray sInt;
if (count > 100) {
count = 100;
}
for (int j = 0; j < count; j++) {
sInt.set(j, i[j]);
}
return sInt;
}
int main () {
int i[] = {5, 6, 7};
SmartIntArray sInt = intsToSIA(i, 3);
sInt.toCout();
}
But wait... I thought local variables got deallocated as soon as we returned from a function? Won't this be undefined behavior?
Nope! Although the local variable sInt in intsToSIA gets deallocated upon return, what *gets* returned is a copy, so we're safe. Good question, Andrew. Thanks, Andrew.
Lastly, we can pass pointers to structs as function parameters, remembering to use the arrow operator to access members of the pointer's dereference:
// ...
// SmartIntArray unmodified here
void normBySize (SmartIntArray* sIPtr) {
for (int j = 0; j < sIPtr->length(); j++) {
sIPtr->set(j, sIPtr->get(j) / sIPtr->length());
}
}
int main () {
SmartIntArray sInt;
for (int j = 0; j < 5; j++) {
sInt.set(j, j * 5);
}
SmartIntArray* sIPtr = &sInt;
normBySize(sIPtr);
sInt.toCout();
}
Miscellaneous Exercises
The following assortment of exercises will test your knowledge of structs to the deepest levels imaginable. Good luck.
What will the following code output? (I eagerly await your angst ridden emails heh)
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
struct xzibit {
string yo,
dawg;
struct inAStruct {
string yo,
dawg;
inAStruct () {
yo = "stringz";
dawg = "inside";
}
} heardYouLiked;
xzibit () {
yo = heardYouLiked.yo;
dawg = "stringsss";
}
};
int main () {
xzibit x;
cout << x.yo << endl;
cout << x.heardYouLiked.dawg << endl;
cout << x.heardYouLiked.yo << endl;
}
Will the following code compile? If so, what will it output?
#include <iostream>
#include <cstring>
#include <cctype>
#include <string>
using namespace std;
struct trickz {
char c[5];
trickz () {
for (int j = 0; j < 4; j++) {
// Assume ASCII encoding
c[j] = 'a' + j;
}
c[4] = '\0';
}
};
void trickzInc (const trickz* t, int count) {
for (int i = 0; i < count; i++) {
toupper(t->c[i]);
}
}
int main () {
trickz t;
trickz* ptr = &t;
cout << t.c << endl;
trickzInc(ptr, 5);
cout << t.c << endl;
}
What will the following code output?
#include <iostream>
#include <cstring>
#include <cctype>
#include <string>
using namespace std;
struct trickz {
int i[5];
trickz () {
for (int j = 0; j < 5; j++) {
// Assume ASCII encoding
i[j] = j;
}
}
};
void trickzInc (trickz*& t, int count) {
for (int j = 0; j < count; j++) {
t->i[j]++;
}
}
int main () {
trickz t;
trickz* ptr;
trickzInc(ptr, 5);
for (int j = 0; j < 5; j++) {
cout << t.i[j] << endl;
}
// True or false?
cout << (ptr == &t) << endl;
}