Pointers are a central feature of the C programming language. They serve as a uniform way to generate reference to elements within different data structures. Pointers are a source of confusion for novice programmers, but the underlying concepts are fairly simple. Here we highlight some key principles of pointers and their mapping into machine code.
指针是C语言的一个重要特点, 他提供了一个一致性的方法去引用结构体中的一个成员。 对于刚学习C语言的程序员来说,就是指针让他感到困惑。但是,指针背后的基本原理是相当简单的。 在这里,我们列出它的一个原理。
Every pointer has an associated type. this type indicates what kind of object the pointer points to. Using the following pointer declarations as illustrations.
每一个指针,都有一个类型, 这个类型表明它指向的object 有着什么样的类型, 我们使用下面的指针声明来说明。
int *ip;
char **cpp;
variable ip is a pointer to an object of type in, while cpp is a pointer to an object that itself is a pointer to an object of type char. In general, if the object has type T, then the pointer has type *T. The special void * type represents a generic pointer. For example, the malloc function returns a generic pointer, which is converted to a typed pointer via either an explicit cast or by the implicit casting of the assignment operation. Pointer types are not part of machine code; they are an abstraction provided by C to help programmers avoid addressing errors.
变量ip 是一个指针,cpp 也是一个指针,cpp 指向一个本身就是指针(指向一个char). void * 表示一个一generic 指针,就是说,它最终可以指向任何类型的,比如说, malloc 函数返回的generic 指针, 它最终指向的类型会被显示或者隐式(按照既定规则)的转换为某种类型。 指针类型,并不是某种机器代码, 它抽象出来,使程序员避免地址(使用)错误
Every pointer has a value. This value is an address of some object of the designated type. The special NULL (0) value indicates that the pointer does no point anywhere.
Pointer are created with &operator. This operator can be applied to any C expression that is categorized an an lvalue, meaning an expression that can appear on the left side of assignment, Examples include variables and the elements of structures, unions, and arrays. We have seen that the machine code realization of the & operator often uses the leal instruction is designed to compute the address of a memory reference.
Pointers are dereferenced with the * operator. The result ia value having the type associated with pointer. Dereferencing is implemented by a memory reference, enther storing to or retrieving from the specified address.
Arrays and pointers are closely related. The name of an array can be referenced (but not updated) as if it were a pointer variable. Array referencing(e.g. a[3]) has the exact same effect as pointer arithmetic and dereferencing (e.g. *(a+3)). Both array referencing and pointer arithmetic require scaling the offsets by the object size. When we write an expression p+i for pointer with value p, the resulting address is computed as p+ L x i, where L is the size of the data type associated with p.
Casting from one type of pointer to another changes its type but not its value, One effect of casting is to change any scaling of pointer arithmetic. So for example, if p is a pointer of type char * having value p, the the expression (int *) p + 7 computes p + 28, while (int *) (p+7) compute p + 7. (Recall that casting has higher precedence than addition.)
Pointers can also point to functions. This provides a powerful capability for storing and passing references to code. which can be invoked in some other part of the program. For example, if we have a function defined by the prototype
int fun(int x, int *p);
then we can declare and assign a pointer fp to this function by the following code sequence:
(int) (*fp)(int, int *);
fp = fun;
we can then invoke the function using this pointer:
int y = 1;
int result = fp(3, &y);
The value of a function pointer is the address of the first instruction in the machine-code representation of the function.