C Programming 5

Download Report

Transcript C Programming 5

Programming in C
Pointers and Arrays, malloc( )
Dynamic memory
In Java, objects are created on the heap using reference variables
and the new operator. Memory is freed by the garbage collector.
In C, memory is allocated from the heap using library functions
malloc(), calloc(), and realloc(). These functions return
a pointer to the allocated heap memory. Memory must be explicitly
freed using free() to avoid memory leaks and program crashes.
The argument to free( ) is a pointer returned when the memory
is allocated.
7/28/09
2
Dynamic Memory Comparison
In JAVA
public class Person
{
public int age;
public double gpa;
}
// memory allocation
Person bob = new Person( );
bob.age = 42;
bob.gpa = 3.5;
// bob is eventually freed by
// garbage collector
In C
typedef struct person
{
int age;
double gpa;
} PERSON;
/* memory allocation */
PERSON *pbob = (PERSON *)malloc(sizeof(PERSON));
pbob->age = 42;
pbob->gpa = 3.5;
...
/* explicitly freeing the memory */
free( pbob );
In C, note the use of
malloc( ) instead of new
free( )
-> (arrow) rather than . (dot)
7/28/09
3
Dynamic Memory Functions
These functions are used to allocate and free dynamically allocated heap memory and are
part of the standard C library
void *malloc( size_t nrBytes );
– Returns a pointer to dynamically allocated memory on the
heap of size nrBytes, or NULL if the request cannot be
satisfied. The memory is uninitialized.
void *calloc( int nrElements, size_t nrBytes );
– Same as malloc( ), but the memory is initialized to zero
void *realloc( void *p, size_t nrBytes);
– Changes the size of the memory pointed to by p to
nrBytes. The contents will be unchanged up to the
minimum of the old and new size. If the new size is
larger, the new space is uninitialized. Returns a
pointer to the new memory, or NULL if request cannot be
satisfied in which case *p is unchanged.
void free( void *p )
– Deallocates the memory pointed to by p which must point
to memory previously allocated by calling one of the
functions above. Does nothing if p is NULL.
7/28/09
4
void* and size_t
• The void* type is C’s generic pointer. It may point to any
kind of variable (but may not be dereferenced). Any other
pointer type may be converted to void* and back again
without loss of information. void* is often used as
parameter types to, and return types from, library functions.
• size_t is an unsigned integral type that should be used
(rather than int) when expressing the size of “something”
(e.g. an int, array, string, or struct). It too is often used as a
parameter to, or return type from, library functions. size_t
is defined as the type that is returned from the sizeof( )
operator.
7/28/09
5
Pointers and Arrays
• In C, there is a strong relationship between
pointers and arrays.
– Any array operation that can be accomplished with
subscripting (using [ ]) can also be done with pointers
• The declaration int a[10]; defines an array of
10 ints which is guaranteed to be a block of
consecutive integers named a[0], a[1], ... a[9].
The notation a[ i ] refers the “i-th” element of the
array.
• If p is defined as a pointer to an int, then the
assignment
p = &a[0]; sets p to point to the first element of
the array. The assignment x = *p; will copy the
contents of a[0] into x.
7/28/09
6
More Pointers & Arrays
• Since the name of an array is a synonym for the
address of the first element of the array, the
statement p = &a[0]; is equivalent to p = a;
• If p points to a particular element of an array, then
p + 1 points to the next element of the array and
p + n points n elements after p, REGARDLESS
of the type of the array.
• The meaning a “adding 1 to a pointer” is that
p + 1 points to the next element in the array.
7/28/09
7
More Pointers and Arrays
The expression a[ i ] can also be written as
*(a + i). The two forms are equivalent.
It follows then that &a[ i ] and (a + i) are also
equivalent. (a + i) is the address of the i-th
element beyond a.
On the other hand, if p is a pointer, then it may be
used with a subscript.
p[ i ] is identical to *(p + i).
In short, an array-and-index expression is equivalent to
a pointer-and-offset expression.
7/28/09
8
Pointer Arithmetic
• Note in the last slide that no mention was made of
the type of the array. Why not? Because it
DOESN’T MATTER!
• If “a” is an array of ints, then a[ k ] is the k-th
int and so is *(a + k).
• If “a” is an array of doubles, then a[ k ] is the kth double and so is *(a + k).
• Adding a constant, k, to a pointer actually adds
k * sizeof(pointer type) to the value of the
pointer.
• This is one important reason why the type of a
pointer must be specified when it’s defined.
• We’ll see more on this later.
7/28/09
9
ptrAdd.c
int main()
{
char c, *cPtr = &c;
int i, *iPtr = &i;
double d, *dPtr = &d;
printf("\nThe addresses
printf("cPtr = %p, iPtr
cPtr, iPtr, dPtr) ;
cPtr = cPtr + 1 ;
iPtr = iPtr + 1 ;
dPtr = dPtr + 1 ;
printf("\nThe values of
printf("cPtr = %p, iPtr
cPtr, iPtr, dPtr) ;
return 0;
of c, i and d are:\n");
= %p, dPtr = %p\n",
cPtr, iPtr and dPtr are:\n") ;
= %p, dPtr = %p\n\n",
}
7/28/09
10
Printing an Array
The code below shows how to use an array
name as a pointer
void printStrings( char *strings[ ], int size )
{
int i;
for (i = 0; i < size; i++)
printf( “%s\n”, *strings++);
}
7/28/09
11
Strings revisited
Recall, in C, a string is represented as an array of characters terminated with a null (\0)
character.
As we’ve seen, arrays and pointers are closely related. A string constant may be declared
as either a char[ ] or char*
char hello[ ] = “Hello Bobby”;
or equivalently
char *hi = “Hello Bob”;
A typedef could also be used to simplify coding;
typedef char* STRING;
STRING hi = “Hello Bob”;
In any case, the compiler will calculate the size of the char array required for the string
(including the null) and the null terminator will automatically be appended to the end
of the string,
There are many library functions written to manipulate strings and characters. See
appendix section B2 and B3 in K & R for a detailed list of function signatures and
purpose.
7/28/09
12
Arrays of Pointers
Since pointers are variable, we can create an array
of pointers just like we can create any array of
any other type. Although the pointers may point
to any type, the most common use of an array of
pointers is an array of char* to create an array of
strings.
7/28/09
13
PointerArray.c
int main( )
{
int *pInt[3];
/* an array of 3 "pointers to int */
int i, weight, height
int *pAge = (int *)malloc( sizeof( int ) );
/* store some values */
weight = 185;
height = 73;
*pAge = 42;
/* the pointers in the array can contain the address of local
** variables or malloc'd variables */
pInt[0] = pAge;
pInt[1] = &height;
pInt[2] = &weight;
for (int i = 0; i < 3; i++)
printf( "%d\n", *pInt[i]);
return 0;
}
7/28/09
14
Boy’s Names
A common use of an array of pointers is to create an array of strings. The
declaration below creates an initialized array of strings (char *) for some
boy’s names. The diagram below illustrates the memory configuration.
char *name[] = {
/* let the compiler computer the size */
“Bobby”, “Jim”, Harold”
};
names:
0
B o b b y \0
1
J i m \0
2
H a r o l d \0
7/28/09
15
Pointers2Pointer.c
int main ( )
{
/* a double, a pointer to double,
** and a pointer to a pointer to a double */
double gpa = 3.25, *pgpa, **ppgpa;
/* make pgpa point to the gpa */
pgpa = &gpa;
/* make ppgpa point to pgpa (which points to gpa) */
ppgpa = &pgpa;
/* all of these print 3.25 */
printf( "%0.2f, %0.2f, %0.2f", gpa, *pgpa, **ppgpa);
return 0;
}
7/28/09
16
char* array vs. char**
Because the name of an array is a synonym for the address of the first
element of the array, the name of the array may be treated like a pointer to
the array. As a result, the name of an array of strings (for example) may be
defined as either char *[ ] or char**.
For example, the boy’s name array
char *name[] = {
“Bobby”, “Jim”, Harold”
};
may also be defined as
char **name = {
“Bobby”, “Jim”, Harold”
};
In particular, the parameters for main may be written as either
int main (int argc, char *argv[ ])
or
int main( int argc, char **argv)
7/28/09
17
Multidimensional Arrays
C support multidimensional arrays using the
standard [ ] indexing.
The definition int a[5][4]; declares a rectangular, 2-d
array with 5 rows, and 4 columns. Enough
memory to hold 20 integers is allocated.
An alternative definition is int *b[5];. This definition
allocates enough memory for 5 int pointers for
the rows. The pointers and the memory for the
rows must be allocated an initialized. An
advantage of this definition is that the rows need
not be the same length. Brackets may still be
used to access the elements.
7/28/09
18
Command Line Arguments
Command line arguments are passed to your program as parameters to
main.
int main( int argc, char *argv[ ] )
– argc is the number of command line arguments (and hence the size of
argv)
– argv is an array of strings (char *) which are the command line
arguments. Note that argv[0] is always the name of your program.
For example, typing
myprog hello world 42
at the linux prompt results in
–
–
–
–
–
argc = 4
argv[0] = “myprog”
argv[1] = “hello”
argv[2] = “world”
argv[3] = “42”
Note that to use argv[3] as an integer, you must convert if from a string
to an int using the library function atoi( ).
E.g. int age = atoi( argv[3] );
7/28/09
19
End of Class 5
7/28/09
20