230 likes | 237 Views
Learn about const pointers, pointer casting, activation records, stack layout, recursive functions, and the scope and lifetime of variables in C.
E N D
C – Scope, Lifetime,and the Stack CS/COE 0449 Jarrett Billingsley
Class announcements • lab 3 is out? • project 1 is out? CS449
More pointer stuff CS449
const pointers • for any type T, a constT*is a read-only pointer to a T • you can read the data that it points to, but you can't write it • you can however change where the pointer points to const char* s = "hello"; s = "goodbye"; // fine! s[3] = 'x'; // COMPILER error! • const pointers are used when you want a pointer, but you want to promise that you won't change the thing that it points to. • e.g. strlen() takes a const char* - it reads from the string but will not modify it. • see 6_const_ptrs.c CS449 (2184)
Pointer casting • casts convert from one type to another, like so: (type)value inta = 20, b = 25; double x = a / (double)b; // now it's 0.8 • you can cast pointers too float f = 3.567; int* p = (int*)&f; // p points to f... printf("%08x\n", *p); // interprets f as an int! • the computer does not care what bits represent • this kind of cast does not change anything in memory • f is still there and it still holds 3.567 • it only changes how we view that memory • see 6_ptr_casts.c (and the visualization linked below it) CS449 (2184)
The Stack!!! CS449
The flow of control • when the caller calls a function, where do we go? • when the callee's code is finished, where do we go? void knife() { spork++; spatula--; } void fork() { knife(); spoon++; } callee caller CS449
What's the stack? • it's an area of memory provided to your program by the OS • when your program starts, it's already there • the stack holds information about function calls. • it's not a strict stack • you can read and write any part of it • but it grows and shrinks like a stack • and we use "push" and "pop" to describe that • each program* gets one stack • cause only one function is running at a time Memory Stack CS449
Activation records (ARs) • when a function is called, a bunch of data is pushed onto the stack • this is the call's activation record(or "stack frame") • it contains local variables (including arguments) and the return address Stack int main() { int x, y; charbuf[5]; return0; } main's AR CS449
The low-level layout • each variable (including array variables) gets enough bytes in the AR to hold its value • where the variable is located is up to the compiler when I compiled this on thoth, this is the arrangement I got: sizeof(int) == 4, so x gets 4 bytes sizeof(arr) == 3, so it gets 3 bytes sizezof(short) == 2, so.. yeah but what's all that grey space? idk lol, compiler does what it wants YOU DON'T NEED TO KNOW THE LOW-LEVEL LAYOUT! int x; char arr[3]; short y; CS449
Call = push, return = pop (animated) • the stack grows when we call a function and shrinks when it exits main int main() { int x; fork(&x); return0; } void fork(int* ptr) { *ptr = knife(); } int knife() { return 10; } fork knife CS449
Recursive functions (animated) • recursive functions work by using the call stack as an implicit stack data structure fact(5) int fact(int x) { if(x <= 2) { return x; } else { return x*fact(x–1); } } fact(4) fact(3) fact(2) CS449
But they don't really go away. (animated) • the stack is used constantly • so it needs to be really fast • so we implement it as a pointer • the stack pointer (sp) sp push AR:sp -= (size of AR) pop AR: sp += (size of AR) but the AR's memory is still there. so if we call another function… this is where that garbage in uninitialized variables comes from! CS449
Don't return stack arrays. • I think I showed this before "function returns address of local variable" • when func() returns, what happened to its variables? • you have no idea • you now have an invalid pointer • it points to who-knows-what • it might crash • it might expose secrets • who knows!! int main() { char* str = func(); printf("%s\n", str); return0; } char* func() { char str[10] = "hi there"; char* dummy = str; return dummy; } CS449
Scope and Lifetime CS449
Scope • scope is "where a name can be seen" • C has three levels of scope globals can be seen by any function in any file static globals can be seen by any function in one file locals can be seen by one function int main() { int x; } one.c two.c CS449
Global variables are terrible • and you should almost never use them. • almost any problem where you think you need one can be instead solved by using a local and passing by reference. • there are legitimate uses for them, but… • unless you are being forced to use them… • avoid them. CS449
Homestead (animated) • every variable takes up space in memory • memory is limited, and the "land" must be "bought and sold." memory must be allocated: reserved for a variable int x int* p float f and when no longer needed, deallocated: released for other use the language handles this process for you, for local and global variables. CS449
Lifetime • lifetime is a little more subtle than scope... • it's the time betweenallocation and deallocation. • it's how long a value is "available" or "valid." • global variables last from program start to program exit • local variables' lifetime starts at their declaration, and ends at the closing brace that encloses them • though the compiler kinda optimizes this and just does one allocation at function start and one at function return CS449
You're watching the Lifetime Channel voidfunc() { int f = 10; } int glob = 0x910B; int main() { int m = 10; func(); return0; } lifetime of glob lifetime of m lifetime of f time CS449
Ownership • ownership answers the question: who is responsible for deallocating a piece of memory? • or: how do we know when it's okay to deallocate memory? • different languages deal with this in different ways. • Java uses garbage collection to do a lot of this. • C mostly sticks its fingers in its ears, goes "LA LA LA," and pretends the problem doesn't exist. • locals and globals are easy: • locals are owned by functions • so their memory is deallocated by the function that made them. • globals are owned by the program • so their memory is deallocated when the program ends. • but… CS449
If only it were that simple public static voidmain(String[] args) { String s = func(); s = null; } String func() { String t = new String("hello"); return t; } • in this Java code: • what is the scope of each variable? • what is the object's lifetime? • the allocation happens at new. • but… where is it deallocated? • when? • by who? • important: the variables s and t and the object they point to have separate lifetimes. CS449
Looking at this problem a different way • what is happening here is a conflict between ownership and lifetime. • the programmer wants the variable to live longer than the ownership will allow it. • but in C, there's no way to "transfer" the ownership. • Java sidesteps this problem: objects can have one or more owners, but if no one owns it, it is deallocated. • that's GC, and next class! int main() { char* str = func(); printf("%s\n", str); return0; } char* func() { char str[10] = "hi there"; char* dummy = str; return dummy; } CS449