Examples of pointer constructs
Find below some examples of pointer constucts which may will help you creating your needed
pointer.
pointer.
int i; // integer variable
int *p; // pointer to integer variable
int a[]; // array of integer
int f(); // function with returnvalue integer
int **pp; // pointer to pointer to integer
int (*pa)[]; // pointer to an array of integer
int (*pf)(); // pointer to a function with returnvalue integer
int *ap[]; // array of pointers to integer
int *fp(); // function, which returns a pointer to an integer
int ***ppp; // pointer to a pointer to a pointer to integer
int (**ppa)[]; // pointer to a pointer to an array of integer
int (**ppf)(); // pointer to a pointer to a function with returnvalue integer int *(*pap)[]; // pointer to an array of pointers to integer
int *(*pfp)(); // pointer to function with returnvalue pointer to integer
int **app[]; // array of pointer to pointer to integer
int *(*pfp)(); // pointer to function with returnvalue pointer to integer
int **app[]; // array of pointer to pointer to integer
int (*apa[])[];// array of pointers to array of integer
int (*apf[])();// array of pointers to functions with returnvalue integer
int ***fpp(); // function with returnvalue pointer to pointer to pointer to int
int (*fpa())[];// function with returnvalue pointer to array of integers
int (*fpf())();// function with returnvalue pointer to function, which returns an integer
sizeof
The sizeof() operator is often used to refer to the size of a static array declared earlier in the same function.
/* better.c demonstrates one method of fixing the problem */
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
{
char buffer[10];
if (argc < 2)
{
if (argc < 2)
{
fprintf(stderr, "USAGE: %s string\n", argv[0]); return 1;
}
strncpy(buffer, argv[1], sizeof(buffer)); buffer[sizeof(buffer) 1] = '\0';
return 0;
}
To iterate over every element of an array, use
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
for( i = 0; i < NUM_ELEM(array); i++ )
{
{
/* do something with array[i] */
;
;
}
Note that the use of sizeof() above is only a convenience syntax, and works only because
buffer was declared as an array of 10 char's earlier in the function, and the compiler can thus replace sizeof(buffer) with the number 10 at compile time (equivalent to us hardcoding 10 into the code in place of sizeof(buffer)). The information about the length of buffer is not actually stored anywhere in memory (unless we keep track of it separately) and cannot be
programmatically obtained at run time from the array/pointer itself.
buffer was declared as an array of 10 char's earlier in the function, and the compiler can thus replace sizeof(buffer) with the number 10 at compile time (equivalent to us hardcoding 10 into the code in place of sizeof(buffer)). The information about the length of buffer is not actually stored anywhere in memory (unless we keep track of it separately) and cannot be
programmatically obtained at run time from the array/pointer itself.
Often a function needs to know the size of an array it was given. Unfortunately, (in C and C++) this is not possible, because (as mentioned above) the size of an array is not stored anywhere.
There are 4 common ways to work around this fact:
• Write the function to require, for each array parameter, a "length" parameter. (Typically we
use sizeof() at the point where this function is called).
use sizeof() at the point where this function is called).
• Instead of passing raw arrays, pass a structure that includes the length of the array (".length")
as well as the array (or a pointer to the first element); similar to the string or vector
classes in C++.
as well as the array (or a pointer to the first element); similar to the string or vector
classes in C++.
Memory Management
In C, you have already considered creating variables for use in the program. You have created some arrays for use, but you may have already noticed some limitations:
• that the size of the array must be known beforehand
• that the size of the array cannot be changed in the duration of your program
Dynamic memory allocation in C is a way of circumventing these problems.
Malloc
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size); void free(void *ptr);
void *malloc(size_t size);
void *realloc(void *ptr, size_t size);
The C function malloc is the means of implementing dynamic memory allocation. It is defined in stdlib.h or malloc.h, depending on what operating system you may be using. Malloc.h contains only the definitions for the memory allocation functions and not the rest of the other functions defined in stdlib.h. Usually you will not need to be so specific in your program, and if both are supported, you should use <stdlib.h>, since that is ANSI C, and what we will use here.
The corresponding call to release allocated memory back to the operating system is free.
When dynamically allocated memory is no longer needed, free should be called to release it back to the memory pool. Overwriting a pointer that points to dynamically allocated memory can result in that data becoming inaccessible. If this happens frequently, eventually the operating system will no longer be able to allocate more memory for the process. Once the process exits, the operating
system is able to free all dynamically allocated memory associated with the process.
Let's look at how dynamic memory allocation can be used for arrays.
Normally when we wish to create an array we use a declaration such as
Normally when we wish to create an array we use a declaration such as
int array[10];
Recall array can be considered a pointer which we use as an array. We specify the length of this array is 10 ints. After array[0], nine other integers have space to be stored consecutively.
Sometimes it is not known at the time the program is written how much memory will be needed for some data. In this case we would want to dynamically allocate required memory after the program has started executing. To do this we only need to declare a pointer, and invoke malloc when we wish to make space for the elements in our array, or, we can tell malloc to make space when we first
initialize the array. Either way is acceptable and useful.
initialize the array. Either way is acceptable and useful.
We also need to know how much an int takes up in memory in order to make room for it; fortunately
this is not difficult, we can use C's builtin sizeof operator. For example, if sizeof(int) yields
4, then one int takes up 4 bytes. Naturally, 2*sizeof(int) is how much memory we need for 2
ints, and so on.
this is not difficult, we can use C's builtin sizeof operator. For example, if sizeof(int) yields
4, then one int takes up 4 bytes. Naturally, 2*sizeof(int) is how much memory we need for 2
ints, and so on.
So how do we malloc an array of ten ints like before? If we wish to declare and make room in one hit, we can simply say
int *array = malloc(10*sizeof(int));
We only need to declare the pointer to the array, malloc gives us some space to store the 10 ints afterward.
Important note! malloc does not initialize the array! Like creating arrays without dynamic
allocation, the programmer must initialize the array with sensible values before using it. Make sure you do so, too. (See later the function memset for a simple method.)
It is not necessary to immediately call malloc after declairing a pointer for the allocated memory.
Often a number of statements exist between the declaration and the call to malloc, as follows:
Often a number of statements exist between the declaration and the call to malloc, as follows:
int *array;
printf("Hello World!!!");
/* more statements */
/* more statements */
array = malloc(10*sizeof(int)); /* use the array */
Error checking
When we want to use malloc, we have to be mindful that the pool of memory available to the programmer is finite. As such, we can conceivably run out of memory! In this case, malloc will
return NULL. In order to stop the program crashing from having no more memory to use, one should
always check that malloc has not returned NULL before attempting to use the memory; we can do
this by
always check that malloc has not returned NULL before attempting to use the memory; we can do
this by
int *pt;
pt = malloc(3 * sizeof(int)); if(pt == NULL)
{
printf("Out of memory, exiting\n"); exit(1);
}
Of course, suddenly quitting as in the above example is not always appropriate, and depends on the
problem you are trying to solve and the architecture you are programming for. For example if
program is a small, non critical application that's running on a desktop quitting may be appropriate. However if the program is some type of editor running on a desktop, you may want to give the
operator the option of saving his tediously entered information instead of just exiting the program. A memory allocation failure in an embedded processor, such as might be in a washing machine, could cause an automatic reset of the machine.
problem you are trying to solve and the architecture you are programming for. For example if
program is a small, non critical application that's running on a desktop quitting may be appropriate. However if the program is some type of editor running on a desktop, you may want to give the
operator the option of saving his tediously entered information instead of just exiting the program. A memory allocation failure in an embedded processor, such as might be in a washing machine, could cause an automatic reset of the machine.
The calloc function
The calloc function allocates space for an array of items and initilizes the memory to zeros. The
call mArray = calloc( count, sizeof(struct V)) allocates count objects, each of
whose size is sufficient to contain an instance of the structure struct V. The space is initialized
to all bits zero. The function returns either a pointer to the allocated memory or, if the allocation
fails, NULL.
call mArray = calloc( count, sizeof(struct V)) allocates count objects, each of
whose size is sufficient to contain an instance of the structure struct V. The space is initialized
to all bits zero. The function returns either a pointer to the allocated memory or, if the allocation
fails, NULL.
The realloc function
The realloc function changes the size of the object pointed to by ptr to the size specified by
size. The contents of the object shall be unchanged up to the lesser of the new and old sizes. If the
new size is larger, the value of the newly allocated portion of the object is indeterminate. If ptr is a
null pointer, the realloc function behaves like the malloc function for the specified size.
Otherwise, if ptr does not match a pointer earlier returned by the calloc, malloc, or
realloc function, or if the space has been deallocated by a call to the free or realloc
function, the behavior is undefined. If the space cannot be allocated, the object pointed to by ptr is
unchanged. If size is zero and ptr is not a null pointer, the object pointed to is freed. The
realloc function returns either a null pointer or a pointer to the possibly moved allocated object.
new size is larger, the value of the newly allocated portion of the object is indeterminate. If ptr is a
null pointer, the realloc function behaves like the malloc function for the specified size.
Otherwise, if ptr does not match a pointer earlier returned by the calloc, malloc, or
realloc function, or if the space has been deallocated by a call to the free or realloc
function, the behavior is undefined. If the space cannot be allocated, the object pointed to by ptr is
unchanged. If size is zero and ptr is not a null pointer, the object pointed to is freed. The
realloc function returns either a null pointer or a pointer to the possibly moved allocated object.
The free function
Memory that has been allocated using malloc, realloc, or calloc must be released back to the system memory pool once it is no longer needed. This is done to avoid perpetually allocating more and more memory, which could result in an eventual memory allocation failure. Memory that is not released with free is however released when the current program terminates on most
operating systems. Calls to free are as in the following example.
operating systems. Calls to free are as in the following example.
int *myStuff = malloc( 20 * sizeof(int)); if (myStuff != NULL ) {
/* more statements here */
/* time to release myStuff */
free( myStuff );
}
It should be noted that free is neither intelligent nor recursive. The following code that depends on
the recursive application of free to the internal variables of a struct does not work.
the recursive application of free to the internal variables of a struct does not work.
typedef struct BSTNode
{
int value;
struct BSTNode* left;
struct BSTNode* right; } BSTNode;
struct BSTNode* right; } BSTNode;
// Later: ...
BSTNode* temp = (BSTNode*) calloc(1, sizeof(BSTNode)); temp>left = (BSTNode*) calloc(1, sizeof(BSTNode));
free(temp);
free(temp);
free temp will *not* free temp>left.
Furthermore, using free when the pointer in question was never allocated in the first place often crashes or leads to mysterious bugs further along
0 comments:
Post a Comment