以下内容主要来自《C Primer Plus》
1 指针基础
Pointers? What are they? Basically, a pointer is a variable (or, more generally, a data object)
whose value is a memory address.
指针(pointer)是一个值为内存地址的变量(或数据对象)。
If you give a particular pointer variable the name ptr , you can have statements such as the
following:
ptr = &pooh; // assigns pooh's address to ptr
我们将一个指针变量命名为ptr,可以编写如下语句:
prt = &pooh; //将pooh的地址赋给ptr
We say that ptr “points to” pooh . The difference between ptr and &pooh is that ptr is a variable,
and &pooh is a constant. Or, ptr is a modifiable lvalue and &pooh is an rvalue.
我们说ptr“指向”pooh。ptr和&pooh的区别在于,ptr是变量,而&pooh是常量,ptr是可修改的左值,&pooh是右值。
We can make ptr point elsewhere:
ptr = &bah; // make ptr point to bah instead of to pooh
Now the value of ptr is the address of bah .
可以把ptr指向别处:
ptr = &bah; //将ptr指向bah,而不再是pooh
现在ptr的值是bah的地址。
1.1 声明指针变量 -----间接运算符(indirection operator)
Suppose you know that ptr points to bah , as shown here:
ptr = &bah;
Then you can use the indirection operator * (also called the dereferencing operator) to find the
value stored in bah
可以使用间接运算符*(也叫作解引用运算符)来找到存储在bah中的值。
The statements ptr = &bah; and val = *ptr; taken together amount to the following statement:
val = bah;
语句ptr = &bah; val = *ptr,等同于 val = bah;
Using the address and indirection operators is a rather indirect way of accomplishing this
result, hence the name “indirection operator.”
由此可见,使用地址和间接运算符可以间接完成这条语句的功能,这也是“间接运算符”名称的由来。
地址运算符 The Address Operator:&
General Comments:
When followed by a variable name, & gives the address of that variable.
说明:
&放在变量的前面,代表该变量的地址。
Example:
&nurse is the address of the variable nurse .
举例:
&nurse是变量nurse的地址。
1.2 声明指针
格式:
data_type * valiable_name;
类型说明符(data_type)表明指针所指向对象的类型,星号(*)表明声明的变量是一个指针。
You have to specify the kind of variable to which the pointer points. The reason is that different variable types take up different amounts of storage, and some pointer operations require knowledge of that storage size.
声明指针变量时,必须指定指针所指向的变量的类型,因为不同的变量类型占用不同的存储空间,一些指针操作需要知道这个存储大的大小。
Here’s how pointers are declared:
int * pi; // pi is a pointer to an integer variable
char * pc; // pc is a pointer to a character variable
float * pf, * pg; // pf, pg are pointers to float variables
下面是一些指针的声明示例:
int * pi; //pi是指向int类型变量的指针
char * pc; //pc是指向char类型变量的指针
float *pf; //pf是指向float类型变量的指针


The value ( *pc ) of what pc points to is of type char . What of pc itself?
pc指向的值(*pc)是char类型的,那pc本身是什么类型呢?
A pointer really is a new type. ANSI C provides the %p form specifically for pointers.
指针实际上是一个新类型。ANSI C专门为指针提供了%p的格式。
通过实验加强理解:

1.3 使用指针在函数间通信
先看如下程序:

运行:

Now, let’s see how this program works. First, the function call looks like this:
interchange(&x, &y);
我们来看看这个程序是怎么工作的。首先看函数调用:
interchange(&x, &y);
Instead of transmitting the values of x and y , the function transmits their addresses .
该函数传递的不是x、y的值,而是它们的地址。
That means the formal arguments u and v , appearing in the prototype and in the definition of
interchange() , will have addresses as their values. Therefore, they should be declared as
pointers.
这意味着出现在函数interchange()原型和定义中的形参u和v,是把地址作为它们的值。因此,应把它们声明为指针。
Because x and y are integers, u and v are pointers to integers, so declare them as
follows:
因为x和y是整数,u和v是指向整数的指针,所以声明如下:
void interchange (int * u, int * v)
Next, the body of the function declares
int temp;
to provide the needed temporary storage.
接下来,在函数体中定义了一个临时变量,来做临时存储。
To store the value of x in temp , use
temp = *u;
Remember, u has the value &x , so u points to x . This means that *u gives you the value of x.
Similarly, to assign the value of y to x , use
*u = *v;
which ultimately has this effect:
x = y;
You can omit the variable names in the ANSI C prototype. Then the prototype declaration
looks like this:
void interchange(int *, int *);
可以省略ANSI C的函数原型中的形参名,如下所示:
void interchange(int *, int *);
2 指针与数组
Indeed, as you will see, array notation is simply a disguised use of pointers.
我们很快就会发现,数组表示法其实是在变相地使用指针。
An example of this disguised use is that an array name is also the address of the first element of the array.
举一个变相使用指针的例子:数组名是该数组首元素的地址。
That is, if flizny is an array, the following is true:
flizny == &flizny[0]; // name of array is the address of the first element
也就是说,如果flizny是一个数组,那么下面的语句成立:
flizny == &flizny[0]; // 数组名是该数组首元素的地址
Both flizny and &flizny[0] represent the memory address of that first element.
flizny和&flizny[0]都表示数组首元素的内存地址。
Both are constants because they remain fixed for the duration of the program.
两者都是常量,因为在程序运行过程中,不会发生改变。
However, they can be assigned as values to a pointer variable , and you can change the
value of a variable.
但是可以把它们赋值给指针变量,然后可以修改指针变量的值。
如下程序:

