分享

我想要一种语言,只需对它说我要干什么就行

 振王府图书馆 2021-08-12
C语言是20 世纪70 年代初期在贝尔实验室开发出来的一种广为使用的编程语言。指针是 C 语言最重要,也是最常被误解的特性之一。让我们一起了解一下指针的基础知识吧。
>>>>

1.

理解指针的第一步是在机器级上观察指针表示的内容。大多数现代计算机将内存分割为字节(byte),每个字节可以存储8位的信息。

Image

每个字节都有唯一的地址(address),用来和内存中的其他字节相区别。如果内存中有n个 字节,那么可以把地址看作0~n-1的数。

  地址   内容

Image

可执行程序由代码(原始C程序中与语句对应的机器指令)和数据(原始程序中的变量)两部分构成。程序中的每个变量占有一个或多个字节内存,把第一个字节的地址称为变量的地址。下图中,变量i占有地址为2000和2001的两个字节,所以变量i的地址是2000:

Image

这就是指针的出处。虽然用数表示地址,但是地址的取值范围可能不同于整数的范围,所以一定不能用普通整型变量存储地址。但是,可以用特殊的指针变量(pointervariable)存储地址。在用指针变量p存储变量i的地址时,我们说p“指向”i。Q&A换句话说,指针就是地址,而指针变量就是存储地址的变量。

这里不再把地址显示为数,而是采用更加简单的标记。为了说明指针变量p存储变量i的地址,把p的内容显示为指向i的箭头:

Image

指针变量的声明

对指针变量的声明与对普通变量的声明基本一样,唯一的不同就是必须在指针变量名字前放置星号:

int*p;

上述声明说明p是指向int类型对象的指针变量。这里我们用术语对象来代替变量,是因为p可以指向不属于变量的内存区域。

指针变量可以和其他变量一起出现在声明中:

inti,j,a[10],b[20],*p,*q;

在这个例子中,i和j都是普通整型变量,a和b是整型数组,而p和q是指向整型对象的指针。

C语言要求每个指针变量只能指向一种特定类型(引用类型)的对象:

int*p;/*pointsonlytointegers*/double*q;/*pointsonlytodoubles*/char*r;  /*pointsonlytocharacters*/

至于引用类型是什么类型则没有限制。事实上,指针变量甚至可以指向另一个指针,即指向指针的指针。

2.取地址运算符和间接寻址运算符

为使用指针,C语言提供了一对特殊设计的运算符。为了找到变量的地址,可以使用&(取地址)运算符。如果x是变量,那么&x就是x在内存中的地址。为了获得对指针所指向对象的访问,可以使用*(间接寻址)运算符。如果p是指针,那么*p表示p当前指向的对象。

 

取地址运算符

声明指针变量是为指针留出空间,但是并没有把它指向对象:

int*p;    /*pointsnowhereinparticular*/

在使用前初始化p是至关重要的。一种初始化指针变量的方法是使用&运算符把某个变量的地址赋给它,或者更常采用左值:

inti,*p;

...

p=&i;

通过把i的地址赋值给变量p的方法,上述语句把p指向了i:

Image                                  

Q&A:在声明指针变量的同时对它进行初始化是可行的:

inti;

int*p=&i;

甚至可以把i的声明和p的声明合并,但是需要首先声明i:

inti,*p=&i;

间接寻址运算符

一旦指针变量指向了对象,就可以使用*运算符访问存储在对象中的内容。例如,如果p

指向i,那么可以显示出i的值,如下所示:

printf('%d\n',*p);

Q&A printf函数将显示i的值,而不是i的地址。习惯于数学思维的读者可能希望把*想象成&的逆运算。对变量使用&运算符产生指向变量

的指针,而对指针使用*运算符则可以返回到原始变量:

j=*&i;     /*sameasj=i;*/

只要p指向i,*p就是i的别名。*p不仅拥有和i相同的值,而且对*p的改变也会改变i的值。(*p是左值,所以对它赋值是合法的。)下面的例子说明了*p和i的等价关系,这些图 显示了在计算中不同的点上p和i的值。

p=&i;

Image 

i=1;

Image

printf('%d\n',i); ->  /*prints1*

/printf('%d\n',*p); ->  /*prints1*/

*p=2;

Image

printf('%d\n',i); -> /*prints2*

/printf('%d\n',*p);  ->  /*prints2*/

注意

不要把间接寻址运算符用于未初始化的指针变量。如果指针变量p没有初始化,那么试图

使用p的值会导致未定义的行为:

int*p;

printf('%d',*p);/***WRONG***/ 

给*p赋值尤其危险。如果p恰好具有有效的内存地址,下面的赋值会试图修改存储在该地址的数据:

int*p;

*p=1;/***WRONG***/ 

如果上述赋值改变的内存单元属于该程序,那么可能会导致出乎意料的行为;如果改变的内存单元属于操作系统,那么很可能会导致系统崩溃。编译器可能会给出警 告消息,告知p未初始化,所以请留意收到的警告消息。

3.指针赋值

C语言允许使用赋值运算符进行指针的复制,前提是两个指针具有相同的类型。假设i、j、 p和q声明如下:

inti,j,*p,*q; 

语句 

p=&i;

是指针赋值的示例,把i的地址复制给p。下面是另一个指针赋值的示例: 

q=p; 

这条语句是把p的内容(即i的地址)复制给q,效果是把q指向了p所指向的地方:

Image

现在p和q都指向了i,所以可以用对*p或*q赋新值的方法来改变i:

*p=1;

Image

*q=2;

Image

任意数量的指针变量都可以指向同一个对象。注意不要把

q=p;

*q=*p;

搞混。第一条语句是指针赋值,而第二条语句不是。就如下面的例子显示的:

p=&i;q=&j;i=1;

*q=*p;

赋值语句*q=*p;是把p指向的值(i的值)复制到q指向的对象(变量j)中。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多