Title: Pointers, Arrays, and Dynamic Memory
1Pointers, Arrays, and Dynamic Memory
2Pointer Variables
- A pointer is a variable whose value is the
address of another variable. - The size of the pointer variable must be n bits
where 2n bytes is the size of the address space.
3Pointer Variables
- Allow C programs to simulate call-by-reference
- Allow a programmer to create and manipulate
dynamic data structures. - Must be defined before it can be used.
- Should be initialized to NULL.
4Declaring a Pointer Variable
- To declare a pointer in a program just use the
type it points to followed by . - lttypegt variableName
- e.g.
- char phrase
- int xPtr
- phrase and xPtr are the names of variables
- The informs the compiler that we want a pointer
variable, i.e. to set aside however many bytes is
required to store an address in memory.
5Pointers
- A pointer variable has two associated values
- Direct value
- address of another memory cell
- Referenced by using the name of the variable
- Indirect value
- value of the memory cell whose address is the
pointer's direct value. - Referenced by applying the indirection
6Pointer Variables
- To refer to the entity to which the pointer
points prepend , the indirection (or
dereferencing) operator - xPtr 10
- stores the value 10 in the address pointed to
by xPtr. - in this case, 10 is stored in x, since xPtr
points to x
7Pointer Operators
- operator
- - indirection operator or dereferencing
operator. - - returns a synonym, alias or nickname to
which its operand points. - operator
- - address operator
- - returns the address of its operand.
8Pointer Variables
- One way to store a value in a pointer variable is
to use the operator. - int x 5
- int xPtr x
- The address of x is stored in xPtr. We say,
xPtr points to x.
9Pointer Variables
- int x 5
- Assume x is stored in memory at location 300000
and y is stored at location 700000 - 300000
- The statement,
- int xPtr x
- causes the address of x to be stored in xPtr
- 700000
5
x
300000
xPtr
10Pointer Variables
- We represent this graphically as
5
x
xPtr
11Pointer Variables
- The indirection (dereferencing) operator is
- xPtr 10
- stores the value 10 in the address pointed to
by xPtr.
10
x
xPtr
12Pointer Variables
- Notice that the character is used in two ways
- To declare that a variable is a pointer.
- To access the location pointed to by a pointer.
- Prepending a variable with a in a declaration
declares that the variable will be a pointer to
the indicated type instead of a regular variable
of that type. - Prepending a variable with a in an expression
indicates the value in the location pointed to by
the address stored in the variable.
13Pointers and Dynamic Allocation of Memory
- So far, we have always allocated memory for
variables in the function data areas that are
located on the stack. - Size of such variables must be known at compile
time. - There are times when it is convenient to allocate
memory at run time using malloc(), calloc(), or
other allocation functions.
14Pointers and Dynamic Allocation of Memory
- The system maintains a second storage area called
the heap - Permits postponing the decision on the size of
the memory block needed to store an array - Or permits using a section of memory for the
storage of an array at one point in time, and
then when that memory is no longer needed it can
be freed up for other uses.
15Pointers and Dynamic Allocation of Memory
- When memory is allocated, the allocating function
(such as malloc(), calloc(), etc.) returns a
pointer of type void (depending on the compiler). - void indicates a pointer to untyped memory
- Will have to cast the returned value to the
specific type needed. - We should always release allocated space when no
longer needed, so that it can be reused.
16Initializing Pointers
- Like all variables pointers must be initialized
before they are used. - / pointer1.c /
- / Example of a common error failure to
intialize / - / a pointer before using it.. This program is /
- / is FATALLY flawed.... /
- int main()
- int ptr
- ptr 99
- printf("val of ptr d and ptr is p \n",
ptr, ptr) - return 0
ptr has not been initialized
17Initializing Pointers
- To minimize pointer problems
- Never declare a pointer without intializing it in
the declaration. - int ptr NULL
- Never use NULL as a synonym for integer or float
0.
18Using gdb to find the point of failure
- The gdb debugger is a handy tool for identifying
the location at which a program failed. - To use the debugger it is necessary to compile
with the g option. - lowerm_at_shadow117 gcc -g pointer1.c -o p1.o
- To start the debugger use the gdb command and
specify the program name - lowerm_at_shadow117 gdb p1.o
19Using gdb to find the point of failure
- At the (gdb) prompt you will usually want to tell
the debugger to halt the program when it reaches
the start of the main() function. The b command
is short for breakpoint and tells the debugger
where to stop. After a function is entered source
code line numbers can be used to specify
breakpoints. - (gdb) b main
- Breakpoint 1 at 0x10604 file pointer1.c, line 11.
20Using gdb to find the point of failure
- To start the program use the run command
- (gdb) run
- Starting program /users/lowerm/public_html/cs101/
examples/p.o - When the program reaches a breakpoint gdb will
tell you and display the next line of code to be
executed. - Breakpoint 1, main () at pointer1.c11
- 11 ptr 99 // ptr has not been initialized
21Using gdb to find the point of failure
- Use the next command to execute a single source
statement. The next command will treat a function
call as a single statement and not single step
into the function being called. If you want to
single step through the function use the step
command to step into it. The output of the - printf() is intermixed with gdb's output and is
shown in blue below. - (gdb) next
- pointer is 0
- 12 ptr 99
22Using gdb to find the point of failure
- Saying next again will cause the program to
execute the flawed assignment. gdb will show you
the line that caused the error (line 12). - (gdb) next
- Program received signal SIGSEGV, Segmentation
fault. - 0x00010620 in main () at p18.c12
- 12 ptr 99
23Using gdb to find the point of failure
- The where command can show you where the failure
occured (along with a complete function
activation trace. - (gdb) where
- 0 0x00010620 in main () at pointer1.c12
- (gdb)
- To print the value of a variable use the print
command. - (gdb) print ptr
- 1 (int ) 0x0
24Using gdb to find the point of failure
- Attempting to print what ptr points to reaffirms
what the problem is - (gdb) print ptr
- Cannot access memory at address 0x0
- Use the q (quit) command to terminate gdb
- (gdb) quit
- The program is running. Exit anyway? (y or n) y
- lowerm_at_shadow7126
25Correct use of the pointer
- In the C language, variables that are declared
within any basic block are allocated on the
runtime stack at the time the basic block is
activated. - / pointer2.c /
- main()
- int y
- int ptr
- static int a
- ptr y // assign the address of y to the
pointer - ptr 99 // assign 99 to what the pointer
points to (y) - printf("y d ptr p addr of ptr p \n",
y, ptr, ptr) - ptr a
- printf("The address of a is p \n", ptr)
26Correct use of the pointer
- lowerm_at_shadow130 ./p2.o
- x 99 ptr ffbff05c addr of ptr ffbff058
- The address of a is 208e0
- Note that a is heap resident and has an address
far removed from the stack resident y and ptr.
27Use of pointers in processing Cstrings
- Recall that a Cstring is an array of characters
whose logical end is denoted by a zero valued
byte. The C standard library has a number of
functions designed to work with C strings. - The strtok() function is one of them. You can see
most of them on a Solaris system via the command - man -s 3C string
- string, strcasecmp, strncasecmp, strcat, strncat,
strlcat, - strchr, strrchr, strcmp, strncmp, strcpy,
strncpy, strlcpy, strcspn, strspn, strdup,
strlen, strpbrk, strstr, strtok, strtok_r -
string operations
28Use of pointers in processing Cstrings
- In this example we will see how strcat might be
implemented. Its prototype is shown below. - char strcat(char s1, const char s2)
29An implementaton of strcat
- The name zstrcat is used to avoid potential name
conflicts with the real strcat. - include ltstdio.hgt
- include lterror.hgt
- / The mission of this function is to concatenate
/ - / the string pointed to by p2 to the end of /
- / the string pointed to by p1 /
- char zstrcat(char p1, char p2)
- char src / source pointer /
- char dest / destination pointer /
- dest p1
- src p2
- / Start by advancing dest to the end of the
string to be extended / - while (dest ! 0)
- dest dest 1
- / Now tack on the string to be appended /
- while (src ! 0)
-
- dst src
- dest dest 1
30An alternate implementaton
- The following approach produces code that is
difficult to read, painful to maintain, but may
(or may not) produce a trivial improvement in
performance . When tempted, just say no! - char zstrcat(char p1, char p2)
- char r p1
- while (p1)
- p1--
- while (p1 p2)
- return(r)
-
31An alternate implementaton
- main()
- char s1
- char s2
- char result
- s1 (char )malloc(40)
- s2 (char )malloc(40)
- result (char )malloc(81)
- result 0
- fgets(s1, 40, stdin)
- fgets(s2, 40, stdin)
- zstrcat(result, s1)
- zstrcat(result, " ")
- zstrcat(result, s2)
- fputs(result, stdout)
-
- Hello
- World
- Hello
32Pointer Variables and Arrays
- Given
- int ptr
- ptr 7
- the compiler will know how many bytes to copy
into that memory location pointed to by ptr. - defining the type that the pointer points to
permits a number of other interesting ways a
compiler can interpret code.
33Pointer Variables and Arrays
- Consider a block in memory consisting of ten
integers in a row. That is, 40 bytes of memory
are set aside to hold 10 integers. - Now, set ptr to point to the first of these
integers. - Suppose the integer is located at memory address
20918. What happens when we write - ptr ptr 1
- Because the compiler "knows"
- this is a pointer (i.e. its value is an address)
and - that it points to an integer (current address,
20918 - it adds 4 to ptr instead of 1, so the pointer
"points to" the next integer, at memory location
34Pointer Variables and Arrays
- Since a block of 10 integers located contiguously
in memory is, by definition, an array of
integers, this brings up an interesting
relationship between arrays and pointers.
35Pointer Variables and Arrays
- Consider the following
- int my_array 1, 23,17,4,-5,100
- Here we have an array containing 6 integers.
- We refer to each of these integers by means of
a subscript to my_array, i.e. using my_array0
through my_array5.
36Pointer Variables and Arrays
- The name of an array and the address of the first
element in the array represent the same thing
consequently, we could alternatively access them
via a pointer as follows - int ptr
- ptr myArray0 / points to the first
- integer in the
array / - Then we could print out our array either using
the array notation or by dereferencing our
pointer.
37Pointer Variables and Arrays
- Since the name of an array is a pointer constant
to the first element of the array therefore, we
could also use the following - ptr myArray
38Pointer Arithmetic and Arrays
- If ptr is pointing to a specific element in an
array, ptr n is the pointer value n
elements away. - The following two expressions are exactly the
same when array is the name of an array and n is
an integer - (array n) arrayn
-
39Using a one-dimensional array to represent 2-D
data
- Suppose the integer variables numRows and numCols
represent the number of rows and columns in an
image and that they have been correctly set using
information in the .ppm header. - Grayscale images
- Space for a grayscale image encoded in binary can
be allocatged by - unsigned char image
- image (unsigned char ) malloc(numRows
numCols)
40Using a one-dimensional array to represent 2-D
data
- To read in the grayscale image from the standard
input - pixelCount fread(image, 1, numRows numCols,
stdin) - if(pixelCount ! numRows numCols)
- fprintf(stderr, "pixel count err expected
d got d\n", - numRows numCols, pixelCount)
- exit(1)
41Accessing a specific element in a malloc'd 2-D
data
- The value of any grayscale pixel at location
(row, col) within the image is accessed in the
following way - pixel (image row numCols col)
- or equivalently
- pixel imagerow numCols col)
- For example, if the value of numCols is 7,
then there are 7 pixels per image row. To reach
the pixel whose (row, column) address is (3, 5)
it is necessary to pass over three complete rows
and 5 pixels in row three. - The offset of the pixel at (3,5) is 3 7
5 as shown above
42Processing an image one row at a time
-
- for (row row lt numRows row)
- unsigned char location
- location image row numCols //
first pixel in row - printf("\n")
- for(col 0 col lt numCols col)
- printf("03x", location)
- location location 1
-
-
43Processing an image one row at a time
-
- An equivalent method that uses array notation
- for (row 0 row lt numRows row)
- printf("\n"
- for(col 0 col lt numCols col)
- printf("03x", imagerow numCols
col) - location location 1
-
-
44Color Images
- A color image is often called an rgb image
because the red, green, and blue intensities of
each pixel are stored together. Space for a color
image in binary rgb format can be allocated by - unsigned char image
- image (unsigned char ) malloc(3 numrows
numcols) - To read in the rgb image
- pixcount fread(imageloc, 3, numrows numcols,
stdin) - if (pixcount ! numrows numcols)
- fprintf(stderr, pix count err - wanted d got d
\n, - numrows numcols, pixcount)
- exit(1)
45Accessing the Individual Pixels of the Binary RGB
Image
- Here the process is slightly more complex because
each pixel is represented by three constituent
components (r, g, and b) where each of (r, g, and
b) are represented by a single unsigned char. - Nevertheless a bit of reflection yields
- red (image 3 row numcols 3 col)
- green (image 3 row numcols 3 col
1) - blue (image 3 row numcols 3 col
2) - or equivalently
- red image3 row numcols 3 col
- green image3 row numcols 3 col 1
- blue image3 row numcols 3 col 2
- It is necessary to muliply by 3 because each
pixel occupies three bytes of memory.
46Functions that Modify Variables of Their Callers
- When a function tries to modify a parameter that
is passed to it, it has no effect on the callers
copy of that variable. - A caller can allow a function to modify its
variables by passing a pointer to the value
47Functions that Modify Variables of Their Callers
- include ltstdio.hgt
- int getDims (int numcols, int numrows )
- int main( )
- int rows
- int cols
- getdims(cols, rows)
- fprintf(stdout, rows d cols d \n, rows,
cols)
48Functions that Modify Variables of Their Callers
- int getDims (int numcols, int numrows )
- fscanf(stdin, "d d", numcols, numrows)
-