Typed Pointers And Casting.

In many languages, pointers have the additional restriction that the object they point to has a specific type. For example, a pointer may be declared to point to an integer; the language will then attempt to prevent the programmer from pointing it to objects which are not integers, such as floating-point numbers, eliminating some errors.
For example, in C
int *money;
char *bags;
money would be an integer pointer and bags would be a char pointer. The following would yield a compiler warning of "assignment from incompatible pointer type" under GCC
bags = money;
because money and bags were declared with different types. To suppress the compiler warning, it must be made explicit that you do indeed wish to make the assignment by type casting it.
bags = (char *)money;
which says to cast the integer pointer of money to a char pointer and assign to bags.
A 2005 draft of the C standard requires that casting a pointer derived from one type to one of another type should maintain the alignment correctness for both types (6.3.2.3 Pointers, par. 7):
char *external_buffer = "abcdef";
int *internal_data;
 
internal_data = (int *)external_buffer;  // UNDEFINED BEHAVIOUR if "the resulting pointer
                                         // is not correctly aligned"
In languages that allow pointer arithmetic, arithmetic on pointers takes into account the size of the type. For example, adding an integer number to a pointer produces another pointer that points to an address that is higher by that number times the size of the type. This allows us to easily compute the address of elements of an array of a given type, as was shown in the C arrays example above. When a pointer of one type is cast to another type of a different size, the programmer should expect that pointer arithmetic will be calculated differently. In C, for example, if the money array starts at 0x2000 and sizeof(int) is 4 bytes whereas sizeof(char) is 1 bytes, then (money+1) will point to 0x2004 but(bags+1) will point to 0x2001. Other risks of casting include loss of data when "wide" data is written to "narrow" locations (e.g. bags[0]=65537;), unexpected results when bit-shifting values, and comparison problems, especially with signed vs unsigned values. Although it is impossible in general to determine at compile-time which casts are safe, some languages store run-time type information which can be used to confirm that these dangerous casts are valid at run time. Other languages merely accept a conservative approximation of safe casts, or none at all.

Making Pointers Safer.

As a pointer allows a program to attempt to access an object that may not be defined, pointers can be the origin of a variety of programming errors. However, the usefulness of pointers is so great that it can be difficult to perform programming tasks without them. Consequently, many languages have created constructs designed to provide some of the useful features of pointers without some of their pitfalls, also sometimes referred to as pointer hazards. In this context, pointers that directly address memory (as used in this article) are referred to as raw pointers, by contrast with smart pointers or other variants.
One major problem with pointers is that as long as they can be directly manipulated as a number, they can be made to point to unused addresses or to data which is being used for other purposes. Many languages, including most functional programming languages and recent imperative languages like Java, replace pointers with a more opaque type of reference, typically referred to as simply a reference, which can only be used to refer to objects and not manipulated as numbers, preventing this type of error. Array indexing is handled as a special case. A pointer which does not have any address assigned to it is called a wild pointer. Any attempt to use such uninitialized pointers can cause unexpected behavior, either because the initial value is not a valid address, or because using it may damage other parts of the program. The result is often a segmentation fault, storage violation or wild branch (if used as a function pointer or branch address).
In systems with explicit memory allocation, it is possible to create a dangling pointer by de allocating the memory region it points into. This type of pointer is dangerous and subtle because a de allocated memory region may contain the same data as it did before it was de allocated but may be then reallocated and overwritten by unrelated code, unknown to the earlier code. Languages with garbage collection prevent this type of error because de allocation is performed automatically when there are no more references in scope. Some languages, like C++, support smart pointers, which use a simple form of reference counting to help track allocation of dynamic memory in addition to acting as a reference. In the absence of reference cycles, where an object refers to itself indirectly through a sequence of smart pointers, these eliminate the possibility of dangling pointers and memory leaks. Delphi strings support reference counting natively. 

Null Pointer.

