指针的初步了解

指针只不过去是一种数据类型罢了

指针常量:什么样的量是指针常量

指针变量:如何定义一个指针变量

指针常量:变量的地址

所有变量一旦完成定义,就会获得计算机分配的空间,而其地址空间首地址即为该变量的地址,通常称其为地址常量或指针常量。

指针变量:可以装指针常量的变量:
px=&x,px里装着指针x的地址
** 存储类型 数据类型 指针名**
auto register static extern
声明位置 存储类型 ——寿命与作用域
全局指针变量,局部指针变量
数据类型:指针所指向的目标的数据类型
int *px
char *name
static int *cns
C语言的指针的概念与运算
具有相同存储类型和数据类型的指针可以在一行中进行说明,也可以和普通变量在一起说明。
int *px,*py,*pz;
char cc,*name;
void型指针变量

· 指向一种抽象的数据类型,即定义一个指针变量,但不指明它指向哪种具体的数
据类型,称为“无类型指针”
<存储类型> void *指针变量名;
void型的定义格式和普通指针几乎一样,仅数据类型指定为void型这类指针可以指
向任何数据类型的目标变量,它在定向时可以将已定向的各种类型指针直接赋给
void指针,反之,将void指针赋给其他类型指针时,必须采用强制类型转换,将它
变成指向相应数据类型的指针。

指针的简单操作
(1)取地址操作符&
取地址运算符&的操作对象必须为左值表达式(即有名存储区或变量),
预算结果为操作对象变量的地址,运算类型为操作对象类型的指针,是指针常量。
单目&是取地址运算符,单目&与操作对象组成的表达式是地址表达式。

int x;  int *p; p=&x;
char y;  char *n; n=&y;
double z;  double *t; t=&z;

数组名,常量和寄存器类型变量均不能做单目&的操作对象。

int i,a[4];  &i,&a[i],&a[0](或a)合法
register int k;  &k, &a非法

(2)取内容运算符*
*操作对象
操作对象必须是地址表达式,即指针(地址常量或指针常量)。
运算结果为指针所指的对象,即变量本身,
结果类型为指针所指的对象的类型。

int c,*p=&c;     //  在说明语句中,*是抽象指针说明符。
//(此处是同时进行定义与赋值操作,一般情况下这么写是不正确的)
*(&c)=100;        // 在表达式中的*,若有两个操作对象则是乘运算符(双目*)
*p=100;            // 若有一个操作对象则是间访运算符(单目*)
c=100;

取地址运算符&与取内容运算符*
单目*与&互为逆运算
*(&左值表达式)=左值表达式;
&(*地址表达式)=地址表达式;
NULL类型指针
表示某种特定的指针而未指向任何东西
与零比较;
对NULL的操作是非法的。

指针操作

