Variable Scoping
Another interesting concept regarding memory in C is variable scoping or
context—in particular, the contexts of variables within functions. Each function
has its own set of local variables, which are independent of everything
else. In fact, multiple calls to the same function all have their own contexts.
You can use the printf() function with format strings to quickly explore this;
check it out in scope.c.
scope.c
#include <stdio.h>
void func3() {
int i = 11;
printf("\t\t\t[in func3] i = %d\n", i);
}
void func2() {
int i = 7;
printf("\t\t[in func2] i = %d\n", i);
func3();
printf("\t\t[back in func2] i = %d\n", i);
}
void func1() {
int i = 5;
printf("\t[in func1] i = %d\n", i);
func2();
printf("\t[back in func1] i = %d\n", i);
}
int main() {
int i = 3;
printf("[in main] i = %d\n", i);
func1();
printf("[back in main] i = %d\n", i);
}
The output of this simple program demonstrates nested function calls.
reader@hacking:~/booksrc $ gcc scope.c
reader@hacking:~/booksrc $ ./a.out
[in main] i = 3
[in func1] i = 5
[in func2] i = 7
[in func3] i = 11
[back in func2] i = 7
[back in func1] i = 5
[back in main] i = 3
reader@hacking:~/booksrc $
P rogramming 63
In each function, the variable i is set to a different value and printed.
Notice that within the main() function, the variable i is 3, even after calling
func1() where the variable i is 5. Similarly, within func1() the variable i
remains 5, even after calling func2() where i is 7, and so forth. The best
way to think of this is that each function call has its own version of the
variable i.
Variables can also have a global scope, which means they will persist
across all functions. Variables are global if they are defined at the beginning
of the code, outside of any functions. In the scope2.c example code shown
below, the variable j is declared globally and set to 42. This variable can be
read from and written to by any function, and the changes to it will persist
between functions.
scope2.c
#include <stdio.h>
int j = 42; // j is a global variable.
void func3() {
int i = 11, j = 999; // Here, j is a local variable of func3().
printf("\t\t\t[in func3] i = %d, j = %d\n", i, j);
}
void func2() {
int i = 7;
printf("\t\t[in func2] i = %d, j = %d\n", i, j);
printf("\t\t[in func2] setting j = 1337\n");
j = 1337; // Writing to j
func3();
printf("\t\t[back in func2] i = %d, j = %d\n", i, j);
}
void func1() {
int i = 5;
printf("\t[in func1] i = %d, j = %d\n", i, j);
func2();
printf("\t[back in func1] i = %d, j = %d\n", i, j);
}
int main() {
int i = 3;
printf("[in main] i = %d, j = %d\n", i, j);
func1();
printf("[back in main] i = %d, j = %d\n", i, j);
}
The results of compiling and executing scope2.c are as follows.
reader@hacking:~/booksrc $ gcc scope2.c
reader@hacking:~/booksrc $ ./a.out
[in main] i = 3, j = 42
64 0x200
[in func1] i = 5, j = 42
[in func2] i = 7, j = 42
[in func2] setting j = 1337
[in func3] i = 11, j = 999
[back in func2] i = 7, j = 1337
[back in func1] i = 5, j = 1337
[back in main] i = 3, j = 1337
reader@hacking:~/booksrc $
In the output, the global variable j is written to in func2(), and the
change persists in all functions except func3(), which has its own local
variable called j. In this case, the compiler prefers to use the local variable.
With all these variables using the same names, it can be a little confusing, but
remember that in the end, it’s all just memory. The global variable j is just
stored in memory, and every function is able to access that memory. The local
variables for each function are each stored in their own places in memory,
regardless of the identical names. Printing the memory addresses of these
variables will give a clearer picture of what's going on. In the scope3.c example
code below, the variable addresses are printed using the unary address-of
operator.
scope3.c
#include <stdio.h>
int j = 42; // j is a global variable.
void func3() {
int i = 11, j = 999; // Here, j is a local variable of func3().
printf("\t\t\t[in func3] i @ 0x%08x = %d\n", &i, i);
printf("\t\t\t[in func3] j @ 0x%08x = %d\n", &j, j);
}
void func2() {
int i = 7;
printf("\t\t[in func2] i @ 0x%08x = %d\n", &i, i);
printf("\t\t[in func2] j @ 0x%08x = %d\n", &j, j);
printf("\t\t[in func2] setting j = 1337\n");
j = 1337; // Writing to j
func3();
printf("\t\t[back in func2] i @ 0x%08x = %d\n", &i, i);
printf("\t\t[back in func2] j @ 0x%08x = %d\n", &j, j);
}
void func1() {
int i = 5;
printf("\t[in func1] i @ 0x%08x = %d\n", &i, i);
printf("\t[in func1] j @ 0x%08x = %d\n", &j, j);
func2();
printf("\t[back in func1] i @ 0x%08x = %d\n", &i, i);
printf("\t[back in func1] j @ 0x%08x = %d\n", &j, j);
}
P rogramming 65
int main() {
int i = 3;
printf("[in main] i @ 0x%08x = %d\n", &i, i);
printf("[in main] j @ 0x%08x = %d\n", &j, j);
func1();
printf("[back in main] i @ 0x%08x = %d\n", &i, i);
printf("[back in main] j @ 0x%08x = %d\n", &j, j);
}
The results of compiling and executing scope3.c are as follows.
reader@hacking:~/booksrc $ gcc scope3.c
reader@hacking:~/booksrc $ ./a.out
[in main] i @ 0xbffff834 = 3
[in main] j @ 0x08049988 = 42
[in func1] i @ 0xbffff814 = 5
[in func1] j @ 0x08049988 = 42
[in func2] i @ 0xbffff7f4 = 7
[in func2] j @ 0x08049988 = 42
[in func2] setting j = 1337
[in func3] i @ 0xbffff7d4 = 11
[in func3] j @ 0xbffff7d0 = 999
[back in func2] i @ 0xbffff7f4 = 7
[back in func2] j @ 0x08049988 = 1337
[back in func1] i @ 0xbffff814 = 5
[back in func1] j @ 0x08049988 = 1337
[back in main] i @ 0xbffff834 = 3
[back in main] j @ 0x08049988 = 1337
reader@hacking:~/booksrc $
In this output, it is obvious that the variable j used by func3() is different
than the j used by the other functions. The j used by func3() is located at
0xbffff7d0, while the j used by the other functions is located at 0x08049988.
Also, notice that the variable i is actually a different memory address for each
function.
In the following output, GDB is used to stop execution at a breakpoint in
func3(). Then the backtrace command shows the record of each function call
on the stack.
reader@hacking:~/booksrc $ gcc -g scope3.c
reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) list 1
1 #include <stdio.h>
2
3 int j = 42; // j is a global variable.
4
5 void func3() {
6 int i = 11, j = 999; // Here, j is a local variable of func3().
7 printf("\t\t\t[in func3] i @ 0x%08x = %d\n", &i, i);
8 printf("\t\t\t[in func3] j @ 0x%08x = %d\n", &j, j);
9 }
66 0x200
10
(gdb) break 7
Breakpoint 1 at 0x8048388: file scope3.c, line 7.
(gdb) run
Starting program: /home/reader/booksrc/a.out
[in main] i @ 0xbffff804 = 3
[in main] j @ 0x08049988 = 42
[in func1] i @ 0xbffff7e4 = 5
[in func1] j @ 0x08049988 = 42
[in func2] i @ 0xbffff7c4 = 7
[in func2] j @ 0x08049988 = 42
[in func2] setting j = 1337
Breakpoint 1, func3 () at scope3.c:7
7 printf("\t\t\t[in func3] i @ 0x%08x = %d\n", &i, i);
(gdb) bt
#0 func3 () at scope3.c:7
#1 0x0804841d in func2 () at scope3.c:17
#2 0x0804849f in func1 () at scope3.c:26
#3 0x0804852b in main () at scope3.c:35
(gdb)
The backtrace also shows the nested function calls by looking at records
kept on the stack. Each time a function is called, a record called a stack frame
is put on the stack. Each line in the backtrace corresponds to a stack frame.
Each stack frame also contains the local variables for that context. The local
variables contained in each stack frame can be shown in GDB by adding the
word full to the backtrace command.
(gdb) bt full
#0 func3 () at scope3.c:7
i = 11
j = 999
#1 0x0804841d in func2 () at scope3.c:17
i = 7
#2 0x0804849f in func1 () at scope3.c:26
i = 5
#3 0x0804852b in main () at scope3.c:35
i = 3
(gdb)
The full backtrace clearly shows that the local variable j only exists in
func3()’s context. The global version of the variable j is used in the other
function’s contexts.
In addition to globals, variables can also be defined as static variables by
prepending the keyword static to the variable definition. Similar to global
variables, a static variable remains intact between function calls; however, static
variables are also akin to local variables since they remain local within a particular
function context. One different and unique feature of static variables
is that they are only initialized once. The code in static.c will help explain
these concepts.
P rogramming 67
static.c
#include <stdio.h>
void function() { // An example function, with its own context
int var = 5;
static int static_var = 5; // Static variable initialization
printf("\t[in function] var = %d\n", var);
printf("\t[in function] static_var = %d\n", static_var);
var++; // Add one to var.
static_var++; // Add one to static_var.
}
int main() { // The main function, with its own context
int i;
static int static_var = 1337; // Another static, in a different context
for(i=0; i < 5; i++) { // Loop 5 times.
printf("[in main] static_var = %d\n", static_var);
function(); // Call the function.
}
}
The aptly named static_var is defined as a static variable in two places:
within the context of main() and within the context of function(). Since static
variables are local within a particular functional context, these variables can
have the same name, but they actually represent two different locations in
memory. The function simply prints the values of the two variables in its context
and then adds 1 to both of them. Compiling and executing this code will
show the difference between the static and nonstatic variables.
reader@hacking:~/booksrc $ gcc static.c
reader@hacking:~/booksrc $ ./a.out
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 5
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 6
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 7
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 8
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 9
reader@hacking:~/booksrc $
68 0x200
Notice that the static_var retains its value between subsequent calls to
function(). This is because static variables retain their values, but also because
they are only initialized once. In addition, since the static variables are local
to a particular functional context, the static_var in the context of main()
retains its value of 1337 the entire time.
Once again, printing the addresses of these variables by dereferencing
them with the unary address operator will provide greater viability into what’s
really going on. Take a look at static2.c for an example.
static2.c
#include <stdio.h>
void function() { // An example function, with its own context
int var = 5;
static int static_var = 5; // Static variable initialization
printf("\t[in function] var @ %p = %d\n", &var, var);
printf("\t[in function] static_var @ %p = %d\n", &static_var, static_var);
var++; // Add 1 to var.
static_var++; // Add 1 to static_var.
}
int main() { // The main function, with its own context
int i;
static int static_var = 1337; // Another static, in a different context
for(i=0; i < 5; i++) { // loop 5 times
printf("[in main] static_var @ %p = %d\n", &static_var, static_var);
function(); // Call the function.
}
}
The results of compiling and executing static2.c are as follows.
reader@hacking:~/booksrc $ gcc static2.c
reader@hacking:~/booksrc $ ./a.out
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 5
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 6
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 7
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 8
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 9
reader@hacking:~/booksrc $
P rogramming 69
With the addresses of the variables displayed, it is apparent that the
static_var in main() is different than the one found in function(), since they are
located at different memory addresses (0x804968c and 0x8049688, respectively).
You may have noticed that the addresses of the local variables all have very
high addresses, like 0xbffff814, while the global and static variables all have
very low memory addresses, like 0x0804968c and 0x8049688. That’s very astute
of you—noticing details like this and asking why is one of the cornerstones of
hacking. Read on for your answers.
Another interesting concept regarding memory in C is variable scoping or
context—in particular, the contexts of variables within functions. Each function
has its own set of local variables, which are independent of everything
else. In fact, multiple calls to the same function all have their own contexts.
You can use the printf() function with format strings to quickly explore this;
check it out in scope.c.
scope.c
#include <stdio.h>
void func3() {
int i = 11;
printf("\t\t\t[in func3] i = %d\n", i);
}
void func2() {
int i = 7;
printf("\t\t[in func2] i = %d\n", i);
func3();
printf("\t\t[back in func2] i = %d\n", i);
}
void func1() {
int i = 5;
printf("\t[in func1] i = %d\n", i);
func2();
printf("\t[back in func1] i = %d\n", i);
}
int main() {
int i = 3;
printf("[in main] i = %d\n", i);
func1();
printf("[back in main] i = %d\n", i);
}
The output of this simple program demonstrates nested function calls.
reader@hacking:~/booksrc $ gcc scope.c
reader@hacking:~/booksrc $ ./a.out
[in main] i = 3
[in func1] i = 5
[in func2] i = 7
[in func3] i = 11
[back in func2] i = 7
[back in func1] i = 5
[back in main] i = 3
reader@hacking:~/booksrc $
P rogramming 63
In each function, the variable i is set to a different value and printed.
Notice that within the main() function, the variable i is 3, even after calling
func1() where the variable i is 5. Similarly, within func1() the variable i
remains 5, even after calling func2() where i is 7, and so forth. The best
way to think of this is that each function call has its own version of the
variable i.
Variables can also have a global scope, which means they will persist
across all functions. Variables are global if they are defined at the beginning
of the code, outside of any functions. In the scope2.c example code shown
below, the variable j is declared globally and set to 42. This variable can be
read from and written to by any function, and the changes to it will persist
between functions.
scope2.c
#include <stdio.h>
int j = 42; // j is a global variable.
void func3() {
int i = 11, j = 999; // Here, j is a local variable of func3().
printf("\t\t\t[in func3] i = %d, j = %d\n", i, j);
}
void func2() {
int i = 7;
printf("\t\t[in func2] i = %d, j = %d\n", i, j);
printf("\t\t[in func2] setting j = 1337\n");
j = 1337; // Writing to j
func3();
printf("\t\t[back in func2] i = %d, j = %d\n", i, j);
}
void func1() {
int i = 5;
printf("\t[in func1] i = %d, j = %d\n", i, j);
func2();
printf("\t[back in func1] i = %d, j = %d\n", i, j);
}
int main() {
int i = 3;
printf("[in main] i = %d, j = %d\n", i, j);
func1();
printf("[back in main] i = %d, j = %d\n", i, j);
}
The results of compiling and executing scope2.c are as follows.
reader@hacking:~/booksrc $ gcc scope2.c
reader@hacking:~/booksrc $ ./a.out
[in main] i = 3, j = 42
64 0x200
[in func1] i = 5, j = 42
[in func2] i = 7, j = 42
[in func2] setting j = 1337
[in func3] i = 11, j = 999
[back in func2] i = 7, j = 1337
[back in func1] i = 5, j = 1337
[back in main] i = 3, j = 1337
reader@hacking:~/booksrc $
In the output, the global variable j is written to in func2(), and the
change persists in all functions except func3(), which has its own local
variable called j. In this case, the compiler prefers to use the local variable.
With all these variables using the same names, it can be a little confusing, but
remember that in the end, it’s all just memory. The global variable j is just
stored in memory, and every function is able to access that memory. The local
variables for each function are each stored in their own places in memory,
regardless of the identical names. Printing the memory addresses of these
variables will give a clearer picture of what's going on. In the scope3.c example
code below, the variable addresses are printed using the unary address-of
operator.
scope3.c
#include <stdio.h>
int j = 42; // j is a global variable.
void func3() {
int i = 11, j = 999; // Here, j is a local variable of func3().
printf("\t\t\t[in func3] i @ 0x%08x = %d\n", &i, i);
printf("\t\t\t[in func3] j @ 0x%08x = %d\n", &j, j);
}
void func2() {
int i = 7;
printf("\t\t[in func2] i @ 0x%08x = %d\n", &i, i);
printf("\t\t[in func2] j @ 0x%08x = %d\n", &j, j);
printf("\t\t[in func2] setting j = 1337\n");
j = 1337; // Writing to j
func3();
printf("\t\t[back in func2] i @ 0x%08x = %d\n", &i, i);
printf("\t\t[back in func2] j @ 0x%08x = %d\n", &j, j);
}
void func1() {
int i = 5;
printf("\t[in func1] i @ 0x%08x = %d\n", &i, i);
printf("\t[in func1] j @ 0x%08x = %d\n", &j, j);
func2();
printf("\t[back in func1] i @ 0x%08x = %d\n", &i, i);
printf("\t[back in func1] j @ 0x%08x = %d\n", &j, j);
}
P rogramming 65
int main() {
int i = 3;
printf("[in main] i @ 0x%08x = %d\n", &i, i);
printf("[in main] j @ 0x%08x = %d\n", &j, j);
func1();
printf("[back in main] i @ 0x%08x = %d\n", &i, i);
printf("[back in main] j @ 0x%08x = %d\n", &j, j);
}
The results of compiling and executing scope3.c are as follows.
reader@hacking:~/booksrc $ gcc scope3.c
reader@hacking:~/booksrc $ ./a.out
[in main] i @ 0xbffff834 = 3
[in main] j @ 0x08049988 = 42
[in func1] i @ 0xbffff814 = 5
[in func1] j @ 0x08049988 = 42
[in func2] i @ 0xbffff7f4 = 7
[in func2] j @ 0x08049988 = 42
[in func2] setting j = 1337
[in func3] i @ 0xbffff7d4 = 11
[in func3] j @ 0xbffff7d0 = 999
[back in func2] i @ 0xbffff7f4 = 7
[back in func2] j @ 0x08049988 = 1337
[back in func1] i @ 0xbffff814 = 5
[back in func1] j @ 0x08049988 = 1337
[back in main] i @ 0xbffff834 = 3
[back in main] j @ 0x08049988 = 1337
reader@hacking:~/booksrc $
In this output, it is obvious that the variable j used by func3() is different
than the j used by the other functions. The j used by func3() is located at
0xbffff7d0, while the j used by the other functions is located at 0x08049988.
Also, notice that the variable i is actually a different memory address for each
function.
In the following output, GDB is used to stop execution at a breakpoint in
func3(). Then the backtrace command shows the record of each function call
on the stack.
reader@hacking:~/booksrc $ gcc -g scope3.c
reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) list 1
1 #include <stdio.h>
2
3 int j = 42; // j is a global variable.
4
5 void func3() {
6 int i = 11, j = 999; // Here, j is a local variable of func3().
7 printf("\t\t\t[in func3] i @ 0x%08x = %d\n", &i, i);
8 printf("\t\t\t[in func3] j @ 0x%08x = %d\n", &j, j);
9 }
66 0x200
10
(gdb) break 7
Breakpoint 1 at 0x8048388: file scope3.c, line 7.
(gdb) run
Starting program: /home/reader/booksrc/a.out
[in main] i @ 0xbffff804 = 3
[in main] j @ 0x08049988 = 42
[in func1] i @ 0xbffff7e4 = 5
[in func1] j @ 0x08049988 = 42
[in func2] i @ 0xbffff7c4 = 7
[in func2] j @ 0x08049988 = 42
[in func2] setting j = 1337
Breakpoint 1, func3 () at scope3.c:7
7 printf("\t\t\t[in func3] i @ 0x%08x = %d\n", &i, i);
(gdb) bt
#0 func3 () at scope3.c:7
#1 0x0804841d in func2 () at scope3.c:17
#2 0x0804849f in func1 () at scope3.c:26
#3 0x0804852b in main () at scope3.c:35
(gdb)
The backtrace also shows the nested function calls by looking at records
kept on the stack. Each time a function is called, a record called a stack frame
is put on the stack. Each line in the backtrace corresponds to a stack frame.
Each stack frame also contains the local variables for that context. The local
variables contained in each stack frame can be shown in GDB by adding the
word full to the backtrace command.
(gdb) bt full
#0 func3 () at scope3.c:7
i = 11
j = 999
#1 0x0804841d in func2 () at scope3.c:17
i = 7
#2 0x0804849f in func1 () at scope3.c:26
i = 5
#3 0x0804852b in main () at scope3.c:35
i = 3
(gdb)
The full backtrace clearly shows that the local variable j only exists in
func3()’s context. The global version of the variable j is used in the other
function’s contexts.
In addition to globals, variables can also be defined as static variables by
prepending the keyword static to the variable definition. Similar to global
variables, a static variable remains intact between function calls; however, static
variables are also akin to local variables since they remain local within a particular
function context. One different and unique feature of static variables
is that they are only initialized once. The code in static.c will help explain
these concepts.
P rogramming 67
static.c
#include <stdio.h>
void function() { // An example function, with its own context
int var = 5;
static int static_var = 5; // Static variable initialization
printf("\t[in function] var = %d\n", var);
printf("\t[in function] static_var = %d\n", static_var);
var++; // Add one to var.
static_var++; // Add one to static_var.
}
int main() { // The main function, with its own context
int i;
static int static_var = 1337; // Another static, in a different context
for(i=0; i < 5; i++) { // Loop 5 times.
printf("[in main] static_var = %d\n", static_var);
function(); // Call the function.
}
}
The aptly named static_var is defined as a static variable in two places:
within the context of main() and within the context of function(). Since static
variables are local within a particular functional context, these variables can
have the same name, but they actually represent two different locations in
memory. The function simply prints the values of the two variables in its context
and then adds 1 to both of them. Compiling and executing this code will
show the difference between the static and nonstatic variables.
reader@hacking:~/booksrc $ gcc static.c
reader@hacking:~/booksrc $ ./a.out
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 5
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 6
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 7
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 8
[in main] static_var = 1337
[in function] var = 5
[in function] static_var = 9
reader@hacking:~/booksrc $
68 0x200
Notice that the static_var retains its value between subsequent calls to
function(). This is because static variables retain their values, but also because
they are only initialized once. In addition, since the static variables are local
to a particular functional context, the static_var in the context of main()
retains its value of 1337 the entire time.
Once again, printing the addresses of these variables by dereferencing
them with the unary address operator will provide greater viability into what’s
really going on. Take a look at static2.c for an example.
static2.c
#include <stdio.h>
void function() { // An example function, with its own context
int var = 5;
static int static_var = 5; // Static variable initialization
printf("\t[in function] var @ %p = %d\n", &var, var);
printf("\t[in function] static_var @ %p = %d\n", &static_var, static_var);
var++; // Add 1 to var.
static_var++; // Add 1 to static_var.
}
int main() { // The main function, with its own context
int i;
static int static_var = 1337; // Another static, in a different context
for(i=0; i < 5; i++) { // loop 5 times
printf("[in main] static_var @ %p = %d\n", &static_var, static_var);
function(); // Call the function.
}
}
The results of compiling and executing static2.c are as follows.
reader@hacking:~/booksrc $ gcc static2.c
reader@hacking:~/booksrc $ ./a.out
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 5
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 6
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 7
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 8
[in main] static_var @ 0x804968c = 1337
[in function] var @ 0xbffff814 = 5
[in function] static_var @ 0x8049688 = 9
reader@hacking:~/booksrc $
P rogramming 69
With the addresses of the variables displayed, it is apparent that the
static_var in main() is different than the one found in function(), since they are
located at different memory addresses (0x804968c and 0x8049688, respectively).
You may have noticed that the addresses of the local variables all have very
high addresses, like 0xbffff814, while the global and static variables all have
very low memory addresses, like 0x0804968c and 0x8049688. That’s very astute
of you—noticing details like this and asking why is one of the cornerstones of
hacking. Read on for your answers.
0 comments:
Post a Comment