There are many different types of variable storage classes and memory usages in C and C++. Here is an overview, along with basic usage of gdb for debugging our programs.
Using gdb for debugging
See the posted tutorials and cheat sheet. Here are some basics:
- Compile using
-g
to add debug info:gcc -g -o program_name my_c_code.c
- Running:
gdb program_name
- You are now in GDB with prompt
(gdb)
; typebreak main:1
to set a breakpoint at line 1 ofmain()
- Type
run
to run the program - Now, typing
next
(or justn
) will run through a line of code if you set a breakpoint, skipping over function calls - Similarly, typing
step
(or justs
) will execute statement by statement, including into function calls - Also, if you type just a return/enter key, gdb will repeat the previous command, letting you step through statements quickly
- Typing
print i+1
will print value ofint
variablei
, plus one
Storage classes/variable types
Recall that lifetime and scope of a variable are not always the same. Lifetime is how long the variable stays alive (persists in memory) at runtime. Scope is what parts of code can see the definition and access the variable.
Different types of storage classes:
- Local variables: local to a block or function - scope and lifetime are only during execution of that block
- Global (external) variables: at the top of the program, scope and lifetime are throughout the program file
static
variables essentially have local scope but global lifetime - more below
Static variables
The static
qualifier can be used with any type of variable declaration, e.g.
static int intarray[10];
- It is a storage class -- how the data is stored
- Its like a
private static
field in Java -
intarray
location exists for duration of program
-- but,intarray
can only be accessed where it is in scope: - Contents of variable persist in memory even when not in local use
- Static variables are automatically initialized to 0 by compiler (not reinitialized each time function w/var declared in it starts)
The program below provides examples of several storage types, and also what happens when a local variable and a global variable have the same name.
#include <stdio.h>
// a global variable
int v = 100;
// void f();
void f1(void);
void f2(int);
int main(void) {
// f(3, 5); compiles if the forward declaration were f()
f1();
f2(10);
printf("global v hasn't changed\n");
printf(" val: %d\n", v); // we can access the global here
printf(" loc: %p\n", (void*)&v); // where global v lives
printf("size: %lu\n", sizeof(v)); // v has a size (in bytes)
printf("\n");
return 0;
}
void f2(int a) {
printf("a: %d\n", a);
f1();
}
void f1(void) {
static int i; // only created & initialized once, first time function is called
printf("static i: %d\n", ++i); // static variable has longer life
printf("access global v\n");
printf(" val: %d\n", v); // we can access the global here
printf(" loc: %p\n", (void*)&v); // where global v lives
printf("size: %lu\n", sizeof(v)); // v has a size (in bytes)
printf("\n");
// declare a variable in a different scope but with the same name
double v = 45.0;
printf("local v 'shadows' global v\n");
printf(" val: %f\n", v); // local v "shadows" global v
printf(" loc: %p\n", (void*)&v); // local v has its own address
printf("size: %lu\n", sizeof(v)); // and size
printf("\n");
}
const
Indicates data is const
ant, the value cannot change after initialization.
- Added to ANSI C (not originally part of C)
- Important to use to mark immutable data
-
const
type qualifier can be applied to any variable declaration, e.g.const int i
- Question "Should this variable ever be modified" answers No? add
const
to its declaration - Generally must be initialized when declared (with
=
, or its a function parameter)
const
can be used at different points in more complex types, with different meanings
- To make a
const
(non-modifiable) pointer: "int * const iptr = &i"
- Local array variable declarations act like
const
pointers; the memory addresses of the array storage cannot be changed - To make a (mutable) pointer to
const
(non-modifiable) data: "const int * iptr"
- Lastly,
const
ptr toconst
data:const int * const iptr
- Read declarations from right to left (inside out) to get it straight
Memory segments
During execution our program variables are stored in different sections of memory, depending on their declaration type.- The stack holds local function variables -- called automatic memory in C. These are freed upon function return - don't try to return an array declared in a function.
auto int x;
in a function is same asint x;
- default isauto
. - The data segment holds global variables (declared outside any function) and static variables. This consists of the heap and registers.
- The heap holds variables that are dynamically allocated at runtimewith an unbounded lifetime. The programmer explicitly allocates and deallocates this memory - see Notes: Pointers and Dynamic Memory Allocation.
- Registers are specific positions in memory. The programmer can declare
register int x;
to suggestx
be stored in a register.