//ptr_ops.c
#inclide <stdio.h>
int main(void)
{
int urn[5] = { 100,200,300,400,500 };
int *ptr1,*ptr2,*ptr3;

ptr1 =urn;//把一个地址赋给指针
ptr2 =&urn[2]; //把一个地址赋给指针
               //解引用指针,以及获得指针的地址
printf("pointer value, dereferenced pointer,pointer address :\n");

//指针加法
ptr3=ptr1+4;
printf("\nadding an int to a pointer :\n"):
printf(“ptr1+4=%p,*(ptr1+4)=%d\n",ptr1+4,*(ptr1+4));
ptr2++; //递增指针
printf("\nvalues after --ptr2:\n");
printf("ptr2 = %p, *ptr2 =%d, &ptr2 =%p\n",ptr2,*ptr2,&ptr2);
--ptr1; //恢复初始值
++ptr2; //恢复初始值
printf("\nPointers reset to original values :\n);
printf("ptr1 = %p, ptr2 = %p\n",ptr1,ptr2);
//一个指针减去另一个指针
printf("\nsubtracting one pointer from another :\n");
printf("ptr2 = %p , ptr1 = %p , ptr2-ptr1 = %td\n",ptr2,ptr1,ptr20ptr1);
//一个指针减去一个整数
printf("\nsubtracting an int from a pointer:\n");
printf("ptr3 = %p,ptr3 -2 = %p\n",ptr3,ptr3-2);
return 0;
}
int a = 10;
int *b =&a;
printf("%p\n",&a); \\输出变量a的自身地址
printf("%p\n",b); \\输出指针b中指向的自身地址,即a的地址
printf("%p\n",&b); \\输出指针b自身地址
printf("%d\n",a); \\输出指针变量a中的数据10
printf("%d\n",b); \\输出指针变量b中存储的数据,即变量a地址的十进制表示
printf("%d\n",*b); \\输出指针b指向的地址内的数据,即变量a中的数据10
printf("%d\n",b); \\输出指针b中存储的数据(变量a的地址),以指针形式输出

指针的基本操作

赋值:

可以把地址赋给指针。例如,用数组名。带地址运算符(&)的变量名、另一个指针进行赋值。
在该例中,把urn数组的首地址赋给了ptr1,该地址的编号恰好是0 x7fff5bff8do。
变量数组ptr2获得数组urn的第3个元素(urn[2])的地址。
注意,地址应该和指针类型兼容。
也就是说,不能把double类型的地址赋给指向int的指针,至少要避免不明智的类型转换。
C99 / C11已经强制不允许这样做

解引用:

"*"运算符给出指针指向地址上存储的值。因此,* ptr1的初值是100,该值存储在编号为Ox7fff5fbff8do的地址上。

取址:

和所有变量一样,指针变量也有自己的地址和值。
对指针而言,&运算符给出指针本身的地 址。
本例中,ptr1存储在内存编号为0 x7fff5fbff8c8的地址上,该存储单元存储的内容0x7fff5fbff8do,即urn的地址。
因此&ptr1是指向ptr1的指针,而ptr1是指向utn[0]的指针。

指针与整数相加:

可以使用+运算符把指针与整数相加,或整数与指针相加。
无论哪种情况,整数 都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加。
因此ptr1 + 4与urn[4]等价。
如果相加的结果超出了初始指针指向的数组范围,计算结果则是未定义的。
除非正好超过数组末尾第一个位置,C保证该指针有效。

递增指针:

递增指向数组元素的指针可以让该指针移动至数组的下一个元素。
因此,ptrl + +相当于把ptr1的值加上4(我们的系统中int字为4),ptr1指urn[1](见图10.4,该图中使用了简化的地址),现在ptr1的值是0 x7fff5tfbff8d4(数组的下一个元素的地址),* ptr的值为200。
注意,ptr1本身的地址仍是0x7fff5bf8c8,毕竟,变量不会因为值发生变化就移动位置。

指针减去一个整数:

可以使用"-"运算符从一个指针中减去一个整数。
指针必须是第1个运算对象,整数是第2个运算对象。
该整数将乘以指针指向类型的大小(以字节为单位),然后用初始地址减去乘积。
所以ptr3-2&urn [2]等价,因为ptr3指向的是&urn[4]。
如果相减的结果超出了初始指针所向数组的范围,计算结果则是未定义的。除非正好超过数组末尾第一个位置, C保证该指针有效。

递减指针:

当然,除了递增指针还可以递减指针。在本例中,递减ptr2使其指向数组的第2个元素而不是第3个元素。前缀或后缀的递增和递减运算符都可以使用。
注意,在重置ptr1和ptr2前,它们都指向相同的元素urn [1]

指针求差:

可以计算两个指针的差值。
通常,求差的两个指针分别指向同一个数组的不同元素,通过计算求出两元素之间的距离。
差值的单位与数组类型的单位相同。
例如,程序清单10.13的输出中, ptr2-ptr1得2,意思是这两个指针所指向的两个元素相隔两个int,而不是2字节。
只要两个指针都指向相同的数组(或者其中一个指针指向数组后面的第1个地址), C都能保证相a运算有效。
如果指向两个不同数组的指针进行求差运算可能会得出一个值,或者导致运行时错误比较:使用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。
注意,这里的减法有两种,可以用一个指针减去另一个指针得到一个整数,或者用一个指针减去一个整数得到另一个指针。
在递增或递减指针时还要注意一些问题 , 编译器不会检查指针是否仍指向数组元素, C只能保证指向数组任意元素的指针和指向数组后面第1个位置的指针有效。
但是,如果递增或递减一个指针后超出了这个范围,则是未定义的。
另外,可以解引用指向数组任意元素的指针。
但是,即使指针指向数组后面一个位置是有效的,也不能保证可以解引用这样的越界指针。
解引用未初始化的指针:
说到注意事项,一定要牢记一点:千万不要解引用未初始化的指针。
例如,考虑下面的例子:
int .pt; //本初始化的指针
* pt 5//严重的错误
为何不行?2行的意思是把5存储在pt指向的位置,但是pt来被初始化,其值是一个随机值所以不知道5将存健在何处,这可能不会出什么错,也可能会擦写数据或代码,或者导致程序崩演。

切记:

创建一个指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存,因此,在使用指针之前,必须先用已分配的地址初始化它。
例如,可以用一个现有变量的地址初始化该指针(使用带指针形参的函数时,就属于这种情况),或者还可以使用malloc 1)函歌先分配内存。
无论如何,使用指针时一定要注意,不要解引用未初始化的指针!
double . pd: //未初始化的指针
基于这些有效的操作, C程序员创建了指针数组、函数指针、指向指针的指针数组、指向函数的指针数组等,别紧张,接下来我们将根据已学的内容介绍指针的一些基本用法,指针的第1个基本用法是在函数间传递信息。前面学过,如果希望在被调函数中改变主调函数的变量,必须使用指针。指针的第2个基本用法是用在处理数组的函数中。下面我们再来看一个使用函数和数组的编程示例。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值