运行结果:

The second line prints the beginning addresses of the two arrays, and the next line gives the
result of adding 1 to the address, and so on.
第二行打印的是这两个数组开始的地址,下一行打印的是指针+1后的地址,以此类推。
What is happening here is that when you say “add 1 to a pointer,” C adds one storage unit .
在C中,指针+1,指的是增加一个存储单元。
Our system is addressed by individual bytes, but type short uses 2 bytes and type double uses 8 bytes.
我们的系统中,地址按字节编址,short类型占用2字节,double类型占用8字节。
所以 指针+1,short的地址由 0x7ffe0c52ccf0 增加为 0x7ffe0c52ccf2。
For arrays, that means the address is increased to the address of the next element , not just the next byte
对数组而言,地址 +1 是指下一个元素的地址,而不是下一个字节。

int dates[y], *pti;
pti = dates; ( or pti=&dates[0];) 把数组dates首元素的地址赋给指针变量pti。
现在可以明确几点:
~~ 指针的值是它所指向对象的地址。
The value of a pointer is the address of the object to which it points.
~~在指针前面使用*运算符可以得到该指针所指向对象的值。
Applying the * operator to a pointer yields the value stored in the pointed-to object.
~~指针+1,指针的值递增它所指向类型的大小(以字节为单位)。
Adding 1 to the pointer increases its value by the size, in bytes, of the pointed-to type.
dates + 2 == &date[2] // same address 相同的地址
*(dates + 2) == dates[2] // same value 相同的值
函数、数组和指针
Suppose you want to write a function that operates on an array. For example, suppose you
want a function that returns the sum of the elements of an array. Suppose marbles is the name
of an array of int .
假设我们要编写一个处理数组的函数,该函数返回数组中所有元素之和。假设一个int类型数组的名称为marbles。
answer = sum(marbles, SIZE); //可能的函数调用 possible function call
What would the prototype be? Remember, the name of an array is the address of its first
element, so the actual argument marbles , being the address of an int , should be assigned to a
formal parameter that is a pointer-to- int :
那么,函数的原型是什么?要记住,数组名是该数组首元素的地址,所以实际参数marbles,作为一个储存int类型的地址,应把它赋给一个指针形式的形参,即该形参是一个指向int的指针。
int sum(int * ar, int n); //对应的函数原型
对应的函数定义:
int sum(int * ar, int n)
{
int i;
int total = 0;
for( i = 0; i < n; i++)
total += *(ar+i);
printf("The size of ar is %zd bytes.\n", sizeof ar);
return total;
}
我们看如下程序的运行:

运行结果:

这里marbles的大小是40字节,因为marbles中有10个整型数,每个值占4字节,所以一共占40字节。但ar的大小才8字节,是因为ar并不是数组本身,它是一个指向marbles数组首元素的指针,我们的系统中用8字节储存地址,所以指针变量的大小是8字节(不同系统可能会有差异)。
如下两种表示是等价的。
int sum(int *ar, int n)
{
// code goes here
}
int sum(int ar[], int n);
{
// code goes here
}
修改该程序,将指针换为数组表示,运行结果相同。

结果:

本文介绍了C语言中的指针概念,包括指针的定义、声明、操作(如间接运算符和地址运算符),以及指针在函数间通信中的应用。还探讨了指针与数组的关系,指出数组名本质上是第一个元素的地址。最后,涉及了如何在函数原型中正确处理数组和指针参数。
722

被折叠的 条评论
为什么被折叠?



