Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
14 views

Programming in C - 211-215

The document discusses pointer safety in C programming. It explains that when pointers do not point to valid memory, it can damage programs. It discusses issues with pointers to local arrays and dynamic memory allocation. The document also introduces linked lists as a dynamic data structure that can grow and shrink at runtime.

Uploaded by

SrinivasaRao
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

Programming in C - 211-215

The document discusses pointer safety in C programming. It explains that when pointers do not point to valid memory, it can damage programs. It discusses issues with pointers to local arrays and dynamic memory allocation. The document also introduces linked lists as a dynamic data structure that can grow and shrink at runtime.

Uploaded by

SrinivasaRao
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

Programming in C Unit 12

Now we don't even have the pointer to the freed memory any more, and (as
long as we check to see that p is non-NULL before using it), we won't
misuse any memory via the pointer p.
When thinking about malloc, free, and dynamically-allocated memory in
general, remember again the distinction between a pointer and what it
points to. If you call malloc to allocate some memory, and store the pointer
which malloc gives you in a local pointer variable, what happens when the
function containing the local pointer variable returns? If the local pointer
variable has automatic duration (which is the default, unless the variable is
declared static), it will disappear when the function returns. But for the
pointer variable to disappear says nothing about the memory pointed to!
That memory still exists and, as far as malloc and free are concerned, is still
allocated. The only thing that has disappeared is the pointer variable you
had which pointed at the allocated memory. (Furthermore, if it contained the
only copy of the pointer you had, once it disappears, you'll have no way of
freeing the memory, and no way of using it, either. Using memory and
freeing memory both require that you have at least one pointer to the
memory!)
12.2.4 Reallocating Memory Blocks
Sometimes you're not sure at first how much memory you'll need. For
example, if you need to store a series of items you read from the user, and if
the only way to know how many there are is to read them until the user
types some “end'' signal, you'll have no way of knowing, as you begin
reading and storing the first few, how many you'll have seen by the time you
do see that “end'' marker. You might want to allocate room for, say, 100
items, and if the user enters a 101st item before entering the “end'' marker,
you might wish for a way to say ”uh, malloc, remember those 100 items I
asked for? Could I change my mind and have 200 instead?''
In fact, you can do exactly this, with the realloc function. You hand realloc
an old pointer (such as you received from an initial call to malloc) and a new
size, and realloc does what it can to give you a chunk of memory big
enough to hold the new size. For example, if we wanted the ip variable from
an earlier example to point at 200 ints instead of 100, we could try calling
ip = realloc(ip, 200 * sizeof(int));

Manipal University of Jaipur Page No.: 211


Programming in C Unit 12

Since you always want each block of dynamically-allocated memory to be


contiguous (so that you can treat it as if it were an array), you and realloc
have to worry about the case where realloc can't make the old block of
memory bigger “in place,'' but rather has to relocate it elsewhere in order to
find enough contiguous space for the new requested size. realloc does this
by returning a new pointer. If realloc was able to make the old block of
memory bigger, it returns the same pointer. If realloc has to go elsewhere to
get enough contiguous memory, it returns a pointer to the new memory,
after copying your old data there. (In this case, after it makes the copy, it
frees the old block.) Finally, if realloc can't find enough memory to satisfy the
new request at all, it returns a null pointer. Therefore, you usually don't want
to overwrite your old pointer with realloc's return value until you've tested it
to make sure it's not a null pointer. You might use code like this:
int *newp;
newp = realloc(ip, 200 * sizeof(int));
if(newp != NULL)
ip = newp;
else {
printf("out of memory\n");
/* exit or return */
/* but ip still points at 100 ints */
}
If realloc returns something other than a null pointer, it succeeded, and we
set ip to what it returned. (We've either set ip to what it used to be or to a
new pointer, but in either case, it points to where our data is now.) If realloc
returns a null pointer, however, we hang on to our old pointer in ip which still
points at our original 100 values.
Putting this all together, here is a piece of code which reads lines of text
from the user, treats each line as an integer by calling atoi, and stores each
integer in a dynamically-allocated “array'':
#define MAXLINE 100
char line[MAXLINE];
int *ip;
int nalloc, nitems;

Manipal University of Jaipur Page No.: 212


Programming in C Unit 12

nalloc = 100;
ip = (int *)malloc(nalloc * sizeof(int)); /* initial allocation */
if(ip == NULL)
{
printf("out of memory\n");
exit(1);
}

nitems = 0;

while(getline(line, MAXLINE) != EOF)


