180 likes | 294 Vues
CS 31 Discussion, Week 8. Faisal Alquaddoomi, faisal@cs.ucla.edu Office Hours: BH 2432, W 4:30-6:30pm, F 12:00-1:00pm. Addresses and Operations Review. All variables have an address in memory (as well as an amount of space they consume dictated by their type)
E N D
CS 31 Discussion, Week 8 Faisal Alquaddoomi, faisal@cs.ucla.edu Office Hours: BH 2432, W 4:30-6:30pm,F 12:00-1:00pm
Addresses and Operations Review • All variables have an address in memory (as well as an amount of space they consume dictated by their type) • The addressof a variable can be retrieved via the ‘&’ operator • The value at an address can be retrieved/changed using the ‘*’ operator on an address
Addresses and Pointers Review, Part 2 • A pointer is a special type of variable used for holding addresses • Pointers can be manipulated using +, -, which moves them in ‘steps’ of their type’s size, e.g.:int* p; p = p + 3;// moves p (3*4) = 12 bytes forward in memory • Arrays and pointers are largely interchangeable (explained with examples)
Tasks with Pointers • Iterating through the elements of an array (pointers, ex. 1) • Similar to using an index variable in a ‘for’ loop, except the pointer acts as the index • Passing arrays as pointers to functions (pointers, ex. 2) • Pointer arithmetic can be used to manipulate the array that ends up being passed (e.g. remove elements from the front) • Pointer arithmetic is especially useful with c-strings • Passing pointers (const vs. non-const) to functions, returning pointers from functions (pointers, ex. 3) • Pointer arithmetic tricks (reading arrays backwards, etc.) (pointers, ex.4)
Pointer Pitfalls • Dereference has the highest priority (excepting parentheses) (pointers, ex. 5)*p + 1 = 30;// incorrect; *p occurs first, then +1 makes it a value*(p + 1) = 30;// correct; *(p+1) is a place to which 30 can be stored • When using pointers to simulate pass-by-reference, you can only change the thing pointed to, not the pointer itself (it’s a local variable)(pointers, ex. 6) • Can get around this in a somewhat tricky way (without changing calling semantics) by using pass-by-reference
Pointer Pitfalls, Part 2 • Uninitialized pointers point at random memory (a bad thing) (pointers, ex. 7)double* p; // this points at random data • Keep in mind when you’re dealing with a pointer versus the thing to which it’s pointing (pointers, ex. 8) • Local variables are destroyed when the function ends; pointers to them are thereafter invalid (pointers, ex. 9) • Illustrates the principle of allocating at the same level of destruction
Dealing with “Structured Data” • Occasionally, it’s useful to be able to deal with a collection of different bits of data as a group • So far, variables have been useful for storing individual values • Arrays are useful for storing many values, but can only store the same type of value • Arrays also have to either end in a nul-terminator, or they have to pass their length around with them • What if we want to refer to a small number of different types of values at the same time?
Example: Class Roster • Each person in a class has a name, a class level, and a total grade in the class • name: string, class level: int (0=freshman, 1=sophomore, etc.), grade: double (0.0 to 100.0) • We don’t want to have to deal with each of these values as individual variables, as the class could be large… • Arrays might work, but we’d need one per type of thing we’re storing, and we’d need to keep track of the indices for all of them…
Solution: Structures (“Structs”) • A struct is a collection of named variables inside of a larger “compound type” • Example:structPerson { string name;intclass_level; double grade;}; // <- note the semicolon!
Structures Cont’d • Defining a struct creates a new type that can be used like any other type (int, double, etc.) • The individual variables in a struct are called fields • Fields of the struct can be referenced using the fieldaccess operator . (dot) • Example of using our Person struct (structs, ex. 4):Person p; p.name = “Faisal”;p.class_level = 5;p.grade = 75.3; • ‘p’ is referred to as an instance of the struct Person
Arrays of Structs • Our original goal was to create a lot of these collections of structured data • Like any other type, we can declare arrays of structs(structs, ex. 5):Person class[50]; // 50 instances class[0].name = “Alice”; class[1].name = “Bob”; // etc. • All the standard array rules apply • don’t shoot past the end or the beginning, pass the length of it when you pass it to a function, etc.
Passing Structs Around • As you might guess, structs can get very large • Structs, like any other type (save arrays, but that’s because they’re actually pointers), are passed by value when passed to a function • This means that they have to be copied as a local variable in the function, then destroyed at the end • This is pretty inefficient, both in terms of space and in terms of time wasted copying data
Pointers to Structs • When you create a new struct, you also create the corresponding pointer type for that struct • Person* can now be used to point to an instance of struct Person, e.g. (structs, ex. 6)Person p; Person* pointer_to_p = &p; (*p).name = “Casper”; • Now that we have struct pointers, we can have our functions take Person* instead of Person • Doesn’t need to copy the whole struct, since the passed pointer points to the original (instead of making a fresh new local copy)
Pointers to Structs and the Dot vs. Arrow Operator • Clearly, typing (*p).someField every time we want to access a field in a pointer is tedious • There’s a common shortcut, the deference-and-access operator, ‘->’ (arrow) • p->name is exactly the same thing as (*p).name • of course, ‘p’ must be a pointer to the struct or you’ll get a compiler error • We’ll discuss these different types of access in (structs, ex. 7)
Pointers to Structs and Functions • Passing a pointer to a struct works the same way as passing a pointer to any other type • Passing an array of structs works the same as passing an array of any other type, too • Like arrays and pointers, passing a pointer to a struct means your original might get modified • const is useful here; it guarantees the caller that your function can’t modify the struct it’s passed • Comparisons of passing by value, by reference, via a pointer, and via a const pointer are in (structs, ex. 8)
Structs Review • Structs are useful for holding collections of named variables • Differ from arrays in that the types can be different, and each ‘slot’ has a name rather than a number • Use the struct <name> { <vars> }; syntax to create a new type, e.g.structMyStruct { int p; }; • Create instances using the new type, e.g. MyStruct thing; • Use the field access operator ‘.’ to access a variable in a struct, e.g.thing.p = 150;
Structs Review, Part 2 • Pointers to structs can be declared, e.g.MyStruct *ptr = &thing; • Field accesses on a pointers can be accomplished either through (*ptr).p = 300; // deference-and-dot, or… ptr->p = 300; // arrow, works same as above • Both change the original object, ‘thing’
Structs Review, Part 3 • Structs can be passed to functions • the default is pass-by-value, which copies the entire struct, and can be inefficient • Struct pointers can be passed instead • can be marked const to prevent modification to the original object (const == “read-only”) • As with all other types, structs can be passed-by-reference using the ‘&’ type, e.g.void someFunc(MyStruct& thing) { /* thing is a reference; changing it changes the original param */ }