LECTUER NOTE 30
CHARACTER POINTERS AND FUNCTIONS
A string constant, written as
"I am a string"
is an array of characters. In the internal representation, the array is terminated with the
null
character '\0' so that programs can find the end. The length in storage is thus one more than the
number of characters between the double quotes.
Perhaps the most common occurrence of string constants is as arguments to functions,
as in
printf("hello, world\n");
When a character string like this appears in a program, access to it is through a character
pointer; printfreceives a pointer to the beginning of the character array. That is, a string
constant is accessed by a pointer to its first element. String constants need not be function
arguments. If pmessageis declared as
char *pmessage;
then the statement
pmessage = "now is the time";
assigns to pmessagea pointer to the character array. This is not a string copy; only pointers
are involved. C does not provide any operators for processing an entire string of characters as a
unit. There is an important difference between these definitions:
char
amessage[] =
"now is the
time"; char
*pmessage =
"now is the
time";
amessage is an array, just big enough to hold the sequence of characters and '\0' that initializes
it. Individual characters within the array may be changed but amessagewill always refer to
the
same storage. On the other hand, pmessageis a pointer, initialized to point to a string constant; the
pointer may subsequently be modified to point elsewhere, but the result is undefined if you try
to modify the string contents.
We will illustrate more aspects of pointers and arrays by studying versions of two
useful
functions adapted from the standard library. The first function is strcpy(s,t), which copies the
LECTURE NOTE
31
DYNAMIC MEMORY ALLOCATION
The memory allocation that we have done till now was static memory allocation.. So the memory
that could be used by the program was fixed. So we couldnot allocate or deallocate
memory during the execution of the program. It is not possible to predict how much
memory will be needed by the program at run time. For example assume we have declared an
array with size 20 elements, which is fixed. So if at run time values to be stored in array
is less than 20 then wastage of memory occurs or our program may fail if more than 20 values
are to be stored in to that array. To solve the above problems and allocate memory during
runtime we are using dynamic memory allocation.
The following functions are used in dynamic memory allocation and are defined in <stdlib.h>
1. malloc()
Declaration: void *malloc(size_t size);
This function is used to allocate memory dynamically. The argument size specifies
the number of bytes to be allocated. On success, malloc() returns a pointer to the first
byte vof allocated memory. The returned pointer is of type void, which can
be type cast to appropriate type of pointer. The memory allocated by malloc()
contains garbage value
2. calloc()
Declaration: void *calloc(size_t n,size_t size);
This function is used to allocate multiple blocks of memory. The first argument
specifies the number of blocks and the second one specifies the size of each block.
The memory allocated by calloc() is initialized to zero.
3. realloc()
Declaration: void *realloc(void *ptr,size_t newsize);
The function realloc() is used to change the size of the memory block. It alters the size
of the memory block without losing the old data. This function takes two arguments,
first is a pointer to the block of memory that was previously allocated by mallloc()
or calloc() and second one is the new size for that block.
4. free();
Declaration: void free(void *p);
This function is used to release the memory space allocated dynamically. Rhe
memory released by free() is made available to the heap again and can be used
for some other purpose. We should not try to free any memory location that
was not allocated by malloc(), calloc() or realloc().
The following program illustrates Dynamic memory allocation.
LECTURE NOTE
32
POINTER TO STRUCTURES
You may recall that the name of an array stands for the address of its zero-th element. Also true
for the names of arrays of structure variables.
Consider the declaration:
;
char dept_code[25];
float cgpa;
} class[100], *ptr ;
The name class represents the address of the zero-th element of the structure array. ptr
is a pointer to data objects of the type struct stud. The assignment ptr = class; will
assign the address of class[0] to ptr.
When the pointer ptr is incremented by one (ptr++) :
The value of ptr is actually increased by sizeof(stud).
It is made to point to the next record.
Once ptr points to a structure variable, the members can be
accessed as: ptr –> roll;
p
t
r
–
>
d
e
p
t
_
c
Pointer Arrays; Pointers to Pointers
Syntax to declare pointer to an array is
datatype (*pointer_variable)[size];
For example
int (*ptr)[10]; ,Here ptr is a pointer that can point to an array of 10 integers, where we
can initialize ptr with the base address of the array then by incre menting the value of ptr
we can access different elements of array a[].
Since pointers are variables themselves, they can be stored in arrays just as other variables
can. Let us illustrate by writing a program that will sort a set of text lines into alphabetic
order, a stripped-down version of the UNIX program sort.
We need a data representation that will cope efficiently and conveniently with variable-length
text lines. This is where the array of pointers enters. If the lines to be sorted are stored end-to-
end in one long character array, then each line can be accessed by a pointer to its first
character. Thepointers themselves can bee stored in an array. Two lines can be compared by
passing their
pointers to strcmp. When two out-of-order lines have to be exchanged, the pointers in the pointer
array are exchanged, not the text lines themselves.
This eliminates the twin problems of complicated storage management and high overhead
that would go with moving the lines themselves.
print them in order
As usual, it's best to divide the program into functions that match this natural division, with
the main routine controlling the other functions. Let us defer the sorting step for a
moment, and concentrate on the data structure and the input and output. The input routine
has to collect and save the characters of each line, and build an array of pointers to the lines.
It will also have to count the number of input lines, since that information is needed for
sorting and printing. Since the input function can only cope with a finite number of input
lines, it can return some illegal
count like -1 if too much input is presented. The output routine only has to print the lines in the
order in which they appear in the array of pointers.
intreadlines(char *lineptr[], intnlines);
M
u
l
t
i
-
d
i
m
e
n
s
i
o
n
a
l
A
r
r
a
y
s
"Illegal month",
"January", "February", "March",
"April", "May", "June",
"July",
"August",
"September"
,
"October",
"November"
,
"December"
};
return (n
< 1 || n >
12) ?
name[0] :
name[n];
}
The declaration of name, which is an array of character pointers, is the same as lineptrin the
sorting example. The initializer is a list of character strings; each is assigned to the corresponding
position in the array. The characters of the i-th string are placed somewhere, and a pointer
to them is stored in name[i]. Since the size of the array name is not specified, the compiler
counts
the initializers and fills in the correct number.
Pointers vs. Multi-dimensional Arrays
Newcomers to C are sometimes confused about the difference between a two-dimensional array
and an array of pointers, such as name in the example above. Given the definitions
then a[3][4] and b[3][4] are both syntactically legal references to a single int. But a is a true
two-dimensional array: 200 int-sized locations have been set aside, and the
conventional
rectangular subscript calculation 20 * row +col is used to find the element a[row,col]. For b,
however, the definition only allocates 10 pointers and does not initialize them; initialization must
be done explicitly, either statically or with code. Assuming that each element of b does point to a
twenty-element array, then there will be 200 ints set aside, plus ten cells for the pointers.
The important advantage of the pointer array is that the rows of the array may be of different
lengths. That is, each element of b need not point to a twenty-element vector; some may
point to two elements, some to fifty, and some to none at all. Although we have phrased
this discussion in terms of integers, by far the most frequent use of arrays of pointers is to store
character strings of
diverse lengths, as in the function month_name. Compare the declaration and picture for an array
of pointers:
Array of Pointers
We can declare an array that contains pointers as its elements. Syntax to declare array of pointer:
datatype *arrayname[size];
For example to declare an array of size 20 that contains integer pointers we
can write int *a[10];
where we can initialize each element of a[] with addresses of variables.
Functions returning Pointer
We can have a function that returns a pointer. Syntax to declare such type of function is
Pointers to Functions
How to declare a pointer to a function?
Syntax: returntype_of_function
(*pointer variable)(List of arguments);
For example:
int (*p)(int,int); can be interpreted as p is a pointer to function which takes two integers
as argument and returntype is integer.