c_指针

来源:互联网 发布:巴宝莉风衣 知乎 编辑:程序博客网 时间:2024/05/20 05:27

/*来源:《C语言教程——Al Kelley Ira Pohl著 徐波译》第四版

*有关c的一些东东,一段时间不用,忘的差不多了,一来记忆力不好,二来原先很少写c代码。

*这本教材很好,看了一段时间,做做笔记。

*/

指针

程序中的简单变量是在机器中某个特定的内存位置(又称地址)按照一定数量的字节存储的。程序中的指针就用于访问内存和操纵地址。
如果v是个变量,那么&v就是它所存储的值在内存中的位置,也就是地址。取地址操作符"&"是单目操作符,它和其他单目操作符的优先级相同,结合性也是从右向左。地址就是一组可以被操纵的值。程序可以声明指针变量,并使用他们来访问和操纵地址。下面这个声明
int *p;
把p声明为int类型的指针。它的合法取值范围总是包括特殊地址0以及一组在特定的C系统中被解释为地址的正整数。下面是对指针p进行赋值的一些例子:

p = 0;
p = NULL;              /*equivalent to p=0; */
p = &i;
p = (int *) 1776;    /*an absolute address in memory  */

在第三个例子中,我们把p看成是“对i的引用”,“指向i”,或“包含了i的地址”。在第四个例子中,为了避免编译错误,这个强制类型转换是必要的。
间接访问或解引用操作符" * "是单目操作符,它的优先级和其他单目操作符相同。并且结合行也是从右向左。如果p是个指针,*p就是p的地址所包含的值。“间接访问”的说法取自机器变成语言。p的直接值是个内存地址,而*p是p的间接值,也就是p所存储的内存位置所存储的值。从某些意义上说,*是&的逆操作。我们想提供一个既简单有能清楚地说明指针工作机制的例子。假设有下面这个声明:

int a = 1,b = 2, *p;
此时,我们可以把变量a,b,p看成是这样存储在内存中的:

我们把p看成是个箭头,但由于它此时尚未赋值,因此我们不知道它指向哪里。假设下一行代码是:
p = &a;
我们把这行代码理解为“p被赋值为a的地址”,这样就有了下图:


现在,假设有这样一条赋值语句:
b = *p;
我们把它理解为“b被赋值为p所指向的值”,由于指针p指向a,因此下面两条语句是等价的:
b = *p;等价于 b = a;
让我们编写一个简单的程序,说明指针值与它所解引用的值之间的区别。我们将使用%p格式来打印指针的值,它在绝大多数系统中产生一个十六进制的值。在ANSI C系统中,%p格式是推荐使用的。

locate.c:
/* printing an address,or location. */
#include <stdio.h>
int main(void)
{
    int i =7, *p = &i;
    printf("%s%d\n%s%p\n"," Value of i: ", *p,"Location of i: ",p);
    return 0;
}
在我们的系统中,这个程序的输出是:
 Value of i: 7
 Location of i: effffb24

指针可以在声明中进行初始化。变量p的类型是int * ,它的初始值是&i。另外,必须在取i的地址之前对它进行声明。变量在内存中的实际位置因系统而异。操作符*对p进行解引用。也就是说,p包含了一个地址(或位置),表达式*p就具有这个地址所存储的值,并根据p的声明类型进行正确的解释。

 声明和初始化 int i=3,j=5,*p=&i,*q=&j,*r;
double x;
               表达式     等价表达式              值    p==&i    p==( &i )    1    **&p    *(*(&p))    3    r=&x    r=(&x)    非法值    7**p/ *q + 7    (((7*(*p)))/(*q))+7    11    *(r=&j)*=*p    (*(r=&j)))*=(*p)    15
在这张表中,我们试图把&x赋值给r。由于r是个int类型的指针,而表达式&x的类型是double,因此这样做是非法的。另外,注意在这张表中我们使用了表达式:
7**p/ *q+7
如果我们把它写成
7**p/*q+7        //少个空格
我们将会发现编译器将把/*当作注释的开始标记。这可能会导致一个难以发现的错误。
在传统C中,在不同类型的指针之间赋值是,进行转换通常是允许的。在ANSI C中,这种转换是不允许的,除非其中一种指针类型为void,或者赋值符右边是常量0.因此,我们可以把void *看成是一种通用的指针类型。这是一个非常重要的概念。

    声明
    int *p;
    float *q;
    void *v;

    合法赋值    非法赋值    p=0;    p=1;    p=(int *) 1;    v=1;    p=v=q;    p=q;    p=(int *) q; 

当然,并不是每个值都存储在可访问的内存位置。记住下面这些禁忌是非常重要的:
无法由指针所指向的结构:
 不要指向常量。
 &3        /*illegal */
 不要指向普通的表达式。
 &(k+99)   /*illegal */
 不要指向寄存器变量。
 register v;
 &v              /*illegal */

取址操作符可以作用于变量和数组元素。如果a是个数组,那么像&a[0]和&a[i+j+3]这样的表达式也是合法的。



原创粉丝点击