null pointer has a value reserved for indicating that the pointer does not refer to a valid object. Null pointers are routinely used to represent conditions such as the end of a list of unknown length or the failure to perform some action; this use of null pointers can be compared to null able types and to the Nothing value in an option type. Null pointers are often considered similar to null values in relational databases, but they have somewhat different semantics. A null pointer in most programming languages means "no value", while a null value in relational database means "unknown value". This leads to important differences in practice: two null pointers are considered equal in most programming languages, but two null values in relational databases are not (since they represent unknown values, it is unknown whether they are equal). In some programming language environments (at least one proprietary Lisp implementation, for example), the value used as the null pointer (called nil in Lisp) may actually be a pointer to a block of internal data useful to the implementation (but not explicitly reachable from user programs), thus allowing the same register to be used as a useful constant and a quick way of accessing implementation internals. This is known as the nil vectorIn C, two null pointers of any type are guaranteed to compare equal. The macro NULL is defined as an implementation-defined null pointer constant, which in C99 can be portably expressed as the integer value 0 converted implicitly or explicitly to the type void*De referencing the NULL pointer typically results in an attempted read or write from memory that is not mapped - triggering a segmentation fault or access violation. This may represent itself to the developer as a program crash, or be transformed into an exception that can be caught. There are, however, certainly circumstances where this is not the case. For example, in x86-real mode, the address 0000:0000 is readable and usually writable, hence de referencing the null pointer is a perfectly valid but typically unwanted action that may lead to undefined but non-crashing behaviour in the application. Note also that there are occasions when de referencing the NULL is intentional and well defined; for example BIOS code written in C for 16-bit real-mode x86 devices may write the IDT at physical address 0 of the machine by de referencing a NULL pointer for writing. It is also possible for the compiler to optimize away the `NULL` pointer de reference, avoiding a segmentation fault but causing other. In C++, while the NULL macro was inherited from C, the integer literal for zero has been traditionally preferred to represent a null pointer constant. However, C++11 has introduced an explicit nullptr constant to be used instead.
A null pointer should not be confused with an uninitialized pointer: A null pointer is guaranteed to compare unequal to any pointer that points to a valid object. However, depending on the language and implementation, an uninitialized pointer may not have any such guarantee. It might compare equal to other, valid pointers; or it might compare equal to null pointers. It might do both at different times. In 2009 C.A.R. Hoare stated that he invented the null reference in 1965 as part of the Algol W language, although NIL had existed in Lisp since 1959. In that 2009 reference Hoare describes his invention as a "billion-dollar mistake":
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. 
Because a null pointer does not point to a meaningful object, an attempt to de reference a null pointer usually (but not always) causes a run-time error or immediate program crash.
  • In C, the behavior of de referencing a null pointer is undefined. Many implementations cause such code to result in the program being halted with a segmentation fault, because the null pointer representation is chosen to be an address that is never allocated by the system for storing objects. However, this behavior is not universal.
  • In Java, access to a null reference triggers a NullPointerException (NPE), which can be caught by error handling code, but the preferred practice is to ensure that such exceptions never occur.
  • In .NET, access to null reference triggers a Null Reference Exception to be thrown. Although catching these is generally considered bad practice, this exception type can be caught and handled by the program.
  • In Objective-C, messages may be sent to a nil object (which is a null pointer) without causing the program to be interrupted; the message is simply ignored, and the return value (if any) is nil or 0, depending on the type. In languages with a tagged architecture, a possibly null pointer can be replaced with a tagged union which enforces explicit handling of the exceptional case; in fact, a possibly null pointer can be seen as a tagged pointer with a computed tag.

Auto relative Pointer.

The term auto relative pointer may refer to a pointer whose value is interpreted as an offset from the address of the pointer itself; thus, if a data structure, M, has an auto relative pointer member, p, that points to some portion of M itself, then M may be relocated in memory without having to update the value of p.
The cited patent also uses the term self-relative pointer to mean the same thing. However, the meaning of that term has been used in other ways:
  • It is often used to mean an offset from the address of a structure rather than from the address of the pointer itself.
  • It has been used to mean a pointer containing its own address, which can be useful for reconstructing in any arbitrary region of memory a collection of data structures that point to each other.

SHARE THIS

Author:

Previous Post
Next Post