{
if(nitems >= nalloc)
{ /* increase allocation */
int *newp;
nalloc += 100;
newp = realloc(ip, nalloc * sizeof(int));
if(newp == NULL)
{
printf("out of memory\n");
exit(1);
}
ip = newp;
}

ip[nitems++] = atoi(line);
}
We use two different variables to keep track of the “array'' pointed to by ip.
nalloc is how many elements we've allocated, and nitems is how many of
them are in use. Whenever we're about to store another item in the “array,''
if nitems >= nalloc, the old “array'' is full, and it's time to call realloc to make
it bigger.
Finally, we might ask what the return type of malloc and realloc is, if they are
able to return pointers to char or pointers to int or (though we haven't seen it
yet) pointers to any other type. The answer is that both of these functions
are declared (in <stdlib.h>) as returning a type we haven't seen, void * (that
Manipal University of Jaipur Page No.: 213
Programming in C Unit 12

is, pointer to void). We haven't really seen type void, either, but what's going
on here is that void * is specially defined as a “generic'' pointer type, which
may be used (strictly speaking, assigned to or from) any pointer type.
Self Assessment Questions
1. The process of allocating memory at run time is known as
_________________.
2. malloc() function returns a pointer to integer. (True/False)
3. For deallocating memory, you can use _________ function.
4. The function that is used to alter the size of a block previously allocated
is __________________.

12.3 Pointer Safety


The hard thing about pointers is not so much manipulating them as ensuring
that the memory they point to is valid. When a pointer doesn't point where
you think it does, if you inadvertently access or modify the memory it points
to, you can damage other parts of your program, or (in some cases) other
programs or the operating system itself!
When we use pointers to simple variables, there's not much that can go
wrong. When we use pointers into arrays, and begin moving the pointers
around, we have to be more careful, to ensure that the moving pointers
always stay within the bounds of the array(s). When we begin passing
pointers to functions, and especially when we begin returning them from
functions, we have to be more careful still, because the code using the
pointer may be far removed from the code which owns or allocated the
memory.
One particular problem concerns functions that return pointers. Where is the
memory to which the returned pointer points? Is it still around by the time
the function returns? The strstr function (as described in the earlier unit),
returns either a null pointer (which points definitively nowhere, and which the
caller presumably checks for) or it returns a pointer which points into the
input string, which the caller supplied, which is pretty safe. One thing a
function must not do, however, is return a pointer to one of its own, local,
automatic arrays. Remember that automatic variables (which includes all
non-static local variables), including automatic arrays, are deallocated and

Manipal University of Jaipur Page No.: 214


Programming in C Unit 12

disappear when the function returns. If a function returns a pointer to a local


array, that pointer will be invalid by the time the caller tries to use it.
Finally, when we're doing dynamic memory allocation with malloc, calloc,
realloc, and free, we have to be most careful of all. Dynamic allocation gives
us a lot more flexibility in how our programs use memory, although with that
flexibility comes the responsibility that we manage dynamically allocated
memory carefully. The possibilities for misdirected pointers and associated
havoc are greatest in programs that make heavy use of dynamic memory
allocation. You can reduce these possibilities by designing your program in
such a way that it's easy to ensure that pointers are used correctly and that
memory is always allocated and deallocated correctly. (If, on the other hand,
your program is designed in such a way that meeting these guarantees is a
tedious nuisance, sooner or later you'll forget or neglect to, and
maintenance will be a nightmare.)

12.4 The Concept of Linked List


When dealing with many problems we need a dynamic list, dynamic in the
sense that the size requirement need not be known at compile time. Thus,
the list may grow or shrink during runtime. A linked list is a data structure
that is used to model such a dynamic list of data items, so the study of the
linked lists as one of the data structures is important.
An array is represented in memory using sequential mapping, which has the
property that elements are fixed distance apart. But this has the following
disadvantage: It makes insertion or deletion at any arbitrary position in an
array a costly operation, because this involves the movement of some of the
existing elements.
When we want to represent several lists by using arrays of varying size,
either we have to represent each list using a separate array of maximum
size or we have to represent each of the lists using one single array. The
first one will lead to wastage of storage, and the second will involve a lot of
data movement.
So we have to use an alternative representation to overcome these
disadvantages. One alternative is a linked representation. In a linked
representation, it is not necessary that the elements be at a fixed distance
apart. Instead, we can place elements anywhere in memory, but to make it a

Manipal University of Jaipur Page No.: 215

You might also like